Extern :
- aggiornata Eigen all'ultima versione disponibile (5.0.1).
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// 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_ACCELERATESUPPORT_MODULE_H
|
||||
#define EIGEN_ACCELERATESUPPORT_MODULE_H
|
||||
|
||||
#include "SparseCore"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
/** \ingroup Support_modules
|
||||
* \defgroup AccelerateSupport_Module AccelerateSupport module
|
||||
*
|
||||
* This module provides an interface to the Apple Accelerate library.
|
||||
* It provides the seven following main factorization classes:
|
||||
* - class AccelerateLLT: a Cholesky (LL^T) factorization.
|
||||
* - class AccelerateLDLT: the default LDL^T factorization.
|
||||
* - class AccelerateLDLTUnpivoted: a Cholesky-like LDL^T factorization with only 1x1 pivots and no pivoting
|
||||
* - class AccelerateLDLTSBK: an LDL^T factorization with Supernode Bunch-Kaufman and static pivoting
|
||||
* - class AccelerateLDLTTPP: an LDL^T factorization with full threshold partial pivoting
|
||||
* - class AccelerateQR: a QR factorization
|
||||
* - class AccelerateCholeskyAtA: a QR factorization without storing Q (equivalent to A^TA = R^T R)
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/AccelerateSupport>
|
||||
* \endcode
|
||||
*
|
||||
* In order to use this module, the Accelerate headers must be accessible from
|
||||
* the include paths, and your binary must be linked to the Accelerate framework.
|
||||
* The Accelerate library is only available on Apple hardware.
|
||||
*
|
||||
* Note that many of the algorithms can be influenced by the UpLo template
|
||||
* argument. All matrices are assumed to be symmetric. For example, the following
|
||||
* creates an LDLT factorization where your matrix is symmetric (implicit) and
|
||||
* uses the lower triangle:
|
||||
*
|
||||
* \code
|
||||
* AccelerateLDLT<SparseMatrix<float>, Lower> ldlt;
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/AccelerateSupport/AccelerateSupport.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_ACCELERATESUPPORT_MODULE_H
|
||||
@@ -0,0 +1,80 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2016 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_THREADPOOL_MODULE_H
|
||||
#define EIGEN_THREADPOOL_MODULE_H
|
||||
|
||||
#include "Core"
|
||||
|
||||
#include "src/Core/util/DisableStupidWarnings.h"
|
||||
|
||||
/** \defgroup ThreadPool_Module ThreadPool Module
|
||||
*
|
||||
* This module provides 2 threadpool implementations
|
||||
* - a simple reference implementation
|
||||
* - a faster non blocking implementation
|
||||
*
|
||||
* \code
|
||||
* #include <Eigen/ThreadPool>
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <time.h>
|
||||
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
// There are non-parenthesized calls to "max" in the <unordered_map> header,
|
||||
// which trigger a check in test/main.h causing compilation to fail.
|
||||
// We work around the check here by removing the check for max in
|
||||
// the case where we have to emulate thread_local.
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
|
||||
#include "src/Core/util/Meta.h"
|
||||
#include "src/Core/util/MaxSizeVector.h"
|
||||
|
||||
#ifndef EIGEN_MUTEX
|
||||
#define EIGEN_MUTEX std::mutex
|
||||
#endif
|
||||
#ifndef EIGEN_MUTEX_LOCK
|
||||
#define EIGEN_MUTEX_LOCK std::unique_lock<std::mutex>
|
||||
#endif
|
||||
#ifndef EIGEN_CONDVAR
|
||||
#define EIGEN_CONDVAR std::condition_variable
|
||||
#endif
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "src/ThreadPool/ThreadLocal.h"
|
||||
#include "src/ThreadPool/ThreadYield.h"
|
||||
#include "src/ThreadPool/ThreadCancel.h"
|
||||
#include "src/ThreadPool/EventCount.h"
|
||||
#include "src/ThreadPool/RunQueue.h"
|
||||
#include "src/ThreadPool/ThreadPoolInterface.h"
|
||||
#include "src/ThreadPool/ThreadEnvironment.h"
|
||||
#include "src/ThreadPool/Barrier.h"
|
||||
#include "src/ThreadPool/NonBlockingThreadPool.h"
|
||||
#include "src/ThreadPool/CoreThreadPoolDevice.h"
|
||||
#include "src/ThreadPool/ForkJoin.h"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#include "src/Core/util/ReenableStupidWarnings.h"
|
||||
|
||||
#endif // EIGEN_CXX11_THREADPOOL_MODULE_H
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef EIGEN_VERSION_H
|
||||
#define EIGEN_VERSION_H
|
||||
|
||||
// The "WORLD" version will forever remain "3" for the "Eigen3" library.
|
||||
#define EIGEN_WORLD_VERSION 3
|
||||
// As of Eigen3 5.0.0, we have moved to Semantic Versioning (semver.org).
|
||||
#define EIGEN_MAJOR_VERSION 5
|
||||
#define EIGEN_MINOR_VERSION 0
|
||||
#define EIGEN_PATCH_VERSION 1
|
||||
#define EIGEN_PRERELEASE_VERSION ""
|
||||
#define EIGEN_BUILD_VERSION ""
|
||||
#define EIGEN_VERSION_STRING "5.0.1"
|
||||
|
||||
#endif // EIGEN_VERSION_H
|
||||
@@ -0,0 +1,423 @@
|
||||
#ifndef EIGEN_ACCELERATESUPPORT_H
|
||||
#define EIGEN_ACCELERATESUPPORT_H
|
||||
|
||||
#include <Accelerate/Accelerate.h>
|
||||
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_>
|
||||
class AccelerateImpl;
|
||||
|
||||
/** \ingroup AccelerateSupport_Module
|
||||
* \typedef AccelerateLLT
|
||||
* \brief A direct Cholesky (LLT) factorization and solver based on Accelerate
|
||||
*
|
||||
* \warning Only single and double precision real scalar types are supported by Accelerate
|
||||
*
|
||||
* \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<>
|
||||
* \tparam UpLo_ additional information about the matrix structure. Default is Lower.
|
||||
*
|
||||
* \sa \ref TutorialSparseSolverConcept, class AccelerateLLT
|
||||
*/
|
||||
template <typename MatrixType, int UpLo = Lower>
|
||||
using AccelerateLLT = AccelerateImpl<MatrixType, UpLo | Symmetric, SparseFactorizationCholesky, true>;
|
||||
|
||||
/** \ingroup AccelerateSupport_Module
|
||||
* \typedef AccelerateLDLT
|
||||
* \brief The default Cholesky (LDLT) factorization and solver based on Accelerate
|
||||
*
|
||||
* \warning Only single and double precision real scalar types are supported by Accelerate
|
||||
*
|
||||
* \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<>
|
||||
* \tparam UpLo_ additional information about the matrix structure. Default is Lower.
|
||||
*
|
||||
* \sa \ref TutorialSparseSolverConcept, class AccelerateLDLT
|
||||
*/
|
||||
template <typename MatrixType, int UpLo = Lower>
|
||||
using AccelerateLDLT = AccelerateImpl<MatrixType, UpLo | Symmetric, SparseFactorizationLDLT, true>;
|
||||
|
||||
/** \ingroup AccelerateSupport_Module
|
||||
* \typedef AccelerateLDLTUnpivoted
|
||||
* \brief A direct Cholesky-like LDL^T factorization and solver based on Accelerate with only 1x1 pivots and no pivoting
|
||||
*
|
||||
* \warning Only single and double precision real scalar types are supported by Accelerate
|
||||
*
|
||||
* \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<>
|
||||
* \tparam UpLo_ additional information about the matrix structure. Default is Lower.
|
||||
*
|
||||
* \sa \ref TutorialSparseSolverConcept, class AccelerateLDLTUnpivoted
|
||||
*/
|
||||
template <typename MatrixType, int UpLo = Lower>
|
||||
using AccelerateLDLTUnpivoted = AccelerateImpl<MatrixType, UpLo | Symmetric, SparseFactorizationLDLTUnpivoted, true>;
|
||||
|
||||
/** \ingroup AccelerateSupport_Module
|
||||
* \typedef AccelerateLDLTSBK
|
||||
* \brief A direct Cholesky (LDLT) factorization and solver based on Accelerate with Supernode Bunch-Kaufman and static
|
||||
* pivoting
|
||||
*
|
||||
* \warning Only single and double precision real scalar types are supported by Accelerate
|
||||
*
|
||||
* \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<>
|
||||
* \tparam UpLo_ additional information about the matrix structure. Default is Lower.
|
||||
*
|
||||
* \sa \ref TutorialSparseSolverConcept, class AccelerateLDLTSBK
|
||||
*/
|
||||
template <typename MatrixType, int UpLo = Lower>
|
||||
using AccelerateLDLTSBK = AccelerateImpl<MatrixType, UpLo | Symmetric, SparseFactorizationLDLTSBK, true>;
|
||||
|
||||
/** \ingroup AccelerateSupport_Module
|
||||
* \typedef AccelerateLDLTTPP
|
||||
* \brief A direct Cholesky (LDLT) factorization and solver based on Accelerate with full threshold partial pivoting
|
||||
*
|
||||
* \warning Only single and double precision real scalar types are supported by Accelerate
|
||||
*
|
||||
* \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<>
|
||||
* \tparam UpLo_ additional information about the matrix structure. Default is Lower.
|
||||
*
|
||||
* \sa \ref TutorialSparseSolverConcept, class AccelerateLDLTTPP
|
||||
*/
|
||||
template <typename MatrixType, int UpLo = Lower>
|
||||
using AccelerateLDLTTPP = AccelerateImpl<MatrixType, UpLo | Symmetric, SparseFactorizationLDLTTPP, true>;
|
||||
|
||||
/** \ingroup AccelerateSupport_Module
|
||||
* \typedef AccelerateQR
|
||||
* \brief A QR factorization and solver based on Accelerate
|
||||
*
|
||||
* \warning Only single and double precision real scalar types are supported by Accelerate
|
||||
*
|
||||
* \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<>
|
||||
*
|
||||
* \sa \ref TutorialSparseSolverConcept, class AccelerateQR
|
||||
*/
|
||||
template <typename MatrixType>
|
||||
using AccelerateQR = AccelerateImpl<MatrixType, 0, SparseFactorizationQR, false>;
|
||||
|
||||
/** \ingroup AccelerateSupport_Module
|
||||
* \typedef AccelerateCholeskyAtA
|
||||
* \brief A QR factorization and solver based on Accelerate without storing Q (equivalent to A^TA = R^T R)
|
||||
*
|
||||
* \warning Only single and double precision real scalar types are supported by Accelerate
|
||||
*
|
||||
* \tparam MatrixType_ the type of the sparse matrix A, it must be a SparseMatrix<>
|
||||
*
|
||||
* \sa \ref TutorialSparseSolverConcept, class AccelerateCholeskyAtA
|
||||
*/
|
||||
template <typename MatrixType>
|
||||
using AccelerateCholeskyAtA = AccelerateImpl<MatrixType, 0, SparseFactorizationCholeskyAtA, false>;
|
||||
|
||||
namespace internal {
|
||||
template <typename T>
|
||||
struct AccelFactorizationDeleter {
|
||||
void operator()(T* sym) {
|
||||
if (sym) {
|
||||
SparseCleanup(*sym);
|
||||
delete sym;
|
||||
sym = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename DenseVecT, typename DenseMatT, typename SparseMatT, typename NumFactT>
|
||||
struct SparseTypesTraitBase {
|
||||
typedef DenseVecT AccelDenseVector;
|
||||
typedef DenseMatT AccelDenseMatrix;
|
||||
typedef SparseMatT AccelSparseMatrix;
|
||||
|
||||
typedef SparseOpaqueSymbolicFactorization SymbolicFactorization;
|
||||
typedef NumFactT NumericFactorization;
|
||||
|
||||
typedef AccelFactorizationDeleter<SymbolicFactorization> SymbolicFactorizationDeleter;
|
||||
typedef AccelFactorizationDeleter<NumericFactorization> NumericFactorizationDeleter;
|
||||
};
|
||||
|
||||
template <typename Scalar>
|
||||
struct SparseTypesTrait {};
|
||||
|
||||
template <>
|
||||
struct SparseTypesTrait<double> : SparseTypesTraitBase<DenseVector_Double, DenseMatrix_Double, SparseMatrix_Double,
|
||||
SparseOpaqueFactorization_Double> {};
|
||||
|
||||
template <>
|
||||
struct SparseTypesTrait<float>
|
||||
: SparseTypesTraitBase<DenseVector_Float, DenseMatrix_Float, SparseMatrix_Float, SparseOpaqueFactorization_Float> {
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_>
|
||||
class AccelerateImpl : public SparseSolverBase<AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_> > {
|
||||
protected:
|
||||
using Base = SparseSolverBase<AccelerateImpl>;
|
||||
using Base::derived;
|
||||
using Base::m_isInitialized;
|
||||
|
||||
public:
|
||||
using Base::_solve_impl;
|
||||
|
||||
typedef MatrixType_ MatrixType;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::StorageIndex StorageIndex;
|
||||
enum { ColsAtCompileTime = Dynamic, MaxColsAtCompileTime = Dynamic };
|
||||
enum { UpLo = UpLo_ };
|
||||
|
||||
using AccelDenseVector = typename internal::SparseTypesTrait<Scalar>::AccelDenseVector;
|
||||
using AccelDenseMatrix = typename internal::SparseTypesTrait<Scalar>::AccelDenseMatrix;
|
||||
using AccelSparseMatrix = typename internal::SparseTypesTrait<Scalar>::AccelSparseMatrix;
|
||||
using SymbolicFactorization = typename internal::SparseTypesTrait<Scalar>::SymbolicFactorization;
|
||||
using NumericFactorization = typename internal::SparseTypesTrait<Scalar>::NumericFactorization;
|
||||
using SymbolicFactorizationDeleter = typename internal::SparseTypesTrait<Scalar>::SymbolicFactorizationDeleter;
|
||||
using NumericFactorizationDeleter = typename internal::SparseTypesTrait<Scalar>::NumericFactorizationDeleter;
|
||||
|
||||
AccelerateImpl() {
|
||||
m_isInitialized = false;
|
||||
|
||||
auto check_flag_set = [](int value, int flag) { return ((value & flag) == flag); };
|
||||
|
||||
if (check_flag_set(UpLo_, Symmetric)) {
|
||||
m_sparseKind = SparseSymmetric;
|
||||
m_triType = (UpLo_ & Lower) ? SparseLowerTriangle : SparseUpperTriangle;
|
||||
} else if (check_flag_set(UpLo_, UnitLower)) {
|
||||
m_sparseKind = SparseUnitTriangular;
|
||||
m_triType = SparseLowerTriangle;
|
||||
} else if (check_flag_set(UpLo_, UnitUpper)) {
|
||||
m_sparseKind = SparseUnitTriangular;
|
||||
m_triType = SparseUpperTriangle;
|
||||
} else if (check_flag_set(UpLo_, StrictlyLower)) {
|
||||
m_sparseKind = SparseTriangular;
|
||||
m_triType = SparseLowerTriangle;
|
||||
} else if (check_flag_set(UpLo_, StrictlyUpper)) {
|
||||
m_sparseKind = SparseTriangular;
|
||||
m_triType = SparseUpperTriangle;
|
||||
} else if (check_flag_set(UpLo_, Lower)) {
|
||||
m_sparseKind = SparseTriangular;
|
||||
m_triType = SparseLowerTriangle;
|
||||
} else if (check_flag_set(UpLo_, Upper)) {
|
||||
m_sparseKind = SparseTriangular;
|
||||
m_triType = SparseUpperTriangle;
|
||||
} else {
|
||||
m_sparseKind = SparseOrdinary;
|
||||
m_triType = (UpLo_ & Lower) ? SparseLowerTriangle : SparseUpperTriangle;
|
||||
}
|
||||
|
||||
m_order = SparseOrderDefault;
|
||||
}
|
||||
|
||||
explicit AccelerateImpl(const MatrixType& matrix) : AccelerateImpl() { compute(matrix); }
|
||||
|
||||
~AccelerateImpl() {}
|
||||
|
||||
inline Index cols() const { return m_nCols; }
|
||||
inline Index rows() const { return m_nRows; }
|
||||
|
||||
ComputationInfo info() const {
|
||||
eigen_assert(m_isInitialized && "Decomposition is not initialized.");
|
||||
return m_info;
|
||||
}
|
||||
|
||||
void analyzePattern(const MatrixType& matrix);
|
||||
|
||||
void factorize(const MatrixType& matrix);
|
||||
|
||||
void compute(const MatrixType& matrix);
|
||||
|
||||
template <typename Rhs, typename Dest>
|
||||
void _solve_impl(const MatrixBase<Rhs>& b, MatrixBase<Dest>& dest) const;
|
||||
|
||||
/** Sets the ordering algorithm to use. */
|
||||
void setOrder(SparseOrder_t order) { m_order = order; }
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void buildAccelSparseMatrix(const SparseMatrix<T>& a, AccelSparseMatrix& A, std::vector<long>& columnStarts) {
|
||||
const Index nColumnsStarts = a.cols() + 1;
|
||||
|
||||
columnStarts.resize(nColumnsStarts);
|
||||
|
||||
for (Index i = 0; i < nColumnsStarts; i++) columnStarts[i] = a.outerIndexPtr()[i];
|
||||
|
||||
SparseAttributes_t attributes{};
|
||||
attributes.transpose = false;
|
||||
attributes.triangle = m_triType;
|
||||
attributes.kind = m_sparseKind;
|
||||
|
||||
SparseMatrixStructure structure{};
|
||||
structure.attributes = attributes;
|
||||
structure.rowCount = static_cast<int>(a.rows());
|
||||
structure.columnCount = static_cast<int>(a.cols());
|
||||
structure.blockSize = 1;
|
||||
structure.columnStarts = columnStarts.data();
|
||||
structure.rowIndices = const_cast<int*>(a.innerIndexPtr());
|
||||
|
||||
A.structure = structure;
|
||||
A.data = const_cast<T*>(a.valuePtr());
|
||||
}
|
||||
|
||||
void doAnalysis(AccelSparseMatrix& A) {
|
||||
m_numericFactorization.reset(nullptr);
|
||||
|
||||
SparseSymbolicFactorOptions opts{};
|
||||
opts.control = SparseDefaultControl;
|
||||
opts.orderMethod = m_order;
|
||||
opts.order = nullptr;
|
||||
opts.ignoreRowsAndColumns = nullptr;
|
||||
opts.malloc = malloc;
|
||||
opts.free = free;
|
||||
opts.reportError = nullptr;
|
||||
|
||||
m_symbolicFactorization.reset(new SymbolicFactorization(SparseFactor(Solver_, A.structure, opts)));
|
||||
|
||||
SparseStatus_t status = m_symbolicFactorization->status;
|
||||
|
||||
updateInfoStatus(status);
|
||||
|
||||
if (status != SparseStatusOK) m_symbolicFactorization.reset(nullptr);
|
||||
}
|
||||
|
||||
void doFactorization(AccelSparseMatrix& A) {
|
||||
SparseStatus_t status = SparseStatusReleased;
|
||||
|
||||
if (m_symbolicFactorization) {
|
||||
m_numericFactorization.reset(new NumericFactorization(SparseFactor(*m_symbolicFactorization, A)));
|
||||
|
||||
status = m_numericFactorization->status;
|
||||
|
||||
if (status != SparseStatusOK) m_numericFactorization.reset(nullptr);
|
||||
}
|
||||
|
||||
updateInfoStatus(status);
|
||||
}
|
||||
|
||||
protected:
|
||||
void updateInfoStatus(SparseStatus_t status) const {
|
||||
switch (status) {
|
||||
case SparseStatusOK:
|
||||
m_info = Success;
|
||||
break;
|
||||
case SparseFactorizationFailed:
|
||||
case SparseMatrixIsSingular:
|
||||
m_info = NumericalIssue;
|
||||
break;
|
||||
case SparseInternalError:
|
||||
case SparseParameterError:
|
||||
case SparseStatusReleased:
|
||||
default:
|
||||
m_info = InvalidInput;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutable ComputationInfo m_info;
|
||||
Index m_nRows, m_nCols;
|
||||
std::unique_ptr<SymbolicFactorization, SymbolicFactorizationDeleter> m_symbolicFactorization;
|
||||
std::unique_ptr<NumericFactorization, NumericFactorizationDeleter> m_numericFactorization;
|
||||
SparseKind_t m_sparseKind;
|
||||
SparseTriangle_t m_triType;
|
||||
SparseOrder_t m_order;
|
||||
};
|
||||
|
||||
/** Computes the symbolic and numeric decomposition of matrix \a a */
|
||||
template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_>
|
||||
void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::compute(const MatrixType& a) {
|
||||
if (EnforceSquare_) eigen_assert(a.rows() == a.cols());
|
||||
|
||||
m_nRows = a.rows();
|
||||
m_nCols = a.cols();
|
||||
|
||||
AccelSparseMatrix A{};
|
||||
std::vector<long> columnStarts;
|
||||
|
||||
buildAccelSparseMatrix(a, A, columnStarts);
|
||||
|
||||
doAnalysis(A);
|
||||
|
||||
if (m_symbolicFactorization) doFactorization(A);
|
||||
|
||||
m_isInitialized = true;
|
||||
}
|
||||
|
||||
/** Performs a symbolic decomposition on the sparsity pattern of matrix \a a.
|
||||
*
|
||||
* This function is particularly useful when solving for several problems having the same structure.
|
||||
*
|
||||
* \sa factorize()
|
||||
*/
|
||||
template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_>
|
||||
void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::analyzePattern(const MatrixType& a) {
|
||||
if (EnforceSquare_) eigen_assert(a.rows() == a.cols());
|
||||
|
||||
m_nRows = a.rows();
|
||||
m_nCols = a.cols();
|
||||
|
||||
AccelSparseMatrix A{};
|
||||
std::vector<long> columnStarts;
|
||||
|
||||
buildAccelSparseMatrix(a, A, columnStarts);
|
||||
|
||||
doAnalysis(A);
|
||||
|
||||
m_isInitialized = true;
|
||||
}
|
||||
|
||||
/** Performs a numeric decomposition of matrix \a a.
|
||||
*
|
||||
* The given matrix must have the same sparsity pattern as the matrix on which the symbolic decomposition has been
|
||||
* performed.
|
||||
*
|
||||
* \sa analyzePattern()
|
||||
*/
|
||||
template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_>
|
||||
void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::factorize(const MatrixType& a) {
|
||||
eigen_assert(m_symbolicFactorization && "You must first call analyzePattern()");
|
||||
eigen_assert(m_nRows == a.rows() && m_nCols == a.cols());
|
||||
|
||||
if (EnforceSquare_) eigen_assert(a.rows() == a.cols());
|
||||
|
||||
AccelSparseMatrix A{};
|
||||
std::vector<long> columnStarts;
|
||||
|
||||
buildAccelSparseMatrix(a, A, columnStarts);
|
||||
|
||||
doFactorization(A);
|
||||
}
|
||||
|
||||
template <typename MatrixType_, int UpLo_, SparseFactorization_t Solver_, bool EnforceSquare_>
|
||||
template <typename Rhs, typename Dest>
|
||||
void AccelerateImpl<MatrixType_, UpLo_, Solver_, EnforceSquare_>::_solve_impl(const MatrixBase<Rhs>& b,
|
||||
MatrixBase<Dest>& x) const {
|
||||
if (!m_numericFactorization) {
|
||||
m_info = InvalidInput;
|
||||
return;
|
||||
}
|
||||
|
||||
eigen_assert(m_nRows == b.rows());
|
||||
eigen_assert(((b.cols() == 1) || b.outerStride() == b.rows()));
|
||||
|
||||
SparseStatus_t status = SparseStatusOK;
|
||||
|
||||
Scalar* b_ptr = const_cast<Scalar*>(b.derived().data());
|
||||
Scalar* x_ptr = const_cast<Scalar*>(x.derived().data());
|
||||
|
||||
AccelDenseMatrix xmat{};
|
||||
xmat.attributes = SparseAttributes_t();
|
||||
xmat.columnCount = static_cast<int>(x.cols());
|
||||
xmat.rowCount = static_cast<int>(x.rows());
|
||||
xmat.columnStride = xmat.rowCount;
|
||||
xmat.data = x_ptr;
|
||||
|
||||
AccelDenseMatrix bmat{};
|
||||
bmat.attributes = SparseAttributes_t();
|
||||
bmat.columnCount = static_cast<int>(b.cols());
|
||||
bmat.rowCount = static_cast<int>(b.rows());
|
||||
bmat.columnStride = bmat.rowCount;
|
||||
bmat.data = b_ptr;
|
||||
|
||||
SparseSolve(*m_numericFactorization, bmat, xmat);
|
||||
|
||||
updateInfoStatus(status);
|
||||
}
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_ACCELERATESUPPORT_H
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_ACCELERATESUPPORT_MODULE_H
|
||||
#error "Please include Eigen/AccelerateSupport instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_CHOLESKY_MODULE_H
|
||||
#error "Please include Eigen/Cholesky instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_CHOLMODSUPPORT_MODULE_H
|
||||
#error "Please include Eigen/CholmodSupport instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,153 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2023 Charlie Schlosser <cs.schlosser@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_DEVICEWRAPPER_H
|
||||
#define EIGEN_DEVICEWRAPPER_H
|
||||
|
||||
namespace Eigen {
|
||||
template <typename Derived, typename Device>
|
||||
struct DeviceWrapper {
|
||||
using Base = EigenBase<internal::remove_all_t<Derived>>;
|
||||
using Scalar = typename Derived::Scalar;
|
||||
|
||||
EIGEN_DEVICE_FUNC DeviceWrapper(Base& xpr, Device& device) : m_xpr(xpr.derived()), m_device(device) {}
|
||||
EIGEN_DEVICE_FUNC DeviceWrapper(const Base& xpr, Device& device) : m_xpr(xpr.derived()), m_device(device) {}
|
||||
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator=(const EigenBase<OtherDerived>& other) {
|
||||
using AssignOp = internal::assign_op<Scalar, typename OtherDerived::Scalar>;
|
||||
internal::call_assignment(*this, other.derived(), AssignOp());
|
||||
return m_xpr;
|
||||
}
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator+=(const EigenBase<OtherDerived>& other) {
|
||||
using AddAssignOp = internal::add_assign_op<Scalar, typename OtherDerived::Scalar>;
|
||||
internal::call_assignment(*this, other.derived(), AddAssignOp());
|
||||
return m_xpr;
|
||||
}
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& operator-=(const EigenBase<OtherDerived>& other) {
|
||||
using SubAssignOp = internal::sub_assign_op<Scalar, typename OtherDerived::Scalar>;
|
||||
internal::call_assignment(*this, other.derived(), SubAssignOp());
|
||||
return m_xpr;
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Derived& derived() { return m_xpr; }
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Device& device() { return m_device; }
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE NoAlias<DeviceWrapper, EigenBase> noalias() {
|
||||
return NoAlias<DeviceWrapper, EigenBase>(*this);
|
||||
}
|
||||
|
||||
Derived& m_xpr;
|
||||
Device& m_device;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
// this is where we differentiate between lazy assignment and specialized kernels (e.g. matrix products)
|
||||
template <typename DstXprType, typename SrcXprType, typename Functor, typename Device,
|
||||
typename Kind = typename AssignmentKind<typename evaluator_traits<DstXprType>::Shape,
|
||||
typename evaluator_traits<SrcXprType>::Shape>::Kind,
|
||||
typename EnableIf = void>
|
||||
struct AssignmentWithDevice;
|
||||
|
||||
// unless otherwise specified, use the default product implementation
|
||||
template <typename DstXprType, typename Lhs, typename Rhs, int Options, typename Functor, typename Device,
|
||||
typename Weak>
|
||||
struct AssignmentWithDevice<DstXprType, Product<Lhs, Rhs, Options>, Functor, Device, Dense2Dense, Weak> {
|
||||
using SrcXprType = Product<Lhs, Rhs, Options>;
|
||||
using Base = Assignment<DstXprType, SrcXprType, Functor>;
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(DstXprType& dst, const SrcXprType& src, const Functor& func,
|
||||
Device&) {
|
||||
Base::run(dst, src, func);
|
||||
}
|
||||
};
|
||||
|
||||
// specialization for coeffcient-wise assignment
|
||||
template <typename DstXprType, typename SrcXprType, typename Functor, typename Device, typename Weak>
|
||||
struct AssignmentWithDevice<DstXprType, SrcXprType, Functor, Device, Dense2Dense, Weak> {
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(DstXprType& dst, const SrcXprType& src, const Functor& func,
|
||||
Device& device) {
|
||||
#ifndef EIGEN_NO_DEBUG
|
||||
internal::check_for_aliasing(dst, src);
|
||||
#endif
|
||||
|
||||
call_dense_assignment_loop(dst, src, func, device);
|
||||
}
|
||||
};
|
||||
|
||||
// this allows us to use the default evaluation scheme if it is not specialized for the device
|
||||
template <typename Kernel, typename Device, int Traversal = Kernel::AssignmentTraits::Traversal,
|
||||
int Unrolling = Kernel::AssignmentTraits::Unrolling>
|
||||
struct dense_assignment_loop_with_device {
|
||||
using Base = dense_assignment_loop<Kernel, Traversal, Unrolling>;
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr void run(Kernel& kernel, Device&) { Base::run(kernel); }
|
||||
};
|
||||
|
||||
// entry point for a generic expression with device
|
||||
template <typename Dst, typename Src, typename Func, typename Device>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr void call_assignment_no_alias(DeviceWrapper<Dst, Device> dst,
|
||||
const Src& src, const Func& func) {
|
||||
enum {
|
||||
NeedToTranspose = ((int(Dst::RowsAtCompileTime) == 1 && int(Src::ColsAtCompileTime) == 1) ||
|
||||
(int(Dst::ColsAtCompileTime) == 1 && int(Src::RowsAtCompileTime) == 1)) &&
|
||||
int(Dst::SizeAtCompileTime) != 1
|
||||
};
|
||||
|
||||
using ActualDstTypeCleaned = std::conditional_t<NeedToTranspose, Transpose<Dst>, Dst>;
|
||||
using ActualDstType = std::conditional_t<NeedToTranspose, Transpose<Dst>, Dst&>;
|
||||
ActualDstType actualDst(dst.derived());
|
||||
|
||||
// TODO check whether this is the right place to perform these checks:
|
||||
EIGEN_STATIC_ASSERT_LVALUE(Dst)
|
||||
EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(ActualDstTypeCleaned, Src)
|
||||
EIGEN_CHECK_BINARY_COMPATIBILIY(Func, typename ActualDstTypeCleaned::Scalar, typename Src::Scalar);
|
||||
|
||||
// this provides a mechanism for specializing simple assignments, matrix products, etc
|
||||
AssignmentWithDevice<ActualDstTypeCleaned, Src, Func, Device>::run(actualDst, src, func, dst.device());
|
||||
}
|
||||
|
||||
// copy and pasted from AssignEvaluator except forward device to kernel
|
||||
template <typename DstXprType, typename SrcXprType, typename Functor, typename Device>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr void call_dense_assignment_loop(DstXprType& dst, const SrcXprType& src,
|
||||
const Functor& func, Device& device) {
|
||||
using DstEvaluatorType = evaluator<DstXprType>;
|
||||
using SrcEvaluatorType = evaluator<SrcXprType>;
|
||||
|
||||
SrcEvaluatorType srcEvaluator(src);
|
||||
|
||||
// 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.
|
||||
resize_if_allowed(dst, src, func);
|
||||
|
||||
DstEvaluatorType dstEvaluator(dst);
|
||||
|
||||
using Kernel = generic_dense_assignment_kernel<DstEvaluatorType, SrcEvaluatorType, Functor>;
|
||||
|
||||
Kernel kernel(dstEvaluator, srcEvaluator, func, dst.const_cast_derived());
|
||||
|
||||
dense_assignment_loop_with_device<Kernel, Device>::run(kernel, device);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename Derived>
|
||||
template <typename Device>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DeviceWrapper<Derived, Device> EigenBase<Derived>::device(Device& device) {
|
||||
return DeviceWrapper<Derived, Device>(derived(), device);
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
template <typename Device>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DeviceWrapper<const Derived, Device> EigenBase<Derived>::device(
|
||||
Device& device) const {
|
||||
return DeviceWrapper<const Derived, Device>(derived(), device);
|
||||
}
|
||||
} // namespace Eigen
|
||||
#endif
|
||||
@@ -0,0 +1,138 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2024 Charles Schlosser <cs.schlosser@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_FILL_H
|
||||
#define EIGEN_FILL_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename Xpr>
|
||||
struct eigen_fill_helper : std::false_type {};
|
||||
|
||||
template <typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
|
||||
struct eigen_fill_helper<Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>> : std::true_type {};
|
||||
|
||||
template <typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
|
||||
struct eigen_fill_helper<Array<Scalar, Rows, Cols, Options, MaxRows, MaxCols>> : std::true_type {};
|
||||
|
||||
template <typename Xpr, int BlockRows, int BlockCols>
|
||||
struct eigen_fill_helper<Block<Xpr, BlockRows, BlockCols, /*InnerPanel*/ true>> : eigen_fill_helper<Xpr> {};
|
||||
|
||||
template <typename Xpr, int BlockRows, int BlockCols>
|
||||
struct eigen_fill_helper<Block<Xpr, BlockRows, BlockCols, /*InnerPanel*/ false>>
|
||||
: std::integral_constant<bool, eigen_fill_helper<Xpr>::value &&
|
||||
(Xpr::IsRowMajor ? (BlockRows == 1) : (BlockCols == 1))> {};
|
||||
|
||||
template <typename Xpr, int Options>
|
||||
struct eigen_fill_helper<Map<Xpr, Options, Stride<0, 0>>> : eigen_fill_helper<Xpr> {};
|
||||
|
||||
template <typename Xpr, int Options, int OuterStride_>
|
||||
struct eigen_fill_helper<Map<Xpr, Options, Stride<OuterStride_, 0>>>
|
||||
: std::integral_constant<bool, eigen_fill_helper<Xpr>::value &&
|
||||
enum_eq_not_dynamic(OuterStride_, Xpr::InnerSizeAtCompileTime)> {};
|
||||
|
||||
template <typename Xpr, int Options, int OuterStride_>
|
||||
struct eigen_fill_helper<Map<Xpr, Options, Stride<OuterStride_, 1>>>
|
||||
: eigen_fill_helper<Map<Xpr, Options, Stride<OuterStride_, 0>>> {};
|
||||
|
||||
template <typename Xpr, int Options, int InnerStride_>
|
||||
struct eigen_fill_helper<Map<Xpr, Options, InnerStride<InnerStride_>>>
|
||||
: eigen_fill_helper<Map<Xpr, Options, Stride<0, InnerStride_>>> {};
|
||||
|
||||
template <typename Xpr, int Options, int OuterStride_>
|
||||
struct eigen_fill_helper<Map<Xpr, Options, OuterStride<OuterStride_>>>
|
||||
: eigen_fill_helper<Map<Xpr, Options, Stride<OuterStride_, 0>>> {};
|
||||
|
||||
template <typename Xpr>
|
||||
struct eigen_fill_impl<Xpr, /*use_fill*/ false> {
|
||||
using Scalar = typename Xpr::Scalar;
|
||||
using Func = scalar_constant_op<Scalar>;
|
||||
using PlainObject = typename Xpr::PlainObject;
|
||||
using Constant = typename PlainObject::ConstantReturnType;
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr void run(Xpr& dst, const Scalar& val) {
|
||||
const Constant src(dst.rows(), dst.cols(), val);
|
||||
run(dst, src);
|
||||
}
|
||||
template <typename SrcXpr>
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr void run(Xpr& dst, const SrcXpr& src) {
|
||||
call_dense_assignment_loop(dst, src, assign_op<Scalar, Scalar>());
|
||||
}
|
||||
};
|
||||
|
||||
#if EIGEN_COMP_MSVC || defined(EIGEN_GPU_COMPILE_PHASE)
|
||||
template <typename Xpr>
|
||||
struct eigen_fill_impl<Xpr, /*use_fill*/ true> : eigen_fill_impl<Xpr, /*use_fill*/ false> {};
|
||||
#else
|
||||
template <typename Xpr>
|
||||
struct eigen_fill_impl<Xpr, /*use_fill*/ true> {
|
||||
using Scalar = typename Xpr::Scalar;
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Xpr& dst, const Scalar& val) {
|
||||
const Scalar val_copy = val;
|
||||
using std::fill_n;
|
||||
fill_n(dst.data(), dst.size(), val_copy);
|
||||
}
|
||||
template <typename SrcXpr>
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Xpr& dst, const SrcXpr& src) {
|
||||
resize_if_allowed(dst, src, assign_op<Scalar, Scalar>());
|
||||
const Scalar& val = src.functor()();
|
||||
run(dst, val);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename Xpr>
|
||||
struct eigen_memset_helper {
|
||||
static constexpr bool value =
|
||||
std::is_trivially_copyable<typename Xpr::Scalar>::value && eigen_fill_helper<Xpr>::value;
|
||||
};
|
||||
|
||||
template <typename Xpr>
|
||||
struct eigen_zero_impl<Xpr, /*use_memset*/ false> {
|
||||
using Scalar = typename Xpr::Scalar;
|
||||
using PlainObject = typename Xpr::PlainObject;
|
||||
using Zero = typename PlainObject::ZeroReturnType;
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr void run(Xpr& dst) {
|
||||
const Zero src(dst.rows(), dst.cols());
|
||||
run(dst, src);
|
||||
}
|
||||
template <typename SrcXpr>
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr void run(Xpr& dst, const SrcXpr& src) {
|
||||
call_dense_assignment_loop(dst, src, assign_op<Scalar, Scalar>());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Xpr>
|
||||
struct eigen_zero_impl<Xpr, /*use_memset*/ true> {
|
||||
using Scalar = typename Xpr::Scalar;
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Xpr& dst) {
|
||||
const std::ptrdiff_t num_bytes = dst.size() * static_cast<std::ptrdiff_t>(sizeof(Scalar));
|
||||
if (num_bytes <= 0) return;
|
||||
void* dst_ptr = static_cast<void*>(dst.data());
|
||||
#ifndef EIGEN_NO_DEBUG
|
||||
eigen_assert((dst_ptr != nullptr) && "null pointer dereference error!");
|
||||
#endif
|
||||
EIGEN_USING_STD(memset);
|
||||
memset(dst_ptr, 0, static_cast<std::size_t>(num_bytes));
|
||||
}
|
||||
template <typename SrcXpr>
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Xpr& dst, const SrcXpr& src) {
|
||||
resize_if_allowed(dst, src, assign_op<Scalar, Scalar>());
|
||||
run(dst);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_FILL_H
|
||||
@@ -0,0 +1,464 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2025 Charlie Schlosser <cs.schlosser@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_FIND_COEFF_H
|
||||
#define EIGEN_FIND_COEFF_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename Scalar, int NaNPropagation, bool IsInteger = NumTraits<Scalar>::IsInteger>
|
||||
struct max_coeff_functor {
|
||||
EIGEN_DEVICE_FUNC inline bool compareCoeff(const Scalar& incumbent, const Scalar& candidate) const {
|
||||
return candidate > incumbent;
|
||||
}
|
||||
template <typename Packet>
|
||||
EIGEN_DEVICE_FUNC inline Packet comparePacket(const Packet& incumbent, const Packet& candidate) const {
|
||||
return pcmp_lt(incumbent, candidate);
|
||||
}
|
||||
template <typename Packet>
|
||||
EIGEN_DEVICE_FUNC inline Scalar predux(const Packet& a) const {
|
||||
return predux_max(a);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Scalar>
|
||||
struct max_coeff_functor<Scalar, PropagateNaN, false> {
|
||||
EIGEN_DEVICE_FUNC inline Scalar compareCoeff(const Scalar& incumbent, const Scalar& candidate) {
|
||||
return (candidate > incumbent) || ((candidate != candidate) && (incumbent == incumbent));
|
||||
}
|
||||
template <typename Packet>
|
||||
EIGEN_DEVICE_FUNC inline Packet comparePacket(const Packet& incumbent, const Packet& candidate) {
|
||||
return pandnot(pcmp_lt_or_nan(incumbent, candidate), pisnan(incumbent));
|
||||
}
|
||||
template <typename Packet>
|
||||
EIGEN_DEVICE_FUNC inline Scalar predux(const Packet& a) const {
|
||||
return predux_max<PropagateNaN>(a);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Scalar>
|
||||
struct max_coeff_functor<Scalar, PropagateNumbers, false> {
|
||||
EIGEN_DEVICE_FUNC inline bool compareCoeff(const Scalar& incumbent, const Scalar& candidate) const {
|
||||
return (candidate > incumbent) || ((candidate == candidate) && (incumbent != incumbent));
|
||||
}
|
||||
template <typename Packet>
|
||||
EIGEN_DEVICE_FUNC inline Packet comparePacket(const Packet& incumbent, const Packet& candidate) const {
|
||||
return pandnot(pcmp_lt_or_nan(incumbent, candidate), pisnan(candidate));
|
||||
}
|
||||
template <typename Packet>
|
||||
EIGEN_DEVICE_FUNC inline Scalar predux(const Packet& a) const {
|
||||
return predux_max<PropagateNumbers>(a);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Scalar, int NaNPropagation, bool IsInteger = NumTraits<Scalar>::IsInteger>
|
||||
struct min_coeff_functor {
|
||||
EIGEN_DEVICE_FUNC inline bool compareCoeff(const Scalar& incumbent, const Scalar& candidate) const {
|
||||
return candidate < incumbent;
|
||||
}
|
||||
template <typename Packet>
|
||||
EIGEN_DEVICE_FUNC inline Packet comparePacket(const Packet& incumbent, const Packet& candidate) const {
|
||||
return pcmp_lt(candidate, incumbent);
|
||||
}
|
||||
template <typename Packet>
|
||||
EIGEN_DEVICE_FUNC inline Scalar predux(const Packet& a) const {
|
||||
return predux_min(a);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Scalar>
|
||||
struct min_coeff_functor<Scalar, PropagateNaN, false> {
|
||||
EIGEN_DEVICE_FUNC inline Scalar compareCoeff(const Scalar& incumbent, const Scalar& candidate) {
|
||||
return (candidate < incumbent) || ((candidate != candidate) && (incumbent == incumbent));
|
||||
}
|
||||
template <typename Packet>
|
||||
EIGEN_DEVICE_FUNC inline Packet comparePacket(const Packet& incumbent, const Packet& candidate) {
|
||||
return pandnot(pcmp_lt_or_nan(candidate, incumbent), pisnan(incumbent));
|
||||
}
|
||||
template <typename Packet>
|
||||
EIGEN_DEVICE_FUNC inline Scalar predux(const Packet& a) const {
|
||||
return predux_min<PropagateNaN>(a);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Scalar>
|
||||
struct min_coeff_functor<Scalar, PropagateNumbers, false> {
|
||||
EIGEN_DEVICE_FUNC inline bool compareCoeff(const Scalar& incumbent, const Scalar& candidate) const {
|
||||
return (candidate < incumbent) || ((candidate == candidate) && (incumbent != incumbent));
|
||||
}
|
||||
template <typename Packet>
|
||||
EIGEN_DEVICE_FUNC inline Packet comparePacket(const Packet& incumbent, const Packet& candidate) const {
|
||||
return pandnot(pcmp_lt_or_nan(candidate, incumbent), pisnan(candidate));
|
||||
}
|
||||
template <typename Packet>
|
||||
EIGEN_DEVICE_FUNC inline Scalar predux(const Packet& a) const {
|
||||
return predux_min<PropagateNumbers>(a);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Scalar>
|
||||
struct min_max_traits {
|
||||
static constexpr bool PacketAccess = packet_traits<Scalar>::Vectorizable;
|
||||
};
|
||||
template <typename Scalar, int NaNPropagation>
|
||||
struct functor_traits<max_coeff_functor<Scalar, NaNPropagation>> : min_max_traits<Scalar> {};
|
||||
template <typename Scalar, int NaNPropagation>
|
||||
struct functor_traits<min_coeff_functor<Scalar, NaNPropagation>> : min_max_traits<Scalar> {};
|
||||
|
||||
template <typename Evaluator, typename Func, bool Linear, bool Vectorize>
|
||||
struct find_coeff_loop;
|
||||
template <typename Evaluator, typename Func>
|
||||
struct find_coeff_loop<Evaluator, Func, /*Linear*/ false, /*Vectorize*/ false> {
|
||||
using Scalar = typename Evaluator::Scalar;
|
||||
static EIGEN_DEVICE_FUNC inline void run(const Evaluator& eval, Func& func, Scalar& res, Index& outer, Index& inner) {
|
||||
Index outerSize = eval.outerSize();
|
||||
Index innerSize = eval.innerSize();
|
||||
|
||||
/* initialization performed in calling function */
|
||||
/* result = eval.coeff(0, 0); */
|
||||
/* outer = 0; */
|
||||
/* inner = 0; */
|
||||
|
||||
for (Index j = 0; j < outerSize; j++) {
|
||||
for (Index i = 0; i < innerSize; i++) {
|
||||
Scalar xprCoeff = eval.coeffByOuterInner(j, i);
|
||||
bool newRes = func.compareCoeff(res, xprCoeff);
|
||||
if (newRes) {
|
||||
outer = j;
|
||||
inner = i;
|
||||
res = xprCoeff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
template <typename Evaluator, typename Func>
|
||||
struct find_coeff_loop<Evaluator, Func, /*Linear*/ true, /*Vectorize*/ false> {
|
||||
using Scalar = typename Evaluator::Scalar;
|
||||
static EIGEN_DEVICE_FUNC inline void run(const Evaluator& eval, Func& func, Scalar& res, Index& index) {
|
||||
Index size = eval.size();
|
||||
|
||||
/* initialization performed in calling function */
|
||||
/* result = eval.coeff(0); */
|
||||
/* index = 0; */
|
||||
|
||||
for (Index k = 0; k < size; k++) {
|
||||
Scalar xprCoeff = eval.coeff(k);
|
||||
bool newRes = func.compareCoeff(res, xprCoeff);
|
||||
if (newRes) {
|
||||
index = k;
|
||||
res = xprCoeff;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
template <typename Evaluator, typename Func>
|
||||
struct find_coeff_loop<Evaluator, Func, /*Linear*/ false, /*Vectorize*/ true> {
|
||||
using ScalarImpl = find_coeff_loop<Evaluator, Func, false, false>;
|
||||
using Scalar = typename Evaluator::Scalar;
|
||||
using Packet = typename Evaluator::Packet;
|
||||
static constexpr int PacketSize = unpacket_traits<Packet>::size;
|
||||
static EIGEN_DEVICE_FUNC inline void run(const Evaluator& eval, Func& func, Scalar& result, Index& outer,
|
||||
Index& inner) {
|
||||
Index outerSize = eval.outerSize();
|
||||
Index innerSize = eval.innerSize();
|
||||
Index packetEnd = numext::round_down(innerSize, PacketSize);
|
||||
|
||||
/* initialization performed in calling function */
|
||||
/* result = eval.coeff(0, 0); */
|
||||
/* outer = 0; */
|
||||
/* inner = 0; */
|
||||
|
||||
bool checkPacket = false;
|
||||
|
||||
for (Index j = 0; j < outerSize; j++) {
|
||||
Packet resultPacket = pset1<Packet>(result);
|
||||
for (Index i = 0; i < packetEnd; i += PacketSize) {
|
||||
Packet xprPacket = eval.template packetByOuterInner<Unaligned, Packet>(j, i);
|
||||
if (predux_any(func.comparePacket(resultPacket, xprPacket))) {
|
||||
outer = j;
|
||||
inner = i;
|
||||
result = func.predux(xprPacket);
|
||||
resultPacket = pset1<Packet>(result);
|
||||
checkPacket = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (Index i = packetEnd; i < innerSize; i++) {
|
||||
Scalar xprCoeff = eval.coeffByOuterInner(j, i);
|
||||
if (func.compareCoeff(result, xprCoeff)) {
|
||||
outer = j;
|
||||
inner = i;
|
||||
result = xprCoeff;
|
||||
checkPacket = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (checkPacket) {
|
||||
result = eval.coeffByOuterInner(outer, inner);
|
||||
Index i_end = inner + PacketSize;
|
||||
for (Index i = inner; i < i_end; i++) {
|
||||
Scalar xprCoeff = eval.coeffByOuterInner(outer, i);
|
||||
if (func.compareCoeff(result, xprCoeff)) {
|
||||
inner = i;
|
||||
result = xprCoeff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
template <typename Evaluator, typename Func>
|
||||
struct find_coeff_loop<Evaluator, Func, /*Linear*/ true, /*Vectorize*/ true> {
|
||||
using ScalarImpl = find_coeff_loop<Evaluator, Func, true, false>;
|
||||
using Scalar = typename Evaluator::Scalar;
|
||||
using Packet = typename Evaluator::Packet;
|
||||
static constexpr int PacketSize = unpacket_traits<Packet>::size;
|
||||
static constexpr int Alignment = Evaluator::Alignment;
|
||||
|
||||
static EIGEN_DEVICE_FUNC inline void run(const Evaluator& eval, Func& func, Scalar& result, Index& index) {
|
||||
Index size = eval.size();
|
||||
Index packetEnd = numext::round_down(size, PacketSize);
|
||||
|
||||
/* initialization performed in calling function */
|
||||
/* result = eval.coeff(0); */
|
||||
/* index = 0; */
|
||||
|
||||
Packet resultPacket = pset1<Packet>(result);
|
||||
bool checkPacket = false;
|
||||
|
||||
for (Index k = 0; k < packetEnd; k += PacketSize) {
|
||||
Packet xprPacket = eval.template packet<Alignment, Packet>(k);
|
||||
if (predux_any(func.comparePacket(resultPacket, xprPacket))) {
|
||||
index = k;
|
||||
result = func.predux(xprPacket);
|
||||
resultPacket = pset1<Packet>(result);
|
||||
checkPacket = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (Index k = packetEnd; k < size; k++) {
|
||||
Scalar xprCoeff = eval.coeff(k);
|
||||
if (func.compareCoeff(result, xprCoeff)) {
|
||||
index = k;
|
||||
result = xprCoeff;
|
||||
checkPacket = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkPacket) {
|
||||
result = eval.coeff(index);
|
||||
Index k_end = index + PacketSize;
|
||||
for (Index k = index; k < k_end; k++) {
|
||||
Scalar xprCoeff = eval.coeff(k);
|
||||
if (func.compareCoeff(result, xprCoeff)) {
|
||||
index = k;
|
||||
result = xprCoeff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Derived>
|
||||
struct find_coeff_evaluator : public evaluator<Derived> {
|
||||
using Base = evaluator<Derived>;
|
||||
using Scalar = typename Derived::Scalar;
|
||||
using Packet = typename packet_traits<Scalar>::type;
|
||||
static constexpr int Flags = Base::Flags;
|
||||
static constexpr bool IsRowMajor = bool(Flags & RowMajorBit);
|
||||
EIGEN_DEVICE_FUNC inline find_coeff_evaluator(const Derived& xpr) : Base(xpr), m_xpr(xpr) {}
|
||||
|
||||
EIGEN_DEVICE_FUNC inline Scalar coeffByOuterInner(Index outer, Index inner) const {
|
||||
Index row = IsRowMajor ? outer : inner;
|
||||
Index col = IsRowMajor ? inner : outer;
|
||||
return Base::coeff(row, col);
|
||||
}
|
||||
template <int LoadMode, typename PacketType>
|
||||
EIGEN_DEVICE_FUNC inline PacketType packetByOuterInner(Index outer, Index inner) const {
|
||||
Index row = IsRowMajor ? outer : inner;
|
||||
Index col = IsRowMajor ? inner : outer;
|
||||
return Base::template packet<LoadMode, PacketType>(row, col);
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC inline Index innerSize() const { return m_xpr.innerSize(); }
|
||||
EIGEN_DEVICE_FUNC inline Index outerSize() const { return m_xpr.outerSize(); }
|
||||
EIGEN_DEVICE_FUNC inline Index size() const { return m_xpr.size(); }
|
||||
|
||||
const Derived& m_xpr;
|
||||
};
|
||||
|
||||
template <typename Derived, typename Func>
|
||||
struct find_coeff_impl {
|
||||
using Evaluator = find_coeff_evaluator<Derived>;
|
||||
static constexpr int Flags = Evaluator::Flags;
|
||||
static constexpr int Alignment = Evaluator::Alignment;
|
||||
static constexpr bool IsRowMajor = Derived::IsRowMajor;
|
||||
static constexpr int MaxInnerSizeAtCompileTime =
|
||||
IsRowMajor ? Derived::MaxColsAtCompileTime : Derived::MaxRowsAtCompileTime;
|
||||
static constexpr int MaxSizeAtCompileTime = Derived::MaxSizeAtCompileTime;
|
||||
|
||||
using Scalar = typename Derived::Scalar;
|
||||
using Packet = typename Evaluator::Packet;
|
||||
|
||||
static constexpr int PacketSize = unpacket_traits<Packet>::size;
|
||||
static constexpr bool Linearize = bool(Flags & LinearAccessBit);
|
||||
static constexpr bool DontVectorize =
|
||||
enum_lt_not_dynamic(Linearize ? MaxSizeAtCompileTime : MaxInnerSizeAtCompileTime, PacketSize);
|
||||
static constexpr bool Vectorize =
|
||||
!DontVectorize && bool(Flags & PacketAccessBit) && functor_traits<Func>::PacketAccess;
|
||||
|
||||
using Loop = find_coeff_loop<Evaluator, Func, Linearize, Vectorize>;
|
||||
|
||||
template <bool ForwardLinearAccess = Linearize, std::enable_if_t<!ForwardLinearAccess, bool> = true>
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived& xpr, Func& func, Scalar& res, Index& outer,
|
||||
Index& inner) {
|
||||
Evaluator eval(xpr);
|
||||
Loop::run(eval, func, res, outer, inner);
|
||||
}
|
||||
template <bool ForwardLinearAccess = Linearize, std::enable_if_t<ForwardLinearAccess, bool> = true>
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived& xpr, Func& func, Scalar& res, Index& outer,
|
||||
Index& inner) {
|
||||
// where possible, use the linear loop and back-calculate the outer and inner indices
|
||||
Index index = 0;
|
||||
run(xpr, func, res, index);
|
||||
outer = index / xpr.innerSize();
|
||||
inner = index % xpr.innerSize();
|
||||
}
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(const Derived& xpr, Func& func, Scalar& res, Index& index) {
|
||||
Evaluator eval(xpr);
|
||||
Loop::run(eval, func, res, index);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Derived, typename IndexType, typename Func>
|
||||
EIGEN_DEVICE_FUNC typename internal::traits<Derived>::Scalar findCoeff(const DenseBase<Derived>& mat, Func& func,
|
||||
IndexType* rowPtr, IndexType* colPtr) {
|
||||
eigen_assert(mat.rows() > 0 && mat.cols() > 0 && "you are using an empty matrix");
|
||||
using Scalar = typename DenseBase<Derived>::Scalar;
|
||||
using FindCoeffImpl = internal::find_coeff_impl<Derived, Func>;
|
||||
Index outer = 0;
|
||||
Index inner = 0;
|
||||
Scalar res = mat.coeff(0, 0);
|
||||
FindCoeffImpl::run(mat.derived(), func, res, outer, inner);
|
||||
*rowPtr = internal::convert_index<IndexType>(Derived::IsRowMajor ? outer : inner);
|
||||
if (colPtr) *colPtr = internal::convert_index<IndexType>(Derived::IsRowMajor ? inner : outer);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename Derived, typename IndexType, typename Func>
|
||||
EIGEN_DEVICE_FUNC typename internal::traits<Derived>::Scalar findCoeff(const DenseBase<Derived>& mat, Func& func,
|
||||
IndexType* indexPtr) {
|
||||
eigen_assert(mat.size() > 0 && "you are using an empty matrix");
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
using Scalar = typename DenseBase<Derived>::Scalar;
|
||||
using FindCoeffImpl = internal::find_coeff_impl<Derived, Func>;
|
||||
Index index = 0;
|
||||
Scalar res = mat.coeff(0);
|
||||
FindCoeffImpl::run(mat.derived(), func, res, index);
|
||||
*indexPtr = internal::convert_index<IndexType>(index);
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/** \fn DenseBase<Derived>::minCoeff(IndexType* rowId, IndexType* colId) const
|
||||
* \returns the minimum of all coefficients of *this and puts in *row and *col its location.
|
||||
*
|
||||
* If there are multiple coefficients with the same extreme value, the location of the first instance is returned.
|
||||
*
|
||||
* In case \c *this contains NaN, NaNPropagation determines the behavior:
|
||||
* NaNPropagation == PropagateFast : undefined
|
||||
* NaNPropagation == PropagateNaN : result is NaN
|
||||
* NaNPropagation == PropagateNumbers : result is maximum of elements that are not NaN
|
||||
* \warning the matrix must be not empty, otherwise an assertion is triggered.
|
||||
*
|
||||
* \sa DenseBase::minCoeff(Index*), DenseBase::maxCoeff(Index*,Index*), DenseBase::visit(), DenseBase::minCoeff()
|
||||
*/
|
||||
template <typename Derived>
|
||||
template <int NaNPropagation, typename IndexType>
|
||||
EIGEN_DEVICE_FUNC typename internal::traits<Derived>::Scalar DenseBase<Derived>::minCoeff(IndexType* rowPtr,
|
||||
IndexType* colPtr) const {
|
||||
using Func = internal::min_coeff_functor<Scalar, NaNPropagation>;
|
||||
Func func;
|
||||
return internal::findCoeff(derived(), func, rowPtr, colPtr);
|
||||
}
|
||||
|
||||
/** \returns the minimum of all coefficients of *this and puts in *index its location.
|
||||
*
|
||||
* If there are multiple coefficients with the same extreme value, the location of the first instance is returned.
|
||||
*
|
||||
* In case \c *this contains NaN, NaNPropagation determines the behavior:
|
||||
* NaNPropagation == PropagateFast : undefined
|
||||
* NaNPropagation == PropagateNaN : result is NaN
|
||||
* NaNPropagation == PropagateNumbers : result is maximum of elements that are not NaN
|
||||
* \warning the matrix must be not empty, otherwise an assertion is triggered.
|
||||
*
|
||||
* \sa DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::maxCoeff(IndexType*,IndexType*), DenseBase::visit(),
|
||||
* DenseBase::minCoeff()
|
||||
*/
|
||||
template <typename Derived>
|
||||
template <int NaNPropagation, typename IndexType>
|
||||
EIGEN_DEVICE_FUNC typename internal::traits<Derived>::Scalar DenseBase<Derived>::minCoeff(IndexType* indexPtr) const {
|
||||
using Func = internal::min_coeff_functor<Scalar, NaNPropagation>;
|
||||
Func func;
|
||||
return internal::findCoeff(derived(), func, indexPtr);
|
||||
}
|
||||
|
||||
/** \fn DenseBase<Derived>::maxCoeff(IndexType* rowId, IndexType* colId) const
|
||||
* \returns the maximum of all coefficients of *this and puts in *row and *col its location.
|
||||
*
|
||||
* If there are multiple coefficients with the same extreme value, the location of the first instance is returned.
|
||||
*
|
||||
* In case \c *this contains NaN, NaNPropagation determines the behavior:
|
||||
* NaNPropagation == PropagateFast : undefined
|
||||
* NaNPropagation == PropagateNaN : result is NaN
|
||||
* NaNPropagation == PropagateNumbers : result is maximum of elements that are not NaN
|
||||
* \warning the matrix must be not empty, otherwise an assertion is triggered.
|
||||
*
|
||||
* \sa DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::visit(), DenseBase::maxCoeff()
|
||||
*/
|
||||
template <typename Derived>
|
||||
template <int NaNPropagation, typename IndexType>
|
||||
EIGEN_DEVICE_FUNC typename internal::traits<Derived>::Scalar DenseBase<Derived>::maxCoeff(IndexType* rowPtr,
|
||||
IndexType* colPtr) const {
|
||||
using Func = internal::max_coeff_functor<Scalar, NaNPropagation>;
|
||||
Func func;
|
||||
return internal::findCoeff(derived(), func, rowPtr, colPtr);
|
||||
}
|
||||
|
||||
/** \returns the maximum of all coefficients of *this and puts in *index its location.
|
||||
*
|
||||
* If there are multiple coefficients with the same extreme value, the location of the first instance is returned.
|
||||
*
|
||||
* In case \c *this contains NaN, NaNPropagation determines the behavior:
|
||||
* NaNPropagation == PropagateFast : undefined
|
||||
* NaNPropagation == PropagateNaN : result is NaN
|
||||
* NaNPropagation == PropagateNumbers : result is maximum of elements that are not NaN
|
||||
* \warning the matrix must be not empty, otherwise an assertion is triggered.
|
||||
*
|
||||
* \sa DenseBase::maxCoeff(IndexType*,IndexType*), DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::visitor(),
|
||||
* DenseBase::maxCoeff()
|
||||
*/
|
||||
template <typename Derived>
|
||||
template <int NaNPropagation, typename IndexType>
|
||||
EIGEN_DEVICE_FUNC typename internal::traits<Derived>::Scalar DenseBase<Derived>::maxCoeff(IndexType* indexPtr) const {
|
||||
using Func = internal::max_coeff_functor<Scalar, NaNPropagation>;
|
||||
Func func;
|
||||
return internal::findCoeff(derived(), func, indexPtr);
|
||||
}
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_FIND_COEFF_H
|
||||
@@ -0,0 +1,260 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2024 Charlie Schlosser <cs.schlosser@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_INNER_PRODUCT_EVAL_H
|
||||
#define EIGEN_INNER_PRODUCT_EVAL_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
// recursively searches for the largest simd type that does not exceed Size, or the smallest if no such type exists
|
||||
template <typename Scalar, int Size, typename Packet = typename packet_traits<Scalar>::type,
|
||||
bool Stop =
|
||||
(unpacket_traits<Packet>::size <= Size) || is_same<Packet, typename unpacket_traits<Packet>::half>::value>
|
||||
struct find_inner_product_packet_helper;
|
||||
|
||||
template <typename Scalar, int Size, typename Packet>
|
||||
struct find_inner_product_packet_helper<Scalar, Size, Packet, false> {
|
||||
using type = typename find_inner_product_packet_helper<Scalar, Size, typename unpacket_traits<Packet>::half>::type;
|
||||
};
|
||||
|
||||
template <typename Scalar, int Size, typename Packet>
|
||||
struct find_inner_product_packet_helper<Scalar, Size, Packet, true> {
|
||||
using type = Packet;
|
||||
};
|
||||
|
||||
template <typename Scalar, int Size>
|
||||
struct find_inner_product_packet : find_inner_product_packet_helper<Scalar, Size> {};
|
||||
|
||||
template <typename Scalar>
|
||||
struct find_inner_product_packet<Scalar, Dynamic> {
|
||||
using type = typename packet_traits<Scalar>::type;
|
||||
};
|
||||
|
||||
template <typename Lhs, typename Rhs>
|
||||
struct inner_product_assert {
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Lhs)
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Rhs)
|
||||
EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Lhs, Rhs)
|
||||
#ifndef EIGEN_NO_DEBUG
|
||||
static EIGEN_DEVICE_FUNC void run(const Lhs& lhs, const Rhs& rhs) {
|
||||
eigen_assert((lhs.size() == rhs.size()) && "Inner product: lhs and rhs vectors must have same size");
|
||||
}
|
||||
#else
|
||||
static EIGEN_DEVICE_FUNC void run(const Lhs&, const Rhs&) {}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename Func, typename Lhs, typename Rhs>
|
||||
struct inner_product_evaluator {
|
||||
static constexpr int LhsFlags = evaluator<Lhs>::Flags;
|
||||
static constexpr int RhsFlags = evaluator<Rhs>::Flags;
|
||||
static constexpr int SizeAtCompileTime = size_prefer_fixed(Lhs::SizeAtCompileTime, Rhs::SizeAtCompileTime);
|
||||
static constexpr int MaxSizeAtCompileTime =
|
||||
min_size_prefer_fixed(Lhs::MaxSizeAtCompileTime, Rhs::MaxSizeAtCompileTime);
|
||||
static constexpr int LhsAlignment = evaluator<Lhs>::Alignment;
|
||||
static constexpr int RhsAlignment = evaluator<Rhs>::Alignment;
|
||||
|
||||
using Scalar = typename Func::result_type;
|
||||
using Packet = typename find_inner_product_packet<Scalar, SizeAtCompileTime>::type;
|
||||
|
||||
static constexpr bool Vectorize =
|
||||
bool(LhsFlags & RhsFlags & PacketAccessBit) && Func::PacketAccess &&
|
||||
((MaxSizeAtCompileTime == Dynamic) || (unpacket_traits<Packet>::size <= MaxSizeAtCompileTime));
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit inner_product_evaluator(const Lhs& lhs, const Rhs& rhs,
|
||||
Func func = Func())
|
||||
: m_func(func), m_lhs(lhs), m_rhs(rhs), m_size(lhs.size()) {
|
||||
inner_product_assert<Lhs, Rhs>::run(lhs, rhs);
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index size() const { return m_size.value(); }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index index) const {
|
||||
return m_func.coeff(m_lhs.coeff(index), m_rhs.coeff(index));
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(const Scalar& value, Index index) const {
|
||||
return m_func.coeff(value, m_lhs.coeff(index), m_rhs.coeff(index));
|
||||
}
|
||||
|
||||
template <typename PacketType, int LhsMode = LhsAlignment, int RhsMode = RhsAlignment>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index index) const {
|
||||
return m_func.packet(m_lhs.template packet<LhsMode, PacketType>(index),
|
||||
m_rhs.template packet<RhsMode, PacketType>(index));
|
||||
}
|
||||
|
||||
template <typename PacketType, int LhsMode = LhsAlignment, int RhsMode = RhsAlignment>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(const PacketType& value, Index index) const {
|
||||
return m_func.packet(value, m_lhs.template packet<LhsMode, PacketType>(index),
|
||||
m_rhs.template packet<RhsMode, PacketType>(index));
|
||||
}
|
||||
|
||||
const Func m_func;
|
||||
const evaluator<Lhs> m_lhs;
|
||||
const evaluator<Rhs> m_rhs;
|
||||
const variable_if_dynamic<Index, SizeAtCompileTime> m_size;
|
||||
};
|
||||
|
||||
template <typename Evaluator, bool Vectorize = Evaluator::Vectorize>
|
||||
struct inner_product_impl;
|
||||
|
||||
// scalar loop
|
||||
template <typename Evaluator>
|
||||
struct inner_product_impl<Evaluator, false> {
|
||||
using Scalar = typename Evaluator::Scalar;
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run(const Evaluator& eval) {
|
||||
const Index size = eval.size();
|
||||
if (size == 0) return Scalar(0);
|
||||
|
||||
Scalar result = eval.coeff(0);
|
||||
for (Index k = 1; k < size; k++) {
|
||||
result = eval.coeff(result, k);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// vector loop
|
||||
template <typename Evaluator>
|
||||
struct inner_product_impl<Evaluator, true> {
|
||||
using UnsignedIndex = std::make_unsigned_t<Index>;
|
||||
using Scalar = typename Evaluator::Scalar;
|
||||
using Packet = typename Evaluator::Packet;
|
||||
static constexpr int PacketSize = unpacket_traits<Packet>::size;
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar run(const Evaluator& eval) {
|
||||
const UnsignedIndex size = static_cast<UnsignedIndex>(eval.size());
|
||||
if (size < PacketSize) return inner_product_impl<Evaluator, false>::run(eval);
|
||||
|
||||
const UnsignedIndex packetEnd = numext::round_down(size, PacketSize);
|
||||
const UnsignedIndex quadEnd = numext::round_down(size, 4 * PacketSize);
|
||||
const UnsignedIndex numPackets = size / PacketSize;
|
||||
const UnsignedIndex numRemPackets = (packetEnd - quadEnd) / PacketSize;
|
||||
|
||||
Packet presult0, presult1, presult2, presult3;
|
||||
|
||||
presult0 = eval.template packet<Packet>(0 * PacketSize);
|
||||
if (numPackets >= 2) presult1 = eval.template packet<Packet>(1 * PacketSize);
|
||||
if (numPackets >= 3) presult2 = eval.template packet<Packet>(2 * PacketSize);
|
||||
if (numPackets >= 4) {
|
||||
presult3 = eval.template packet<Packet>(3 * PacketSize);
|
||||
|
||||
for (UnsignedIndex k = 4 * PacketSize; k < quadEnd; k += 4 * PacketSize) {
|
||||
presult0 = eval.packet(presult0, k + 0 * PacketSize);
|
||||
presult1 = eval.packet(presult1, k + 1 * PacketSize);
|
||||
presult2 = eval.packet(presult2, k + 2 * PacketSize);
|
||||
presult3 = eval.packet(presult3, k + 3 * PacketSize);
|
||||
}
|
||||
|
||||
if (numRemPackets >= 1) presult0 = eval.packet(presult0, quadEnd + 0 * PacketSize);
|
||||
if (numRemPackets >= 2) presult1 = eval.packet(presult1, quadEnd + 1 * PacketSize);
|
||||
if (numRemPackets == 3) presult2 = eval.packet(presult2, quadEnd + 2 * PacketSize);
|
||||
|
||||
presult2 = padd(presult2, presult3);
|
||||
}
|
||||
|
||||
if (numPackets >= 3) presult1 = padd(presult1, presult2);
|
||||
if (numPackets >= 2) presult0 = padd(presult0, presult1);
|
||||
|
||||
Scalar result = predux(presult0);
|
||||
for (UnsignedIndex k = packetEnd; k < size; k++) {
|
||||
result = eval.coeff(result, k);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Scalar, bool Conj>
|
||||
struct conditional_conj;
|
||||
|
||||
template <typename Scalar>
|
||||
struct conditional_conj<Scalar, true> {
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(const Scalar& a) { return numext::conj(a); }
|
||||
template <typename Packet>
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packet(const Packet& a) {
|
||||
return pconj(a);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Scalar>
|
||||
struct conditional_conj<Scalar, false> {
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(const Scalar& a) { return a; }
|
||||
template <typename Packet>
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packet(const Packet& a) {
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename LhsScalar, typename RhsScalar, bool Conj>
|
||||
struct scalar_inner_product_op {
|
||||
using result_type = typename ScalarBinaryOpTraits<LhsScalar, RhsScalar>::ReturnType;
|
||||
using conj_helper = conditional_conj<LhsScalar, Conj>;
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type coeff(const LhsScalar& a, const RhsScalar& b) const {
|
||||
return (conj_helper::coeff(a) * b);
|
||||
}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type coeff(const result_type& accum, const LhsScalar& a,
|
||||
const RhsScalar& b) const {
|
||||
return (conj_helper::coeff(a) * b) + accum;
|
||||
}
|
||||
static constexpr bool PacketAccess = false;
|
||||
};
|
||||
|
||||
// Partial specialization for packet access if and only if
|
||||
// LhsScalar == RhsScalar == ScalarBinaryOpTraits<LhsScalar, RhsScalar>::ReturnType.
|
||||
template <typename Scalar, bool Conj>
|
||||
struct scalar_inner_product_op<
|
||||
Scalar,
|
||||
typename std::enable_if<internal::is_same<typename ScalarBinaryOpTraits<Scalar, Scalar>::ReturnType, Scalar>::value,
|
||||
Scalar>::type,
|
||||
Conj> {
|
||||
using result_type = Scalar;
|
||||
using conj_helper = conditional_conj<Scalar, Conj>;
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(const Scalar& a, const Scalar& b) const {
|
||||
return pmul(conj_helper::coeff(a), b);
|
||||
}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(const Scalar& accum, const Scalar& a, const Scalar& b) const {
|
||||
return pmadd(conj_helper::coeff(a), b, accum);
|
||||
}
|
||||
template <typename Packet>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packet(const Packet& a, const Packet& b) const {
|
||||
return pmul(conj_helper::packet(a), b);
|
||||
}
|
||||
template <typename Packet>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet packet(const Packet& accum, const Packet& a, const Packet& b) const {
|
||||
return pmadd(conj_helper::packet(a), b, accum);
|
||||
}
|
||||
static constexpr bool PacketAccess = packet_traits<Scalar>::HasMul && packet_traits<Scalar>::HasAdd;
|
||||
};
|
||||
|
||||
template <typename Lhs, typename Rhs, bool Conj>
|
||||
struct default_inner_product_impl {
|
||||
using LhsScalar = typename traits<Lhs>::Scalar;
|
||||
using RhsScalar = typename traits<Rhs>::Scalar;
|
||||
using Op = scalar_inner_product_op<LhsScalar, RhsScalar, Conj>;
|
||||
using Evaluator = inner_product_evaluator<Op, Lhs, Rhs>;
|
||||
using result_type = typename Evaluator::Scalar;
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type run(const MatrixBase<Lhs>& a, const MatrixBase<Rhs>& b) {
|
||||
Evaluator eval(a.derived(), b.derived(), Op());
|
||||
return inner_product_impl<Evaluator>::run(eval);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Lhs, typename Rhs>
|
||||
struct dot_impl : default_inner_product_impl<Lhs, Rhs, true> {};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_INNER_PRODUCT_EVAL_H
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_CORE_MODULE_H
|
||||
#error "Please include Eigen/Core instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,262 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2024 Charles Schlosser <cs.schlosser@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_RANDOM_IMPL_H
|
||||
#define EIGEN_RANDOM_IMPL_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
/****************************************************************************
|
||||
* Implementation of random *
|
||||
****************************************************************************/
|
||||
|
||||
template <typename Scalar, bool IsComplex, bool IsInteger>
|
||||
struct random_default_impl {};
|
||||
|
||||
template <typename Scalar>
|
||||
struct random_impl : random_default_impl<Scalar, NumTraits<Scalar>::IsComplex, NumTraits<Scalar>::IsInteger> {};
|
||||
|
||||
template <typename Scalar>
|
||||
struct random_retval {
|
||||
typedef Scalar type;
|
||||
};
|
||||
|
||||
template <typename Scalar>
|
||||
inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random(const Scalar& x, const Scalar& y) {
|
||||
return EIGEN_MATHFUNC_IMPL(random, Scalar)::run(x, y);
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
inline EIGEN_MATHFUNC_RETVAL(random, Scalar) random() {
|
||||
return EIGEN_MATHFUNC_IMPL(random, Scalar)::run();
|
||||
}
|
||||
|
||||
// TODO: replace or provide alternatives to this, e.g. std::random_device
|
||||
struct eigen_random_device {
|
||||
using ReturnType = int;
|
||||
static constexpr int Entropy = meta_floor_log2<(unsigned int)(RAND_MAX) + 1>::value;
|
||||
static constexpr ReturnType Highest = RAND_MAX;
|
||||
static EIGEN_DEVICE_FUNC inline ReturnType run() { return std::rand(); }
|
||||
};
|
||||
|
||||
// Fill a built-in unsigned integer with numRandomBits beginning with the least significant bit
|
||||
template <typename Scalar>
|
||||
struct random_bits_impl {
|
||||
EIGEN_STATIC_ASSERT(std::is_unsigned<Scalar>::value, SCALAR MUST BE A BUILT - IN UNSIGNED INTEGER)
|
||||
using RandomDevice = eigen_random_device;
|
||||
using RandomReturnType = typename RandomDevice::ReturnType;
|
||||
static constexpr int kEntropy = RandomDevice::Entropy;
|
||||
static constexpr int kTotalBits = sizeof(Scalar) * CHAR_BIT;
|
||||
// return a Scalar filled with numRandomBits beginning from the least significant bit
|
||||
static EIGEN_DEVICE_FUNC inline Scalar run(int numRandomBits) {
|
||||
eigen_assert((numRandomBits >= 0) && (numRandomBits <= kTotalBits));
|
||||
const Scalar mask = Scalar(-1) >> ((kTotalBits - numRandomBits) & (kTotalBits - 1));
|
||||
Scalar randomBits = 0;
|
||||
for (int shift = 0; shift < numRandomBits; shift += kEntropy) {
|
||||
RandomReturnType r = RandomDevice::run();
|
||||
randomBits |= static_cast<Scalar>(r) << shift;
|
||||
}
|
||||
// clear the excess bits
|
||||
randomBits &= mask;
|
||||
return randomBits;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename BitsType>
|
||||
EIGEN_DEVICE_FUNC inline BitsType getRandomBits(int numRandomBits) {
|
||||
return random_bits_impl<BitsType>::run(numRandomBits);
|
||||
}
|
||||
|
||||
// random implementation for a built-in floating point type
|
||||
template <typename Scalar, bool BuiltIn = std::is_floating_point<Scalar>::value>
|
||||
struct random_float_impl {
|
||||
using BitsType = typename numext::get_integer_by_size<sizeof(Scalar)>::unsigned_type;
|
||||
static constexpr EIGEN_DEVICE_FUNC inline int mantissaBits() {
|
||||
const int digits = NumTraits<Scalar>::digits();
|
||||
return digits - 1;
|
||||
}
|
||||
static EIGEN_DEVICE_FUNC inline Scalar run(int numRandomBits) {
|
||||
eigen_assert(numRandomBits >= 0 && numRandomBits <= mantissaBits());
|
||||
BitsType randomBits = getRandomBits<BitsType>(numRandomBits);
|
||||
// if fewer than MantissaBits is requested, shift them to the left
|
||||
randomBits <<= (mantissaBits() - numRandomBits);
|
||||
// randomBits is in the half-open interval [2,4)
|
||||
randomBits |= numext::bit_cast<BitsType>(Scalar(2));
|
||||
// result is in the half-open interval [-1,1)
|
||||
Scalar result = numext::bit_cast<Scalar>(randomBits) - Scalar(3);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
// random implementation for a custom floating point type
|
||||
// uses double as the implementation with a mantissa with a size equal to either the target scalar's mantissa or that of
|
||||
// double, whichever is smaller
|
||||
template <typename Scalar>
|
||||
struct random_float_impl<Scalar, false> {
|
||||
static EIGEN_DEVICE_FUNC inline int mantissaBits() {
|
||||
const int digits = NumTraits<Scalar>::digits();
|
||||
constexpr int kDoubleDigits = NumTraits<double>::digits();
|
||||
return numext::mini(digits, kDoubleDigits) - 1;
|
||||
}
|
||||
static EIGEN_DEVICE_FUNC inline Scalar run(int numRandomBits) {
|
||||
eigen_assert(numRandomBits >= 0 && numRandomBits <= mantissaBits());
|
||||
Scalar result = static_cast<Scalar>(random_float_impl<double>::run(numRandomBits));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
#if !EIGEN_COMP_NVCC
|
||||
// random implementation for long double
|
||||
// this specialization is not compatible with double-double scalars
|
||||
template <bool Specialize = (sizeof(long double) == 2 * sizeof(uint64_t)) &&
|
||||
((std::numeric_limits<long double>::digits != (2 * std::numeric_limits<double>::digits)))>
|
||||
struct random_longdouble_impl {
|
||||
static constexpr int Size = sizeof(long double);
|
||||
static constexpr EIGEN_DEVICE_FUNC int mantissaBits() { return NumTraits<long double>::digits() - 1; }
|
||||
static EIGEN_DEVICE_FUNC inline long double run(int numRandomBits) {
|
||||
eigen_assert(numRandomBits >= 0 && numRandomBits <= mantissaBits());
|
||||
EIGEN_USING_STD(memcpy);
|
||||
int numLowBits = numext::mini(numRandomBits, 64);
|
||||
int numHighBits = numext::maxi(numRandomBits - 64, 0);
|
||||
uint64_t randomBits[2];
|
||||
long double result = 2.0L;
|
||||
memcpy(&randomBits, &result, Size);
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
randomBits[0] |= getRandomBits<uint64_t>(numLowBits);
|
||||
randomBits[1] |= getRandomBits<uint64_t>(numHighBits);
|
||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
randomBits[0] |= getRandomBits<uint64_t>(numHighBits);
|
||||
randomBits[1] |= getRandomBits<uint64_t>(numLowBits);
|
||||
#else
|
||||
#error Unexpected or undefined __BYTE_ORDER__
|
||||
#endif
|
||||
memcpy(&result, &randomBits, Size);
|
||||
result -= 3.0L;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct random_longdouble_impl<false> {
|
||||
static constexpr EIGEN_DEVICE_FUNC int mantissaBits() { return NumTraits<double>::digits() - 1; }
|
||||
static EIGEN_DEVICE_FUNC inline long double run(int numRandomBits) {
|
||||
return static_cast<long double>(random_float_impl<double>::run(numRandomBits));
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct random_float_impl<long double> : random_longdouble_impl<> {};
|
||||
#endif
|
||||
|
||||
template <typename Scalar>
|
||||
struct random_default_impl<Scalar, false, false> {
|
||||
using Impl = random_float_impl<Scalar>;
|
||||
static EIGEN_DEVICE_FUNC inline Scalar run(const Scalar& x, const Scalar& y, int numRandomBits) {
|
||||
Scalar half_x = Scalar(0.5) * x;
|
||||
Scalar half_y = Scalar(0.5) * y;
|
||||
Scalar result = (half_x + half_y) + (half_y - half_x) * run(numRandomBits);
|
||||
// result is in the half-open interval [x, y) -- provided that x < y
|
||||
return result;
|
||||
}
|
||||
static EIGEN_DEVICE_FUNC inline Scalar run(const Scalar& x, const Scalar& y) {
|
||||
return run(x, y, Impl::mantissaBits());
|
||||
}
|
||||
static EIGEN_DEVICE_FUNC inline Scalar run(int numRandomBits) { return Impl::run(numRandomBits); }
|
||||
static EIGEN_DEVICE_FUNC inline Scalar run() { return run(Impl::mantissaBits()); }
|
||||
};
|
||||
|
||||
template <typename Scalar, bool IsSigned = NumTraits<Scalar>::IsSigned, bool BuiltIn = std::is_integral<Scalar>::value>
|
||||
struct random_int_impl;
|
||||
|
||||
// random implementation for a built-in unsigned integer type
|
||||
template <typename Scalar>
|
||||
struct random_int_impl<Scalar, false, true> {
|
||||
static constexpr int kTotalBits = sizeof(Scalar) * CHAR_BIT;
|
||||
static EIGEN_DEVICE_FUNC inline Scalar run(const Scalar& x, const Scalar& y) {
|
||||
if (y <= x) return x;
|
||||
Scalar range = y - x;
|
||||
// handle edge case where [x,y] spans the entire range of Scalar
|
||||
if (range == NumTraits<Scalar>::highest()) return run();
|
||||
Scalar count = range + 1;
|
||||
// calculate the number of random bits needed to fill range
|
||||
int numRandomBits = log2_ceil(count);
|
||||
Scalar randomBits;
|
||||
do {
|
||||
randomBits = getRandomBits<Scalar>(numRandomBits);
|
||||
// if the random draw is outside [0, range), try again (rejection sampling)
|
||||
// in the worst-case scenario, the probability of rejection is: 1/2 - 1/2^numRandomBits < 50%
|
||||
} while (randomBits >= count);
|
||||
Scalar result = x + randomBits;
|
||||
return result;
|
||||
}
|
||||
static EIGEN_DEVICE_FUNC inline Scalar run() { return getRandomBits<Scalar>(kTotalBits); }
|
||||
};
|
||||
|
||||
// random implementation for a built-in signed integer type
|
||||
template <typename Scalar>
|
||||
struct random_int_impl<Scalar, true, true> {
|
||||
static constexpr int kTotalBits = sizeof(Scalar) * CHAR_BIT;
|
||||
using BitsType = typename make_unsigned<Scalar>::type;
|
||||
static EIGEN_DEVICE_FUNC inline Scalar run(const Scalar& x, const Scalar& y) {
|
||||
if (y <= x) return x;
|
||||
// Avoid overflow by representing `range` as an unsigned type
|
||||
BitsType range = static_cast<BitsType>(y) - static_cast<BitsType>(x);
|
||||
BitsType randomBits = random_int_impl<BitsType>::run(0, range);
|
||||
// Avoid overflow in the case where `x` is negative and there is a large range so
|
||||
// `randomBits` would also be negative if cast to `Scalar` first.
|
||||
Scalar result = static_cast<Scalar>(static_cast<BitsType>(x) + randomBits);
|
||||
return result;
|
||||
}
|
||||
static EIGEN_DEVICE_FUNC inline Scalar run() { return static_cast<Scalar>(getRandomBits<BitsType>(kTotalBits)); }
|
||||
};
|
||||
|
||||
// todo: custom integers
|
||||
template <typename Scalar, bool IsSigned>
|
||||
struct random_int_impl<Scalar, IsSigned, false> {
|
||||
static EIGEN_DEVICE_FUNC inline Scalar run(const Scalar&, const Scalar&) { return run(); }
|
||||
static EIGEN_DEVICE_FUNC inline Scalar run() {
|
||||
eigen_assert(std::false_type::value && "RANDOM FOR CUSTOM INTEGERS NOT YET SUPPORTED");
|
||||
return Scalar(0);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Scalar>
|
||||
struct random_default_impl<Scalar, false, true> : random_int_impl<Scalar> {};
|
||||
|
||||
template <>
|
||||
struct random_impl<bool> {
|
||||
static EIGEN_DEVICE_FUNC inline bool run(const bool& x, const bool& y) {
|
||||
if (y <= x) return x;
|
||||
return run();
|
||||
}
|
||||
static EIGEN_DEVICE_FUNC inline bool run() { return getRandomBits<unsigned>(1) ? true : false; }
|
||||
};
|
||||
|
||||
template <typename Scalar>
|
||||
struct random_default_impl<Scalar, true, false> {
|
||||
typedef typename NumTraits<Scalar>::Real RealScalar;
|
||||
using Impl = random_impl<RealScalar>;
|
||||
static EIGEN_DEVICE_FUNC inline Scalar run(const Scalar& x, const Scalar& y, int numRandomBits) {
|
||||
return Scalar(Impl::run(x.real(), y.real(), numRandomBits), Impl::run(x.imag(), y.imag(), numRandomBits));
|
||||
}
|
||||
static EIGEN_DEVICE_FUNC inline Scalar run(const Scalar& x, const Scalar& y) {
|
||||
return Scalar(Impl::run(x.real(), y.real()), Impl::run(x.imag(), y.imag()));
|
||||
}
|
||||
static EIGEN_DEVICE_FUNC inline Scalar run(int numRandomBits) {
|
||||
return Scalar(Impl::run(numRandomBits), Impl::run(numRandomBits));
|
||||
}
|
||||
static EIGEN_DEVICE_FUNC inline Scalar run() { return Scalar(Impl::run(), Impl::run()); }
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_RANDOM_IMPL_H
|
||||
@@ -0,0 +1,250 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2025 Charlie Schlosser <cs.schlosser@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_REALVIEW_H
|
||||
#define EIGEN_REALVIEW_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Vectorized assignment to RealView requires array-oriented access to the real and imaginary components.
|
||||
// From https://en.cppreference.com/w/cpp/numeric/complex.html:
|
||||
// For any pointer to an element of an array of std::complex<T> named p and any valid array index i,
|
||||
// reinterpret_cast<T*>(p)[2 * i] is the real part of the complex number p[i], and
|
||||
// reinterpret_cast<T*>(p)[2 * i + 1] is the imaginary part of the complex number p[i].
|
||||
|
||||
template <typename ComplexScalar>
|
||||
struct complex_array_access : std::false_type {};
|
||||
template <>
|
||||
struct complex_array_access<std::complex<float>> : std::true_type {};
|
||||
template <>
|
||||
struct complex_array_access<std::complex<double>> : std::true_type {};
|
||||
template <>
|
||||
struct complex_array_access<std::complex<long double>> : std::true_type {};
|
||||
|
||||
template <typename Xpr>
|
||||
struct traits<RealView<Xpr>> : public traits<Xpr> {
|
||||
template <typename T>
|
||||
static constexpr int double_size(T size, bool times_two) {
|
||||
int size_as_int = int(size);
|
||||
if (size_as_int == Dynamic) return Dynamic;
|
||||
return times_two ? (2 * size_as_int) : size_as_int;
|
||||
}
|
||||
using Base = traits<Xpr>;
|
||||
using ComplexScalar = typename Base::Scalar;
|
||||
using Scalar = typename NumTraits<ComplexScalar>::Real;
|
||||
static constexpr int ActualDirectAccessBit = complex_array_access<ComplexScalar>::value ? DirectAccessBit : 0;
|
||||
static constexpr int ActualPacketAccessBit = packet_traits<Scalar>::Vectorizable ? PacketAccessBit : 0;
|
||||
static constexpr int FlagMask =
|
||||
ActualDirectAccessBit | ActualPacketAccessBit | HereditaryBits | LinearAccessBit | LvalueBit;
|
||||
static constexpr int BaseFlags = int(evaluator<Xpr>::Flags) | int(Base::Flags);
|
||||
static constexpr int Flags = BaseFlags & FlagMask;
|
||||
static constexpr bool IsRowMajor = Flags & RowMajorBit;
|
||||
static constexpr int RowsAtCompileTime = double_size(Base::RowsAtCompileTime, !IsRowMajor);
|
||||
static constexpr int ColsAtCompileTime = double_size(Base::ColsAtCompileTime, IsRowMajor);
|
||||
static constexpr int SizeAtCompileTime = size_at_compile_time(RowsAtCompileTime, ColsAtCompileTime);
|
||||
static constexpr int MaxRowsAtCompileTime = double_size(Base::MaxRowsAtCompileTime, !IsRowMajor);
|
||||
static constexpr int MaxColsAtCompileTime = double_size(Base::MaxColsAtCompileTime, IsRowMajor);
|
||||
static constexpr int MaxSizeAtCompileTime = size_at_compile_time(MaxRowsAtCompileTime, MaxColsAtCompileTime);
|
||||
static constexpr int OuterStrideAtCompileTime = double_size(outer_stride_at_compile_time<Xpr>::ret, true);
|
||||
static constexpr int InnerStrideAtCompileTime = inner_stride_at_compile_time<Xpr>::ret;
|
||||
};
|
||||
|
||||
template <typename Xpr>
|
||||
struct evaluator<RealView<Xpr>> : private evaluator<Xpr> {
|
||||
using BaseEvaluator = evaluator<Xpr>;
|
||||
using XprType = RealView<Xpr>;
|
||||
using ExpressionTraits = traits<XprType>;
|
||||
using ComplexScalar = typename ExpressionTraits::ComplexScalar;
|
||||
using ComplexCoeffReturnType = typename BaseEvaluator::CoeffReturnType;
|
||||
using Scalar = typename ExpressionTraits::Scalar;
|
||||
|
||||
static constexpr bool IsRowMajor = ExpressionTraits::IsRowMajor;
|
||||
static constexpr int Flags = ExpressionTraits::Flags;
|
||||
static constexpr int CoeffReadCost = BaseEvaluator::CoeffReadCost;
|
||||
static constexpr int Alignment = BaseEvaluator::Alignment;
|
||||
|
||||
EIGEN_DEVICE_FUNC explicit evaluator(XprType realView) : BaseEvaluator(realView.m_xpr) {}
|
||||
|
||||
template <bool Enable = std::is_reference<ComplexCoeffReturnType>::value, typename = std::enable_if_t<!Enable>>
|
||||
constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index row, Index col) const {
|
||||
ComplexCoeffReturnType cscalar = BaseEvaluator::coeff(IsRowMajor ? row : row / 2, IsRowMajor ? col / 2 : col);
|
||||
Index p = (IsRowMajor ? col : row) & 1;
|
||||
return p ? numext::real(cscalar) : numext::imag(cscalar);
|
||||
}
|
||||
|
||||
template <bool Enable = std::is_reference<ComplexCoeffReturnType>::value, typename = std::enable_if_t<Enable>>
|
||||
constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(Index row, Index col) const {
|
||||
ComplexCoeffReturnType cscalar = BaseEvaluator::coeff(IsRowMajor ? row : row / 2, IsRowMajor ? col / 2 : col);
|
||||
Index p = (IsRowMajor ? col : row) & 1;
|
||||
return reinterpret_cast<const Scalar(&)[2]>(cscalar)[p];
|
||||
}
|
||||
|
||||
constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) {
|
||||
ComplexScalar& cscalar = BaseEvaluator::coeffRef(IsRowMajor ? row : row / 2, IsRowMajor ? col / 2 : col);
|
||||
Index p = (IsRowMajor ? col : row) & 1;
|
||||
return reinterpret_cast<Scalar(&)[2]>(cscalar)[p];
|
||||
}
|
||||
|
||||
template <bool Enable = std::is_reference<ComplexCoeffReturnType>::value, typename = std::enable_if_t<!Enable>>
|
||||
constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar coeff(Index index) const {
|
||||
ComplexCoeffReturnType cscalar = BaseEvaluator::coeff(index / 2);
|
||||
Index p = index & 1;
|
||||
return p ? numext::real(cscalar) : numext::imag(cscalar);
|
||||
}
|
||||
|
||||
template <bool Enable = std::is_reference<ComplexCoeffReturnType>::value, typename = std::enable_if_t<Enable>>
|
||||
constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Scalar& coeff(Index index) const {
|
||||
ComplexCoeffReturnType cscalar = BaseEvaluator::coeff(index / 2);
|
||||
Index p = index & 1;
|
||||
return reinterpret_cast<const Scalar(&)[2]>(cscalar)[p];
|
||||
}
|
||||
|
||||
constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) {
|
||||
ComplexScalar& cscalar = BaseEvaluator::coeffRef(index / 2);
|
||||
Index p = index & 1;
|
||||
return reinterpret_cast<Scalar(&)[2]>(cscalar)[p];
|
||||
}
|
||||
|
||||
template <int LoadMode, typename PacketType>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const {
|
||||
constexpr int RealPacketSize = unpacket_traits<PacketType>::size;
|
||||
using ComplexPacket = typename find_packet_by_size<ComplexScalar, RealPacketSize / 2>::type;
|
||||
EIGEN_STATIC_ASSERT((find_packet_by_size<ComplexScalar, RealPacketSize / 2>::value),
|
||||
MISSING COMPATIBLE COMPLEX PACKET TYPE)
|
||||
eigen_assert(((IsRowMajor ? col : row) % 2 == 0) && "the inner index must be even");
|
||||
|
||||
Index crow = IsRowMajor ? row : row / 2;
|
||||
Index ccol = IsRowMajor ? col / 2 : col;
|
||||
ComplexPacket cpacket = BaseEvaluator::template packet<LoadMode, ComplexPacket>(crow, ccol);
|
||||
return preinterpret<PacketType, ComplexPacket>(cpacket);
|
||||
}
|
||||
|
||||
template <int LoadMode, typename PacketType>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index index) const {
|
||||
constexpr int RealPacketSize = unpacket_traits<PacketType>::size;
|
||||
using ComplexPacket = typename find_packet_by_size<ComplexScalar, RealPacketSize / 2>::type;
|
||||
EIGEN_STATIC_ASSERT((find_packet_by_size<ComplexScalar, RealPacketSize / 2>::value),
|
||||
MISSING COMPATIBLE COMPLEX PACKET TYPE)
|
||||
eigen_assert((index % 2 == 0) && "the index must be even");
|
||||
|
||||
Index cindex = index / 2;
|
||||
ComplexPacket cpacket = BaseEvaluator::template packet<LoadMode, ComplexPacket>(cindex);
|
||||
return preinterpret<PacketType, ComplexPacket>(cpacket);
|
||||
}
|
||||
|
||||
template <int LoadMode, typename PacketType>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index row, Index col, Index begin, Index count) const {
|
||||
constexpr int RealPacketSize = unpacket_traits<PacketType>::size;
|
||||
using ComplexPacket = typename find_packet_by_size<ComplexScalar, RealPacketSize / 2>::type;
|
||||
EIGEN_STATIC_ASSERT((find_packet_by_size<ComplexScalar, RealPacketSize / 2>::value),
|
||||
MISSING COMPATIBLE COMPLEX PACKET TYPE)
|
||||
eigen_assert(((IsRowMajor ? col : row) % 2 == 0) && "the inner index must be even");
|
||||
eigen_assert((begin % 2 == 0) && (count % 2 == 0) && "begin and count must be even");
|
||||
|
||||
Index crow = IsRowMajor ? row : row / 2;
|
||||
Index ccol = IsRowMajor ? col / 2 : col;
|
||||
Index cbegin = begin / 2;
|
||||
Index ccount = count / 2;
|
||||
ComplexPacket cpacket = BaseEvaluator::template packetSegment<LoadMode, ComplexPacket>(crow, ccol, cbegin, ccount);
|
||||
return preinterpret<PacketType, ComplexPacket>(cpacket);
|
||||
}
|
||||
|
||||
template <int LoadMode, typename PacketType>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index index, Index begin, Index count) const {
|
||||
constexpr int RealPacketSize = unpacket_traits<PacketType>::size;
|
||||
using ComplexPacket = typename find_packet_by_size<ComplexScalar, RealPacketSize / 2>::type;
|
||||
EIGEN_STATIC_ASSERT((find_packet_by_size<ComplexScalar, RealPacketSize / 2>::value),
|
||||
MISSING COMPATIBLE COMPLEX PACKET TYPE)
|
||||
eigen_assert((index % 2 == 0) && "the index must be even");
|
||||
eigen_assert((begin % 2 == 0) && (count % 2 == 0) && "begin and count must be even");
|
||||
|
||||
Index cindex = index / 2;
|
||||
Index cbegin = begin / 2;
|
||||
Index ccount = count / 2;
|
||||
ComplexPacket cpacket = BaseEvaluator::template packetSegment<LoadMode, ComplexPacket>(cindex, cbegin, ccount);
|
||||
return preinterpret<PacketType, ComplexPacket>(cpacket);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename Xpr>
|
||||
class RealView : public internal::dense_xpr_base<RealView<Xpr>>::type {
|
||||
using ExpressionTraits = internal::traits<RealView>;
|
||||
EIGEN_STATIC_ASSERT(NumTraits<typename Xpr::Scalar>::IsComplex, SCALAR MUST BE COMPLEX)
|
||||
public:
|
||||
using Scalar = typename ExpressionTraits::Scalar;
|
||||
using Nested = RealView;
|
||||
|
||||
EIGEN_DEVICE_FUNC explicit RealView(Xpr& xpr) : m_xpr(xpr) {}
|
||||
EIGEN_DEVICE_FUNC constexpr Index rows() const noexcept { return Xpr::IsRowMajor ? m_xpr.rows() : 2 * m_xpr.rows(); }
|
||||
EIGEN_DEVICE_FUNC constexpr Index cols() const noexcept { return Xpr::IsRowMajor ? 2 * m_xpr.cols() : m_xpr.cols(); }
|
||||
EIGEN_DEVICE_FUNC constexpr Index size() const noexcept { return 2 * m_xpr.size(); }
|
||||
EIGEN_DEVICE_FUNC constexpr Index innerStride() const noexcept { return m_xpr.innerStride(); }
|
||||
EIGEN_DEVICE_FUNC constexpr Index outerStride() const noexcept { return 2 * m_xpr.outerStride(); }
|
||||
EIGEN_DEVICE_FUNC void resize(Index rows, Index cols) {
|
||||
m_xpr.resize(Xpr::IsRowMajor ? rows : rows / 2, Xpr::IsRowMajor ? cols / 2 : cols);
|
||||
}
|
||||
EIGEN_DEVICE_FUNC void resize(Index size) { m_xpr.resize(size / 2); }
|
||||
EIGEN_DEVICE_FUNC Scalar* data() { return reinterpret_cast<Scalar*>(m_xpr.data()); }
|
||||
EIGEN_DEVICE_FUNC const Scalar* data() const { return reinterpret_cast<const Scalar*>(m_xpr.data()); }
|
||||
|
||||
EIGEN_DEVICE_FUNC RealView(const RealView&) = default;
|
||||
|
||||
EIGEN_DEVICE_FUNC RealView& operator=(const RealView& other);
|
||||
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC RealView& operator=(const RealView<OtherDerived>& other);
|
||||
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC RealView& operator=(const DenseBase<OtherDerived>& other);
|
||||
|
||||
protected:
|
||||
friend struct internal::evaluator<RealView<Xpr>>;
|
||||
Xpr& m_xpr;
|
||||
};
|
||||
|
||||
template <typename Xpr>
|
||||
EIGEN_DEVICE_FUNC RealView<Xpr>& RealView<Xpr>::operator=(const RealView& other) {
|
||||
internal::call_assignment(*this, other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Xpr>
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC RealView<Xpr>& RealView<Xpr>::operator=(const RealView<OtherDerived>& other) {
|
||||
internal::call_assignment(*this, other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Xpr>
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC RealView<Xpr>& RealView<Xpr>::operator=(const DenseBase<OtherDerived>& other) {
|
||||
internal::call_assignment(*this, other.derived());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
EIGEN_DEVICE_FUNC typename DenseBase<Derived>::RealViewReturnType DenseBase<Derived>::realView() {
|
||||
return RealViewReturnType(derived());
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
EIGEN_DEVICE_FUNC typename DenseBase<Derived>::ConstRealViewReturnType DenseBase<Derived>::realView() const {
|
||||
return ConstRealViewReturnType(derived());
|
||||
}
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_REALVIEW_H
|
||||
@@ -0,0 +1,382 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2009 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
// Copyright (C) 2007-2009 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_SKEWSYMMETRICMATRIX3_H
|
||||
#define EIGEN_SKEWSYMMETRICMATRIX3_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
/** \class SkewSymmetricBase
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* \brief Base class for skew symmetric matrices and expressions
|
||||
*
|
||||
* This is the base class that is inherited by SkewSymmetricMatrix3 and related expression
|
||||
* types, which internally use a three vector for storing the entries. SkewSymmetric
|
||||
* types always represent square three times three matrices.
|
||||
*
|
||||
* This implementations follows class DiagonalMatrix
|
||||
*
|
||||
* \tparam Derived is the derived type, a SkewSymmetricMatrix3 or SkewSymmetricWrapper.
|
||||
*
|
||||
* \sa class SkewSymmetricMatrix3, class SkewSymmetricWrapper
|
||||
*/
|
||||
template <typename Derived>
|
||||
class SkewSymmetricBase : public EigenBase<Derived> {
|
||||
public:
|
||||
typedef typename internal::traits<Derived>::SkewSymmetricVectorType SkewSymmetricVectorType;
|
||||
typedef typename SkewSymmetricVectorType::Scalar Scalar;
|
||||
typedef typename SkewSymmetricVectorType::RealScalar RealScalar;
|
||||
typedef typename internal::traits<Derived>::StorageKind StorageKind;
|
||||
typedef typename internal::traits<Derived>::StorageIndex StorageIndex;
|
||||
|
||||
enum {
|
||||
RowsAtCompileTime = SkewSymmetricVectorType::SizeAtCompileTime,
|
||||
ColsAtCompileTime = SkewSymmetricVectorType::SizeAtCompileTime,
|
||||
MaxRowsAtCompileTime = SkewSymmetricVectorType::MaxSizeAtCompileTime,
|
||||
MaxColsAtCompileTime = SkewSymmetricVectorType::MaxSizeAtCompileTime,
|
||||
IsVectorAtCompileTime = 0,
|
||||
Flags = NoPreferredStorageOrderBit
|
||||
};
|
||||
|
||||
typedef Matrix<Scalar, RowsAtCompileTime, ColsAtCompileTime, 0, MaxRowsAtCompileTime, MaxColsAtCompileTime>
|
||||
DenseMatrixType;
|
||||
typedef DenseMatrixType DenseType;
|
||||
typedef SkewSymmetricMatrix3<Scalar> PlainObject;
|
||||
|
||||
/** \returns a reference to the derived object. */
|
||||
EIGEN_DEVICE_FUNC inline const Derived& derived() const { return *static_cast<const Derived*>(this); }
|
||||
/** \returns a const reference to the derived object. */
|
||||
EIGEN_DEVICE_FUNC inline Derived& derived() { return *static_cast<Derived*>(this); }
|
||||
|
||||
/**
|
||||
* Constructs a dense matrix from \c *this. Note, this directly returns a dense matrix type,
|
||||
* not an expression.
|
||||
* \returns A dense matrix, with its entries set from the the derived object. */
|
||||
EIGEN_DEVICE_FUNC DenseMatrixType toDenseMatrix() const { return derived(); }
|
||||
|
||||
/** Determinant vanishes */
|
||||
EIGEN_DEVICE_FUNC constexpr Scalar determinant() const { return 0; }
|
||||
|
||||
/** A.transpose() = -A */
|
||||
EIGEN_DEVICE_FUNC PlainObject transpose() const { return (-vector()).asSkewSymmetric(); }
|
||||
|
||||
/** \returns the exponential of this matrix using Rodrigues’ formula */
|
||||
EIGEN_DEVICE_FUNC DenseMatrixType exponential() const {
|
||||
DenseMatrixType retVal = DenseMatrixType::Identity();
|
||||
const SkewSymmetricVectorType& v = vector();
|
||||
if (v.isZero()) {
|
||||
return retVal;
|
||||
}
|
||||
const Scalar norm2 = v.squaredNorm();
|
||||
const Scalar norm = numext::sqrt(norm2);
|
||||
retVal += ((((1 - numext::cos(norm)) / norm2) * derived()) * derived()) +
|
||||
(numext::sin(norm) / norm) * derived().toDenseMatrix();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/** \returns a reference to the derived object's vector of coefficients. */
|
||||
EIGEN_DEVICE_FUNC inline const SkewSymmetricVectorType& vector() const { return derived().vector(); }
|
||||
/** \returns a const reference to the derived object's vector of coefficients. */
|
||||
EIGEN_DEVICE_FUNC inline SkewSymmetricVectorType& vector() { return derived().vector(); }
|
||||
|
||||
/** \returns the number of rows. */
|
||||
EIGEN_DEVICE_FUNC constexpr Index rows() const { return 3; }
|
||||
/** \returns the number of columns. */
|
||||
EIGEN_DEVICE_FUNC constexpr Index cols() const { return 3; }
|
||||
|
||||
/** \returns the matrix product of \c *this by the dense matrix, \a matrix */
|
||||
template <typename MatrixDerived>
|
||||
EIGEN_DEVICE_FUNC Product<Derived, MatrixDerived, LazyProduct> operator*(
|
||||
const MatrixBase<MatrixDerived>& matrix) const {
|
||||
return Product<Derived, MatrixDerived, LazyProduct>(derived(), matrix.derived());
|
||||
}
|
||||
|
||||
/** \returns the matrix product of \c *this by the skew symmetric matrix, \a matrix */
|
||||
template <typename MatrixDerived>
|
||||
EIGEN_DEVICE_FUNC Product<Derived, MatrixDerived, LazyProduct> operator*(
|
||||
const SkewSymmetricBase<MatrixDerived>& matrix) const {
|
||||
return Product<Derived, MatrixDerived, LazyProduct>(derived(), matrix.derived());
|
||||
}
|
||||
|
||||
template <typename OtherDerived>
|
||||
using SkewSymmetricProductReturnType = SkewSymmetricWrapper<const EIGEN_CWISE_BINARY_RETURN_TYPE(
|
||||
SkewSymmetricVectorType, typename OtherDerived::SkewSymmetricVectorType, product)>;
|
||||
|
||||
/** \returns the wedge product of \c *this by the skew symmetric matrix \a other
|
||||
* A wedge B = AB - BA */
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC SkewSymmetricProductReturnType<OtherDerived> wedge(
|
||||
const SkewSymmetricBase<OtherDerived>& other) const {
|
||||
return vector().cross(other.vector()).asSkewSymmetric();
|
||||
}
|
||||
|
||||
using SkewSymmetricScaleReturnType =
|
||||
SkewSymmetricWrapper<const EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(SkewSymmetricVectorType, Scalar, product)>;
|
||||
|
||||
/** \returns the product of \c *this by the scalar \a scalar */
|
||||
EIGEN_DEVICE_FUNC inline SkewSymmetricScaleReturnType operator*(const Scalar& scalar) const {
|
||||
return (vector() * scalar).asSkewSymmetric();
|
||||
}
|
||||
|
||||
using ScaleSkewSymmetricReturnType =
|
||||
SkewSymmetricWrapper<const EIGEN_SCALAR_BINARYOP_EXPR_RETURN_TYPE(Scalar, SkewSymmetricVectorType, product)>;
|
||||
|
||||
/** \returns the product of a scalar and the skew symmetric matrix \a other */
|
||||
EIGEN_DEVICE_FUNC friend inline ScaleSkewSymmetricReturnType operator*(const Scalar& scalar,
|
||||
const SkewSymmetricBase& other) {
|
||||
return (scalar * other.vector()).asSkewSymmetric();
|
||||
}
|
||||
|
||||
template <typename OtherDerived>
|
||||
using SkewSymmetricSumReturnType = SkewSymmetricWrapper<const EIGEN_CWISE_BINARY_RETURN_TYPE(
|
||||
SkewSymmetricVectorType, typename OtherDerived::SkewSymmetricVectorType, sum)>;
|
||||
|
||||
/** \returns the sum of \c *this and the skew symmetric matrix \a other */
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC inline SkewSymmetricSumReturnType<OtherDerived> operator+(
|
||||
const SkewSymmetricBase<OtherDerived>& other) const {
|
||||
return (vector() + other.vector()).asSkewSymmetric();
|
||||
}
|
||||
|
||||
template <typename OtherDerived>
|
||||
using SkewSymmetricDifferenceReturnType = SkewSymmetricWrapper<const EIGEN_CWISE_BINARY_RETURN_TYPE(
|
||||
SkewSymmetricVectorType, typename OtherDerived::SkewSymmetricVectorType, difference)>;
|
||||
|
||||
/** \returns the difference of \c *this and the skew symmetric matrix \a other */
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC inline SkewSymmetricDifferenceReturnType<OtherDerived> operator-(
|
||||
const SkewSymmetricBase<OtherDerived>& other) const {
|
||||
return (vector() - other.vector()).asSkewSymmetric();
|
||||
}
|
||||
};
|
||||
|
||||
/** \class SkewSymmetricMatrix3
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* \brief Represents a 3x3 skew symmetric matrix with its storage
|
||||
*
|
||||
* \tparam Scalar_ the type of coefficients
|
||||
*
|
||||
* \sa class SkewSymmetricBase, class SkewSymmetricWrapper
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
template <typename Scalar_>
|
||||
struct traits<SkewSymmetricMatrix3<Scalar_>> : traits<Matrix<Scalar_, 3, 3, 0, 3, 3>> {
|
||||
typedef Matrix<Scalar_, 3, 1, 0, 3, 1> SkewSymmetricVectorType;
|
||||
typedef SkewSymmetricShape StorageKind;
|
||||
enum { Flags = LvalueBit | NoPreferredStorageOrderBit | NestByRefBit };
|
||||
};
|
||||
} // namespace internal
|
||||
template <typename Scalar_>
|
||||
class SkewSymmetricMatrix3 : public SkewSymmetricBase<SkewSymmetricMatrix3<Scalar_>> {
|
||||
public:
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
typedef typename internal::traits<SkewSymmetricMatrix3>::SkewSymmetricVectorType SkewSymmetricVectorType;
|
||||
typedef const SkewSymmetricMatrix3& Nested;
|
||||
typedef Scalar_ Scalar;
|
||||
typedef typename internal::traits<SkewSymmetricMatrix3>::StorageKind StorageKind;
|
||||
typedef typename internal::traits<SkewSymmetricMatrix3>::StorageIndex StorageIndex;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
SkewSymmetricVectorType m_vector;
|
||||
|
||||
public:
|
||||
/** const version of vector(). */
|
||||
EIGEN_DEVICE_FUNC inline const SkewSymmetricVectorType& vector() const { return m_vector; }
|
||||
/** \returns a reference to the stored vector of coefficients. */
|
||||
EIGEN_DEVICE_FUNC inline SkewSymmetricVectorType& vector() { return m_vector; }
|
||||
|
||||
/** Default constructor without initialization */
|
||||
EIGEN_DEVICE_FUNC inline SkewSymmetricMatrix3() {}
|
||||
|
||||
/** Constructor from three scalars */
|
||||
EIGEN_DEVICE_FUNC inline SkewSymmetricMatrix3(const Scalar& x, const Scalar& y, const Scalar& z)
|
||||
: m_vector(x, y, z) {}
|
||||
|
||||
/** \brief Constructs a SkewSymmetricMatrix3 from an r-value vector type */
|
||||
EIGEN_DEVICE_FUNC explicit inline SkewSymmetricMatrix3(SkewSymmetricVectorType&& vec) : m_vector(std::move(vec)) {}
|
||||
|
||||
/** generic constructor from expression of the coefficients */
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC explicit inline SkewSymmetricMatrix3(const MatrixBase<OtherDerived>& other) : m_vector(other) {}
|
||||
|
||||
/** Copy constructor. */
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC inline SkewSymmetricMatrix3(const SkewSymmetricBase<OtherDerived>& other)
|
||||
: m_vector(other.vector()) {}
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** copy constructor. prevent a default copy constructor from hiding the other templated constructor */
|
||||
inline SkewSymmetricMatrix3(const SkewSymmetricMatrix3& other) : m_vector(other.vector()) {}
|
||||
#endif
|
||||
|
||||
/** Copy operator. */
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC SkewSymmetricMatrix3& operator=(const SkewSymmetricBase<OtherDerived>& other) {
|
||||
m_vector = other.vector();
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** This is a special case of the templated operator=. Its purpose is to
|
||||
* prevent a default operator= from hiding the templated operator=.
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC SkewSymmetricMatrix3& operator=(const SkewSymmetricMatrix3& other) {
|
||||
m_vector = other.vector();
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef SkewSymmetricWrapper<const CwiseNullaryOp<internal::scalar_constant_op<Scalar>, SkewSymmetricVectorType>>
|
||||
InitializeReturnType;
|
||||
|
||||
/** Initializes a skew symmetric matrix with coefficients set to zero */
|
||||
EIGEN_DEVICE_FUNC static InitializeReturnType Zero() { return SkewSymmetricVectorType::Zero().asSkewSymmetric(); }
|
||||
|
||||
/** Sets all coefficients to zero. */
|
||||
EIGEN_DEVICE_FUNC inline void setZero() { m_vector.setZero(); }
|
||||
};
|
||||
|
||||
/** \class SkewSymmetricWrapper
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* \brief Expression of a skew symmetric matrix
|
||||
*
|
||||
* \tparam SkewSymmetricVectorType_ the type of the vector of coefficients
|
||||
*
|
||||
* This class is an expression of a skew symmetric matrix, but not storing its own vector of coefficients,
|
||||
* instead wrapping an existing vector expression. It is the return type of MatrixBase::asSkewSymmetric()
|
||||
* and most of the time this is the only way that it is used.
|
||||
*
|
||||
* \sa class SkewSymmetricMatrix3, class SkewSymmetricBase, MatrixBase::asSkewSymmetric()
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
template <typename SkewSymmetricVectorType_>
|
||||
struct traits<SkewSymmetricWrapper<SkewSymmetricVectorType_>> {
|
||||
typedef SkewSymmetricVectorType_ SkewSymmetricVectorType;
|
||||
typedef typename SkewSymmetricVectorType::Scalar Scalar;
|
||||
typedef typename SkewSymmetricVectorType::StorageIndex StorageIndex;
|
||||
typedef SkewSymmetricShape StorageKind;
|
||||
typedef typename traits<SkewSymmetricVectorType>::XprKind XprKind;
|
||||
enum {
|
||||
RowsAtCompileTime = SkewSymmetricVectorType::SizeAtCompileTime,
|
||||
ColsAtCompileTime = SkewSymmetricVectorType::SizeAtCompileTime,
|
||||
MaxRowsAtCompileTime = SkewSymmetricVectorType::MaxSizeAtCompileTime,
|
||||
MaxColsAtCompileTime = SkewSymmetricVectorType::MaxSizeAtCompileTime,
|
||||
Flags = (traits<SkewSymmetricVectorType>::Flags & LvalueBit) | NoPreferredStorageOrderBit
|
||||
};
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
template <typename SkewSymmetricVectorType_>
|
||||
class SkewSymmetricWrapper : public SkewSymmetricBase<SkewSymmetricWrapper<SkewSymmetricVectorType_>>,
|
||||
internal::no_assignment_operator {
|
||||
public:
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
typedef SkewSymmetricVectorType_ SkewSymmetricVectorType;
|
||||
typedef SkewSymmetricWrapper Nested;
|
||||
#endif
|
||||
|
||||
/** Constructor from expression of coefficients to wrap. */
|
||||
EIGEN_DEVICE_FUNC explicit inline SkewSymmetricWrapper(SkewSymmetricVectorType& a_vector) : m_vector(a_vector) {}
|
||||
|
||||
/** \returns a const reference to the wrapped expression of coefficients. */
|
||||
EIGEN_DEVICE_FUNC const SkewSymmetricVectorType& vector() const { return m_vector; }
|
||||
|
||||
protected:
|
||||
typename SkewSymmetricVectorType::Nested m_vector;
|
||||
};
|
||||
|
||||
/** \returns a pseudo-expression of a skew symmetric matrix with *this as vector of coefficients
|
||||
*
|
||||
* \only_for_vectors
|
||||
*
|
||||
* \sa class SkewSymmetricWrapper, class SkewSymmetricMatrix3, vector(), isSkewSymmetric()
|
||||
**/
|
||||
template <typename Derived>
|
||||
EIGEN_DEVICE_FUNC inline const SkewSymmetricWrapper<const Derived> MatrixBase<Derived>::asSkewSymmetric() const {
|
||||
return SkewSymmetricWrapper<const Derived>(derived());
|
||||
}
|
||||
|
||||
/** \returns true if *this is approximately equal to a skew symmetric matrix,
|
||||
* within the precision given by \a prec.
|
||||
*/
|
||||
template <typename Derived>
|
||||
bool MatrixBase<Derived>::isSkewSymmetric(const RealScalar& prec) const {
|
||||
if (cols() != rows()) return false;
|
||||
return (this->transpose() + *this).isZero(prec);
|
||||
}
|
||||
|
||||
/** \returns the matrix product of \c *this by the skew symmetric matrix \a skew.
|
||||
*/
|
||||
template <typename Derived>
|
||||
template <typename SkewDerived>
|
||||
EIGEN_DEVICE_FUNC inline const Product<Derived, SkewDerived, LazyProduct> MatrixBase<Derived>::operator*(
|
||||
const SkewSymmetricBase<SkewDerived>& skew) const {
|
||||
return Product<Derived, SkewDerived, LazyProduct>(derived(), skew.derived());
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <>
|
||||
struct storage_kind_to_shape<SkewSymmetricShape> {
|
||||
typedef SkewSymmetricShape Shape;
|
||||
};
|
||||
|
||||
struct SkewSymmetric2Dense {};
|
||||
|
||||
template <>
|
||||
struct AssignmentKind<DenseShape, SkewSymmetricShape> {
|
||||
typedef SkewSymmetric2Dense Kind;
|
||||
};
|
||||
|
||||
// SkewSymmetric matrix to Dense assignment
|
||||
template <typename DstXprType, typename SrcXprType, typename Functor>
|
||||
struct Assignment<DstXprType, SrcXprType, Functor, SkewSymmetric2Dense> {
|
||||
EIGEN_DEVICE_FUNC static void run(
|
||||
DstXprType& dst, const SrcXprType& src,
|
||||
const internal::assign_op<typename DstXprType::Scalar, typename SrcXprType::Scalar>& /*func*/) {
|
||||
if ((dst.rows() != 3) || (dst.cols() != 3)) {
|
||||
dst.resize(3, 3);
|
||||
}
|
||||
dst.diagonal().setZero();
|
||||
const typename SrcXprType::SkewSymmetricVectorType v = src.vector();
|
||||
dst(0, 1) = -v(2);
|
||||
dst(1, 0) = v(2);
|
||||
dst(0, 2) = v(1);
|
||||
dst(2, 0) = -v(1);
|
||||
dst(1, 2) = -v(0);
|
||||
dst(2, 1) = v(0);
|
||||
}
|
||||
EIGEN_DEVICE_FUNC static void run(
|
||||
DstXprType& dst, const SrcXprType& src,
|
||||
const internal::add_assign_op<typename DstXprType::Scalar, typename SrcXprType::Scalar>& /*func*/) {
|
||||
dst.vector() += src.vector();
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC static void run(
|
||||
DstXprType& dst, const SrcXprType& src,
|
||||
const internal::sub_assign_op<typename DstXprType::Scalar, typename SrcXprType::Scalar>& /*func*/) {
|
||||
dst.vector() -= src.vector();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_SKEWSYMMETRICMATRIX3_H
|
||||
@@ -0,0 +1,353 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2025 Charlie Schlosser <cs.schlosser@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_REDUCTIONS_AVX_H
|
||||
#define EIGEN_REDUCTIONS_AVX_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "../../InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet8i -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int predux(const Packet8i& a) {
|
||||
Packet4i lo = _mm256_castsi256_si128(a);
|
||||
Packet4i hi = _mm256_extractf128_si256(a, 1);
|
||||
return predux(padd(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int predux_mul(const Packet8i& a) {
|
||||
Packet4i lo = _mm256_castsi256_si128(a);
|
||||
Packet4i hi = _mm256_extractf128_si256(a, 1);
|
||||
return predux_mul(pmul(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int predux_min(const Packet8i& a) {
|
||||
Packet4i lo = _mm256_castsi256_si128(a);
|
||||
Packet4i hi = _mm256_extractf128_si256(a, 1);
|
||||
return predux_min(pmin(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int predux_max(const Packet8i& a) {
|
||||
Packet4i lo = _mm256_castsi256_si128(a);
|
||||
Packet4i hi = _mm256_extractf128_si256(a, 1);
|
||||
return predux_max(pmax(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet8i& a) {
|
||||
#ifdef EIGEN_VECTORIZE_AVX2
|
||||
return _mm256_movemask_epi8(a) != 0x0;
|
||||
#else
|
||||
return _mm256_movemask_ps(_mm256_castsi256_ps(a)) != 0x0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet8ui -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE uint32_t predux(const Packet8ui& a) {
|
||||
Packet4ui lo = _mm256_castsi256_si128(a);
|
||||
Packet4ui hi = _mm256_extractf128_si256(a, 1);
|
||||
return predux(padd(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE uint32_t predux_mul(const Packet8ui& a) {
|
||||
Packet4ui lo = _mm256_castsi256_si128(a);
|
||||
Packet4ui hi = _mm256_extractf128_si256(a, 1);
|
||||
return predux_mul(pmul(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE uint32_t predux_min(const Packet8ui& a) {
|
||||
Packet4ui lo = _mm256_castsi256_si128(a);
|
||||
Packet4ui hi = _mm256_extractf128_si256(a, 1);
|
||||
return predux_min(pmin(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE uint32_t predux_max(const Packet8ui& a) {
|
||||
Packet4ui lo = _mm256_castsi256_si128(a);
|
||||
Packet4ui hi = _mm256_extractf128_si256(a, 1);
|
||||
return predux_max(pmax(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet8ui& a) {
|
||||
#ifdef EIGEN_VECTORIZE_AVX2
|
||||
return _mm256_movemask_epi8(a) != 0x0;
|
||||
#else
|
||||
return _mm256_movemask_ps(_mm256_castsi256_ps(a)) != 0x0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef EIGEN_VECTORIZE_AVX2
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet4l -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int64_t predux(const Packet4l& a) {
|
||||
Packet2l lo = _mm256_castsi256_si128(a);
|
||||
Packet2l hi = _mm256_extractf128_si256(a, 1);
|
||||
return predux(padd(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet4l& a) {
|
||||
return _mm256_movemask_pd(_mm256_castsi256_pd(a)) != 0x0;
|
||||
}
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet4ul -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE uint64_t predux(const Packet4ul& a) {
|
||||
return static_cast<uint64_t>(predux(Packet4l(a)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet4ul& a) {
|
||||
return _mm256_movemask_pd(_mm256_castsi256_pd(a)) != 0x0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet8f -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux(const Packet8f& a) {
|
||||
Packet4f lo = _mm256_castps256_ps128(a);
|
||||
Packet4f hi = _mm256_extractf128_ps(a, 1);
|
||||
return predux(padd(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_mul(const Packet8f& a) {
|
||||
Packet4f lo = _mm256_castps256_ps128(a);
|
||||
Packet4f hi = _mm256_extractf128_ps(a, 1);
|
||||
return predux_mul(pmul(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_min(const Packet8f& a) {
|
||||
Packet4f lo = _mm256_castps256_ps128(a);
|
||||
Packet4f hi = _mm256_extractf128_ps(a, 1);
|
||||
return predux_min(pmin(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_min<PropagateNumbers>(const Packet8f& a) {
|
||||
Packet4f lo = _mm256_castps256_ps128(a);
|
||||
Packet4f hi = _mm256_extractf128_ps(a, 1);
|
||||
return predux_min<PropagateNumbers>(pmin<PropagateNumbers>(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_min<PropagateNaN>(const Packet8f& a) {
|
||||
Packet4f lo = _mm256_castps256_ps128(a);
|
||||
Packet4f hi = _mm256_extractf128_ps(a, 1);
|
||||
return predux_min<PropagateNaN>(pmin<PropagateNaN>(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_max(const Packet8f& a) {
|
||||
Packet4f lo = _mm256_castps256_ps128(a);
|
||||
Packet4f hi = _mm256_extractf128_ps(a, 1);
|
||||
return predux_max(pmax(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_max<PropagateNumbers>(const Packet8f& a) {
|
||||
Packet4f lo = _mm256_castps256_ps128(a);
|
||||
Packet4f hi = _mm256_extractf128_ps(a, 1);
|
||||
return predux_max<PropagateNumbers>(pmax<PropagateNumbers>(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_max<PropagateNaN>(const Packet8f& a) {
|
||||
Packet4f lo = _mm256_castps256_ps128(a);
|
||||
Packet4f hi = _mm256_extractf128_ps(a, 1);
|
||||
return predux_max<PropagateNaN>(pmax<PropagateNaN>(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet8f& a) {
|
||||
return _mm256_movemask_ps(a) != 0x0;
|
||||
}
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet4d -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux(const Packet4d& a) {
|
||||
Packet2d lo = _mm256_castpd256_pd128(a);
|
||||
Packet2d hi = _mm256_extractf128_pd(a, 1);
|
||||
return predux(padd(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_mul(const Packet4d& a) {
|
||||
Packet2d lo = _mm256_castpd256_pd128(a);
|
||||
Packet2d hi = _mm256_extractf128_pd(a, 1);
|
||||
return predux_mul(pmul(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_min(const Packet4d& a) {
|
||||
Packet2d lo = _mm256_castpd256_pd128(a);
|
||||
Packet2d hi = _mm256_extractf128_pd(a, 1);
|
||||
return predux_min(pmin(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_min<PropagateNumbers>(const Packet4d& a) {
|
||||
Packet2d lo = _mm256_castpd256_pd128(a);
|
||||
Packet2d hi = _mm256_extractf128_pd(a, 1);
|
||||
return predux_min<PropagateNumbers>(pmin<PropagateNumbers>(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_min<PropagateNaN>(const Packet4d& a) {
|
||||
Packet2d lo = _mm256_castpd256_pd128(a);
|
||||
Packet2d hi = _mm256_extractf128_pd(a, 1);
|
||||
return predux_min<PropagateNaN>(pmin<PropagateNaN>(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_max(const Packet4d& a) {
|
||||
Packet2d lo = _mm256_castpd256_pd128(a);
|
||||
Packet2d hi = _mm256_extractf128_pd(a, 1);
|
||||
return predux_max(pmax(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_max<PropagateNumbers>(const Packet4d& a) {
|
||||
Packet2d lo = _mm256_castpd256_pd128(a);
|
||||
Packet2d hi = _mm256_extractf128_pd(a, 1);
|
||||
return predux_max<PropagateNumbers>(pmax<PropagateNumbers>(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_max<PropagateNaN>(const Packet4d& a) {
|
||||
Packet2d lo = _mm256_castpd256_pd128(a);
|
||||
Packet2d hi = _mm256_extractf128_pd(a, 1);
|
||||
return predux_max<PropagateNaN>(pmax<PropagateNaN>(lo, hi));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet4d& a) {
|
||||
return _mm256_movemask_pd(a) != 0x0;
|
||||
}
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet8h -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
#ifndef EIGEN_VECTORIZE_AVX512FP16
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE half predux(const Packet8h& a) {
|
||||
return static_cast<half>(predux(half2float(a)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE half predux_mul(const Packet8h& a) {
|
||||
return static_cast<half>(predux_mul(half2float(a)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE half predux_min(const Packet8h& a) {
|
||||
return static_cast<half>(predux_min(half2float(a)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE half predux_min<PropagateNumbers>(const Packet8h& a) {
|
||||
return static_cast<half>(predux_min<PropagateNumbers>(half2float(a)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE half predux_min<PropagateNaN>(const Packet8h& a) {
|
||||
return static_cast<half>(predux_min<PropagateNaN>(half2float(a)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE half predux_max(const Packet8h& a) {
|
||||
return static_cast<half>(predux_max(half2float(a)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE half predux_max<PropagateNumbers>(const Packet8h& a) {
|
||||
return static_cast<half>(predux_max<PropagateNumbers>(half2float(a)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE half predux_max<PropagateNaN>(const Packet8h& a) {
|
||||
return static_cast<half>(predux_max<PropagateNaN>(half2float(a)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet8h& a) {
|
||||
return _mm_movemask_epi8(a) != 0;
|
||||
}
|
||||
#endif // EIGEN_VECTORIZE_AVX512FP16
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet8bf -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bfloat16 predux(const Packet8bf& a) {
|
||||
return static_cast<bfloat16>(predux<Packet8f>(Bf16ToF32(a)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bfloat16 predux_mul(const Packet8bf& a) {
|
||||
return static_cast<bfloat16>(predux_mul<Packet8f>(Bf16ToF32(a)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bfloat16 predux_min(const Packet8bf& a) {
|
||||
return static_cast<bfloat16>(predux_min(Bf16ToF32(a)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bfloat16 predux_min<PropagateNumbers>(const Packet8bf& a) {
|
||||
return static_cast<bfloat16>(predux_min<PropagateNumbers>(Bf16ToF32(a)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bfloat16 predux_min<PropagateNaN>(const Packet8bf& a) {
|
||||
return static_cast<bfloat16>(predux_min<PropagateNaN>(Bf16ToF32(a)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bfloat16 predux_max(const Packet8bf& a) {
|
||||
return static_cast<bfloat16>(predux_max<Packet8f>(Bf16ToF32(a)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bfloat16 predux_max<PropagateNumbers>(const Packet8bf& a) {
|
||||
return static_cast<bfloat16>(predux_max<PropagateNumbers>(Bf16ToF32(a)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bfloat16 predux_max<PropagateNaN>(const Packet8bf& a) {
|
||||
return static_cast<bfloat16>(predux_max<PropagateNaN>(Bf16ToF32(a)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet8bf& a) {
|
||||
return _mm_movemask_epi8(a) != 0;
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_REDUCTIONS_AVX_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,75 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2025 The Eigen Authors.
|
||||
//
|
||||
// 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_MATH_FUNCTIONS_FP16_AVX512_H
|
||||
#define EIGEN_MATH_FUNCTIONS_FP16_AVX512_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "../../InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
namespace internal {
|
||||
|
||||
EIGEN_STRONG_INLINE Packet32h combine2Packet16h(const Packet16h& a, const Packet16h& b) {
|
||||
__m512i result = _mm512_castsi256_si512(_mm256_castph_si256(a));
|
||||
result = _mm512_inserti64x4(result, _mm256_castph_si256(b), 1);
|
||||
return _mm512_castsi512_ph(result);
|
||||
}
|
||||
|
||||
EIGEN_STRONG_INLINE void extract2Packet16h(const Packet32h& x, Packet16h& a, Packet16h& b) {
|
||||
a = _mm256_castsi256_ph(_mm512_castsi512_si256(_mm512_castph_si512(x)));
|
||||
b = _mm256_castsi256_ph(_mm512_extracti64x4_epi64(_mm512_castph_si512(x), 1));
|
||||
}
|
||||
|
||||
#define _EIGEN_GENERATE_FP16_MATH_FUNCTION(func) \
|
||||
template <> \
|
||||
EIGEN_STRONG_INLINE Packet8h func<Packet8h>(const Packet8h& a) { \
|
||||
return float2half(func(half2float(a))); \
|
||||
} \
|
||||
\
|
||||
template <> \
|
||||
EIGEN_STRONG_INLINE Packet16h func<Packet16h>(const Packet16h& a) { \
|
||||
return float2half(func(half2float(a))); \
|
||||
} \
|
||||
\
|
||||
template <> \
|
||||
EIGEN_STRONG_INLINE Packet32h func<Packet32h>(const Packet32h& a) { \
|
||||
Packet16h low; \
|
||||
Packet16h high; \
|
||||
extract2Packet16h(a, low, high); \
|
||||
return combine2Packet16h(func(low), func(high)); \
|
||||
}
|
||||
|
||||
_EIGEN_GENERATE_FP16_MATH_FUNCTION(psin)
|
||||
_EIGEN_GENERATE_FP16_MATH_FUNCTION(pcos)
|
||||
_EIGEN_GENERATE_FP16_MATH_FUNCTION(plog)
|
||||
_EIGEN_GENERATE_FP16_MATH_FUNCTION(plog2)
|
||||
_EIGEN_GENERATE_FP16_MATH_FUNCTION(plog1p)
|
||||
_EIGEN_GENERATE_FP16_MATH_FUNCTION(pexp)
|
||||
_EIGEN_GENERATE_FP16_MATH_FUNCTION(pexpm1)
|
||||
_EIGEN_GENERATE_FP16_MATH_FUNCTION(pexp2)
|
||||
_EIGEN_GENERATE_FP16_MATH_FUNCTION(ptanh)
|
||||
#undef _EIGEN_GENERATE_FP16_MATH_FUNCTION
|
||||
|
||||
// pfrexp
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet32h pfrexp<Packet32h>(const Packet32h& a, Packet32h& exponent) {
|
||||
return pfrexp_generic(a, exponent);
|
||||
}
|
||||
|
||||
// pldexp
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet32h pldexp<Packet32h>(const Packet32h& a, const Packet32h& exponent) {
|
||||
return pldexp_generic(a, exponent);
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_MATH_FUNCTIONS_FP16_AVX512_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,297 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2025 Charlie Schlosser <cs.schlosser@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_REDUCTIONS_AVX512_H
|
||||
#define EIGEN_REDUCTIONS_AVX512_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "../../InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet16i -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int predux(const Packet16i& a) {
|
||||
return _mm512_reduce_add_epi32(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int predux_mul(const Packet16i& a) {
|
||||
return _mm512_reduce_mul_epi32(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int predux_min(const Packet16i& a) {
|
||||
return _mm512_reduce_min_epi32(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int predux_max(const Packet16i& a) {
|
||||
return _mm512_reduce_max_epi32(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet16i& a) {
|
||||
return _mm512_reduce_or_epi32(a) != 0;
|
||||
}
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet8l -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int64_t predux(const Packet8l& a) {
|
||||
return _mm512_reduce_add_epi64(a);
|
||||
}
|
||||
|
||||
#if EIGEN_COMP_MSVC
|
||||
// MSVC's _mm512_reduce_mul_epi64 is borked, at least up to and including 1939.
|
||||
// alignas(64) int64_t data[] = { 1,1,-1,-1,1,-1,-1,-1 };
|
||||
// int64_t out = _mm512_reduce_mul_epi64(_mm512_load_epi64(data));
|
||||
// produces garbage: 4294967295. It seems to happen whenever the output is supposed to be negative.
|
||||
// Fall back to a manual approach:
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int64_t predux_mul(const Packet8l& a) {
|
||||
Packet4l lane0 = _mm512_extracti64x4_epi64(a, 0);
|
||||
Packet4l lane1 = _mm512_extracti64x4_epi64(a, 1);
|
||||
return predux_mul(pmul(lane0, lane1));
|
||||
}
|
||||
#else
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int64_t predux_mul<Packet8l>(const Packet8l& a) {
|
||||
return _mm512_reduce_mul_epi64(a);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int64_t predux_min(const Packet8l& a) {
|
||||
return _mm512_reduce_min_epi64(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int64_t predux_max(const Packet8l& a) {
|
||||
return _mm512_reduce_max_epi64(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet8l& a) {
|
||||
return _mm512_reduce_or_epi64(a) != 0;
|
||||
}
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet16f -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux(const Packet16f& a) {
|
||||
return _mm512_reduce_add_ps(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_mul(const Packet16f& a) {
|
||||
return _mm512_reduce_mul_ps(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_min(const Packet16f& a) {
|
||||
return _mm512_reduce_min_ps(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_min<PropagateNumbers>(const Packet16f& a) {
|
||||
Packet8f lane0 = _mm512_extractf32x8_ps(a, 0);
|
||||
Packet8f lane1 = _mm512_extractf32x8_ps(a, 1);
|
||||
return predux_min<PropagateNumbers>(pmin<PropagateNumbers>(lane0, lane1));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_min<PropagateNaN>(const Packet16f& a) {
|
||||
Packet8f lane0 = _mm512_extractf32x8_ps(a, 0);
|
||||
Packet8f lane1 = _mm512_extractf32x8_ps(a, 1);
|
||||
return predux_min<PropagateNaN>(pmin<PropagateNaN>(lane0, lane1));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_max(const Packet16f& a) {
|
||||
return _mm512_reduce_max_ps(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_max<PropagateNumbers>(const Packet16f& a) {
|
||||
Packet8f lane0 = _mm512_extractf32x8_ps(a, 0);
|
||||
Packet8f lane1 = _mm512_extractf32x8_ps(a, 1);
|
||||
return predux_max<PropagateNumbers>(pmax<PropagateNumbers>(lane0, lane1));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_max<PropagateNaN>(const Packet16f& a) {
|
||||
Packet8f lane0 = _mm512_extractf32x8_ps(a, 0);
|
||||
Packet8f lane1 = _mm512_extractf32x8_ps(a, 1);
|
||||
return predux_max<PropagateNaN>(pmax<PropagateNaN>(lane0, lane1));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet16f& a) {
|
||||
return _mm512_reduce_or_epi32(_mm512_castps_si512(a)) != 0;
|
||||
}
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet8d -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux(const Packet8d& a) {
|
||||
return _mm512_reduce_add_pd(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_mul(const Packet8d& a) {
|
||||
return _mm512_reduce_mul_pd(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_min(const Packet8d& a) {
|
||||
return _mm512_reduce_min_pd(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_min<PropagateNumbers>(const Packet8d& a) {
|
||||
Packet4d lane0 = _mm512_extractf64x4_pd(a, 0);
|
||||
Packet4d lane1 = _mm512_extractf64x4_pd(a, 1);
|
||||
return predux_min<PropagateNumbers>(pmin<PropagateNumbers>(lane0, lane1));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_min<PropagateNaN>(const Packet8d& a) {
|
||||
Packet4d lane0 = _mm512_extractf64x4_pd(a, 0);
|
||||
Packet4d lane1 = _mm512_extractf64x4_pd(a, 1);
|
||||
return predux_min<PropagateNaN>(pmin<PropagateNaN>(lane0, lane1));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_max(const Packet8d& a) {
|
||||
return _mm512_reduce_max_pd(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_max<PropagateNumbers>(const Packet8d& a) {
|
||||
Packet4d lane0 = _mm512_extractf64x4_pd(a, 0);
|
||||
Packet4d lane1 = _mm512_extractf64x4_pd(a, 1);
|
||||
return predux_max<PropagateNumbers>(pmax<PropagateNumbers>(lane0, lane1));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_max<PropagateNaN>(const Packet8d& a) {
|
||||
Packet4d lane0 = _mm512_extractf64x4_pd(a, 0);
|
||||
Packet4d lane1 = _mm512_extractf64x4_pd(a, 1);
|
||||
return predux_max<PropagateNaN>(pmax<PropagateNaN>(lane0, lane1));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet8d& a) {
|
||||
return _mm512_reduce_or_epi64(_mm512_castpd_si512(a)) != 0;
|
||||
}
|
||||
|
||||
#ifndef EIGEN_VECTORIZE_AVX512FP16
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet16h -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE half predux(const Packet16h& from) {
|
||||
return half(predux(half2float(from)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE half predux_mul(const Packet16h& from) {
|
||||
return half(predux_mul(half2float(from)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE half predux_min(const Packet16h& from) {
|
||||
return half(predux_min(half2float(from)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE half predux_min<PropagateNumbers>(const Packet16h& from) {
|
||||
return half(predux_min<PropagateNumbers>(half2float(from)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE half predux_min<PropagateNaN>(const Packet16h& from) {
|
||||
return half(predux_min<PropagateNaN>(half2float(from)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE half predux_max(const Packet16h& from) {
|
||||
return half(predux_max(half2float(from)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE half predux_max<PropagateNumbers>(const Packet16h& from) {
|
||||
return half(predux_max<PropagateNumbers>(half2float(from)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE half predux_max<PropagateNaN>(const Packet16h& from) {
|
||||
return half(predux_max<PropagateNaN>(half2float(from)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet16h& a) {
|
||||
return predux_any<Packet8i>(a.m_val);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet16bf -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bfloat16 predux(const Packet16bf& from) {
|
||||
return static_cast<bfloat16>(predux<Packet16f>(Bf16ToF32(from)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bfloat16 predux_mul(const Packet16bf& from) {
|
||||
return static_cast<bfloat16>(predux_mul<Packet16f>(Bf16ToF32(from)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bfloat16 predux_min(const Packet16bf& from) {
|
||||
return static_cast<bfloat16>(predux_min<Packet16f>(Bf16ToF32(from)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bfloat16 predux_min<PropagateNumbers>(const Packet16bf& from) {
|
||||
return static_cast<bfloat16>(predux_min<PropagateNumbers>(Bf16ToF32(from)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bfloat16 predux_min<PropagateNaN>(const Packet16bf& from) {
|
||||
return static_cast<bfloat16>(predux_min<PropagateNaN>(Bf16ToF32(from)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bfloat16 predux_max(const Packet16bf& from) {
|
||||
return static_cast<bfloat16>(predux_max(Bf16ToF32(from)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bfloat16 predux_max<PropagateNumbers>(const Packet16bf& from) {
|
||||
return static_cast<bfloat16>(predux_max<PropagateNumbers>(Bf16ToF32(from)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bfloat16 predux_max<PropagateNaN>(const Packet16bf& from) {
|
||||
return static_cast<bfloat16>(predux_max<PropagateNaN>(Bf16ToF32(from)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet16bf& a) {
|
||||
return predux_any<Packet8i>(a.m_val);
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_REDUCTIONS_AVX512_H
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,130 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2025 The Eigen Authors.
|
||||
//
|
||||
// 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_TYPE_CASTING_FP16_AVX512_H
|
||||
#define EIGEN_TYPE_CASTING_FP16_AVX512_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "../../InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
namespace internal {
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet32s preinterpret<Packet32s, Packet32h>(const Packet32h& a) {
|
||||
return _mm512_castph_si512(a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16s preinterpret<Packet16s, Packet16h>(const Packet16h& a) {
|
||||
return _mm256_castph_si256(a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8s preinterpret<Packet8s, Packet8h>(const Packet8h& a) {
|
||||
return _mm_castph_si128(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet32h preinterpret<Packet32h, Packet32s>(const Packet32s& a) {
|
||||
return _mm512_castsi512_ph(a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16h preinterpret<Packet16h, Packet16s>(const Packet16s& a) {
|
||||
return _mm256_castsi256_ph(a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8h preinterpret<Packet8h, Packet8s>(const Packet8s& a) {
|
||||
return _mm_castsi128_ph(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16f pcast<Packet16h, Packet16f>(const Packet16h& a) {
|
||||
return half2float(a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8f pcast<Packet8h, Packet8f>(const Packet8h& a) {
|
||||
return half2float(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16h pcast<Packet16f, Packet16h>(const Packet16f& a) {
|
||||
return float2half(a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8h pcast<Packet8f, Packet8h>(const Packet8f& a) {
|
||||
return float2half(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16f pcast<Packet32h, Packet16f>(const Packet32h& a) {
|
||||
// Discard second-half of input.
|
||||
Packet16h low = _mm256_castpd_ph(_mm512_extractf64x4_pd(_mm512_castph_pd(a), 0));
|
||||
return _mm512_cvtxph_ps(low);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8f pcast<Packet16h, Packet8f>(const Packet16h& a) {
|
||||
// Discard second-half of input.
|
||||
Packet8h low = _mm_castps_ph(_mm256_extractf32x4_ps(_mm256_castph_ps(a), 0));
|
||||
return _mm256_cvtxph_ps(low);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4f pcast<Packet8h, Packet4f>(const Packet8h& a) {
|
||||
Packet8f full = _mm256_cvtxph_ps(a);
|
||||
// Discard second-half of input.
|
||||
return _mm256_extractf32x4_ps(full, 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet32h pcast<Packet16f, Packet32h>(const Packet16f& a, const Packet16f& b) {
|
||||
__m512 result = _mm512_castsi512_ps(_mm512_castsi256_si512(_mm256_castph_si256(_mm512_cvtxps_ph(a))));
|
||||
result = _mm512_insertf32x8(result, _mm256_castph_ps(_mm512_cvtxps_ph(b)), 1);
|
||||
return _mm512_castps_ph(result);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16h pcast<Packet8f, Packet16h>(const Packet8f& a, const Packet8f& b) {
|
||||
__m256 result = _mm256_castsi256_ps(_mm256_castsi128_si256(_mm_castph_si128(_mm256_cvtxps_ph(a))));
|
||||
result = _mm256_insertf32x4(result, _mm_castph_ps(_mm256_cvtxps_ph(b)), 1);
|
||||
return _mm256_castps_ph(result);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8h pcast<Packet4f, Packet8h>(const Packet4f& a, const Packet4f& b) {
|
||||
__m256 result = _mm256_castsi256_ps(_mm256_castsi128_si256(_mm_castps_si128(a)));
|
||||
result = _mm256_insertf128_ps(result, b, 1);
|
||||
return _mm256_cvtxps_ph(result);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet32s pcast<Packet32h, Packet32s>(const Packet32h& a) {
|
||||
return _mm512_cvtph_epi16(a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16s pcast<Packet16h, Packet16s>(const Packet16h& a) {
|
||||
return _mm256_cvtph_epi16(a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8s pcast<Packet8h, Packet8s>(const Packet8h& a) {
|
||||
return _mm_cvtph_epi16(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet32h pcast<Packet32s, Packet32h>(const Packet32s& a) {
|
||||
return _mm512_cvtepi16_ph(a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16h pcast<Packet16s, Packet16h>(const Packet16s& a) {
|
||||
return _mm256_cvtepi16_ph(a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8h pcast<Packet8s, Packet8h>(const Packet8s& a) {
|
||||
return _mm_cvtepi16_ph(a);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_TYPE_CASTING_FP16_AVX512_H
|
||||
@@ -0,0 +1,742 @@
|
||||
#ifndef EIGEN_MATRIX_PRODUCT_MMA_BFLOAT16_ALTIVEC_H
|
||||
#define EIGEN_MATRIX_PRODUCT_MMA_BFLOAT16_ALTIVEC_H
|
||||
|
||||
#if EIGEN_COMP_LLVM
|
||||
#define BFLOAT16_UNROLL _Pragma("unroll 8")
|
||||
#else
|
||||
#define BFLOAT16_UNROLL _Pragma("GCC unroll(8)")
|
||||
#endif
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <bool zero>
|
||||
EIGEN_ALWAYS_INLINE Packet8bf loadBfloat16(const bfloat16* indexA) {
|
||||
Packet8bf lhs1 = ploadu<Packet8bf>(indexA);
|
||||
if (zero) {
|
||||
Packet8bf lhs2 = pset1<Packet8bf>(Eigen::bfloat16(0));
|
||||
return vec_mergeh(lhs1.m_val, lhs2.m_val);
|
||||
} else {
|
||||
return lhs1;
|
||||
}
|
||||
}
|
||||
|
||||
template <bool zero>
|
||||
EIGEN_ALWAYS_INLINE Packet8bf loadRhsBfloat16(const bfloat16* blockB, Index strideB, Index i) {
|
||||
return loadBfloat16<zero>(blockB + strideB * i);
|
||||
}
|
||||
|
||||
template <Index num_acc, Index num_packets, bool zero, bool rhsExtraCols, bool lhsExtraRows, Index num_rhs,
|
||||
Index num_lhs>
|
||||
EIGEN_ALWAYS_INLINE void KLoop(const bfloat16* indexA, const bfloat16* indexB, __vector_quad (&quad_acc)[num_acc],
|
||||
Index strideB, Index k, Index offsetB, Index extra_cols, Index extra_rows) {
|
||||
Packet8bf lhs[num_lhs], rhs[num_rhs];
|
||||
|
||||
BFLOAT16_UNROLL
|
||||
for (Index i = 0; i < (num_rhs - (rhsExtraCols ? 1 : 0)); i++) {
|
||||
rhs[i] = loadRhsBfloat16<zero>(indexB + k * 4, strideB, i);
|
||||
}
|
||||
if (rhsExtraCols) {
|
||||
rhs[num_rhs - 1] = loadRhsBfloat16<zero>(indexB + k * extra_cols - offsetB, strideB, num_rhs - 1);
|
||||
}
|
||||
|
||||
indexA += k * (lhsExtraRows ? extra_rows : num_packets);
|
||||
if (num_lhs == 1) {
|
||||
lhs[0] = loadBfloat16<zero>(indexA);
|
||||
} else {
|
||||
BFLOAT16_UNROLL
|
||||
for (Index j = 0; j < num_lhs; j += 2) {
|
||||
Packet8bf lhs1 = ploadu<Packet8bf>(indexA + (j + 0) * (zero ? 4 : 8));
|
||||
if (zero) {
|
||||
Packet8bf lhs2 = pset1<Packet8bf>(Eigen::bfloat16(0));
|
||||
lhs[j + 0] = vec_mergeh(lhs1.m_val, lhs2.m_val);
|
||||
lhs[j + 1] = vec_mergel(lhs1.m_val, lhs2.m_val);
|
||||
} else {
|
||||
lhs[j + 0] = lhs1;
|
||||
lhs[j + 1] = ploadu<Packet8bf>(indexA + (j + 1) * 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BFLOAT16_UNROLL
|
||||
for (Index i = 0, x = 0; i < num_rhs; i++) {
|
||||
BFLOAT16_UNROLL
|
||||
for (Index j = 0; j < num_lhs; j++, x++) {
|
||||
__builtin_mma_xvbf16ger2pp(&(quad_acc[x]), reinterpret_cast<Packet16uc>(rhs[i].m_val),
|
||||
reinterpret_cast<Packet16uc>(lhs[j].m_val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <Index num_acc>
|
||||
EIGEN_ALWAYS_INLINE void zeroAccumulators(__vector_quad (&quad_acc)[num_acc]) {
|
||||
BFLOAT16_UNROLL
|
||||
for (Index k = 0; k < num_acc; k++) __builtin_mma_xxsetaccz(&(quad_acc[k]));
|
||||
}
|
||||
|
||||
template <Index num_acc>
|
||||
EIGEN_ALWAYS_INLINE void disassembleAccumulators(__vector_quad (&quad_acc)[num_acc], Packet4f (&acc)[num_acc][4]) {
|
||||
BFLOAT16_UNROLL
|
||||
for (Index k = 0; k < num_acc; k++) __builtin_mma_disassemble_acc((void*)acc[k], &(quad_acc[k]));
|
||||
}
|
||||
|
||||
template <Index num_acc, bool rhsExtraCols, bool lhsExtraRows, Index num_rhs, Index num_lhs>
|
||||
EIGEN_ALWAYS_INLINE void outputResults(Packet4f (&acc)[num_acc][4], Index rows, const Packet4f pAlpha, float* result,
|
||||
const Index extra_cols, Index extra_rows) {
|
||||
BFLOAT16_UNROLL
|
||||
for (Index i = 0, k = 0; i < num_rhs - (rhsExtraCols ? 1 : 0); i++, result += 4 * rows) {
|
||||
BFLOAT16_UNROLL
|
||||
for (Index j = 0; j < num_lhs; j++, k++) {
|
||||
storeResults<false, lhsExtraRows>(acc[k], rows, pAlpha, result + j * 4, extra_cols, extra_rows);
|
||||
}
|
||||
}
|
||||
if (rhsExtraCols) {
|
||||
storeResults<rhsExtraCols, lhsExtraRows>(acc[num_acc - 1], rows, pAlpha, result, extra_cols, extra_rows);
|
||||
}
|
||||
}
|
||||
|
||||
template <const Index num_acc, const Index num_packets, bool rhsExtraCols, bool lhsExtraRows, bool multiIter = false>
|
||||
EIGEN_ALWAYS_INLINE void colLoopBodyIter(Index depth, Index rows, const Packet4f pAlpha, const bfloat16* indexA,
|
||||
const bfloat16* indexB, Index strideB, Index offsetB, float* result,
|
||||
const Index extra_cols, const Index extra_rows) {
|
||||
constexpr Index num_lhs = multiIter ? (num_packets / 4) : 1;
|
||||
constexpr Index num_rhs = (num_acc + num_lhs - 1) / num_lhs;
|
||||
|
||||
for (Index offset_row = 0; offset_row < num_packets; offset_row += 4, indexA += (multiIter ? 0 : 8),
|
||||
indexB += (multiIter ? (num_rhs * strideB) : 0), result += (multiIter ? (4 * rows * num_rhs) : 4)) {
|
||||
Packet4f acc[num_acc][4];
|
||||
__vector_quad quad_acc[num_acc];
|
||||
|
||||
zeroAccumulators<num_acc>(quad_acc);
|
||||
|
||||
Index k;
|
||||
for (k = 0; k + 2 <= depth; k += 2) {
|
||||
KLoop<num_acc, num_packets, false, rhsExtraCols, lhsExtraRows, num_rhs, num_lhs>(
|
||||
indexA, indexB, quad_acc, strideB, k, offsetB, extra_cols, extra_rows);
|
||||
}
|
||||
if (depth & 1) {
|
||||
KLoop<num_acc, num_packets, true, rhsExtraCols, lhsExtraRows, num_rhs, num_lhs>(
|
||||
indexA - (multiIter ? 0 : offset_row), indexB, quad_acc, strideB, k, offsetB, extra_cols, extra_rows);
|
||||
}
|
||||
|
||||
disassembleAccumulators<num_acc>(quad_acc, acc);
|
||||
|
||||
outputResults<num_acc, rhsExtraCols, lhsExtraRows, num_rhs, num_lhs>(acc, rows, pAlpha, result, extra_cols,
|
||||
extra_rows);
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_BFLOAT16_ACC 8
|
||||
|
||||
template <const Index num_acc, const Index num_packets, bool rhsExtraCols, bool lhsExtraRows>
|
||||
void colLoopBody(Index& col, Index depth, Index cols, Index rows, const Packet4f pAlpha, const bfloat16* indexA,
|
||||
const bfloat16* indexB, Index strideB, Index offsetB, float* result) {
|
||||
constexpr Index step = (num_acc * 4); // each accumulator has 4 elements
|
||||
const Index extra_cols = (rhsExtraCols) ? (cols & 3) : 0;
|
||||
const Index extra_rows = (lhsExtraRows) ? (rows & 3) : 0;
|
||||
constexpr bool multiIters = !rhsExtraCols && (num_acc == MAX_BFLOAT16_ACC);
|
||||
constexpr bool normIters = multiIters && ((num_acc % (num_packets / 4)) == 0);
|
||||
|
||||
do {
|
||||
colLoopBodyIter<num_acc, num_packets, rhsExtraCols, lhsExtraRows, normIters>(
|
||||
depth, rows, pAlpha, indexA, indexB, strideB, offsetB, result, extra_cols, extra_rows);
|
||||
|
||||
indexB += strideB * num_acc;
|
||||
result += rows * step;
|
||||
} while (multiIters && (step <= cols - (col += step)));
|
||||
}
|
||||
|
||||
template <const Index num_acc, const Index num_packets, bool rhsExtraCols, bool lhsExtraRows>
|
||||
EIGEN_ALWAYS_INLINE void colLoopBodyExtraN(Index col, Index depth, Index cols, Index rows, const Packet4f pAlpha,
|
||||
const bfloat16* indexA, const bfloat16* blockB, Index strideB, Index offsetB,
|
||||
float* result) {
|
||||
if (MAX_BFLOAT16_ACC > num_acc) {
|
||||
colLoopBody<num_acc + (rhsExtraCols ? 1 : 0), num_packets, rhsExtraCols, lhsExtraRows>(
|
||||
col, depth, cols, rows, pAlpha, indexA, blockB, strideB, offsetB, result);
|
||||
}
|
||||
}
|
||||
|
||||
template <const Index num_packets, bool rhsExtraCols, bool lhsExtraRows>
|
||||
void colLoopBodyExtra(Index col, Index depth, Index cols, Index rows, const Packet4f pAlpha, const bfloat16* indexA,
|
||||
const bfloat16* blockB, Index strideB, Index offsetB, float* result) {
|
||||
switch ((cols - col) >> 2) {
|
||||
case 7:
|
||||
colLoopBodyExtraN<7, num_packets, rhsExtraCols, lhsExtraRows>(col, depth, cols, rows, pAlpha, indexA, blockB,
|
||||
strideB, offsetB, result);
|
||||
break;
|
||||
case 6:
|
||||
colLoopBodyExtraN<6, num_packets, rhsExtraCols, lhsExtraRows>(col, depth, cols, rows, pAlpha, indexA, blockB,
|
||||
strideB, offsetB, result);
|
||||
break;
|
||||
case 5:
|
||||
colLoopBodyExtraN<5, num_packets, rhsExtraCols, lhsExtraRows>(col, depth, cols, rows, pAlpha, indexA, blockB,
|
||||
strideB, offsetB, result);
|
||||
break;
|
||||
case 4:
|
||||
colLoopBodyExtraN<4, num_packets, rhsExtraCols, lhsExtraRows>(col, depth, cols, rows, pAlpha, indexA, blockB,
|
||||
strideB, offsetB, result);
|
||||
break;
|
||||
case 3:
|
||||
colLoopBodyExtraN<3, num_packets, rhsExtraCols, lhsExtraRows>(col, depth, cols, rows, pAlpha, indexA, blockB,
|
||||
strideB, offsetB, result);
|
||||
break;
|
||||
case 2:
|
||||
colLoopBodyExtraN<2, num_packets, rhsExtraCols, lhsExtraRows>(col, depth, cols, rows, pAlpha, indexA, blockB,
|
||||
strideB, offsetB, result);
|
||||
break;
|
||||
case 1:
|
||||
colLoopBodyExtraN<1, num_packets, rhsExtraCols, lhsExtraRows>(col, depth, cols, rows, pAlpha, indexA, blockB,
|
||||
strideB, offsetB, result);
|
||||
break;
|
||||
default:
|
||||
if (rhsExtraCols) {
|
||||
colLoopBody<1, num_packets, true, lhsExtraRows>(col, depth, cols, rows, pAlpha, indexA, blockB, strideB,
|
||||
offsetB, result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <const Index num_packets, bool lhsExtraRows = false>
|
||||
EIGEN_ALWAYS_INLINE void colLoops(Index depth, Index cols, Index rows, const Packet4f pAlpha, const bfloat16* indexA,
|
||||
const bfloat16* blockB, Index strideB, Index offsetB, float* result) {
|
||||
Index col = 0;
|
||||
if (cols >= (MAX_BFLOAT16_ACC * 4)) {
|
||||
colLoopBody<MAX_BFLOAT16_ACC, num_packets, false, lhsExtraRows>(col, depth, cols, rows, pAlpha, indexA, blockB,
|
||||
strideB, 0, result);
|
||||
blockB += (strideB >> 2) * col;
|
||||
result += rows * col;
|
||||
}
|
||||
if (cols & 3) {
|
||||
colLoopBodyExtra<num_packets, true, lhsExtraRows>(col, depth, cols, rows, pAlpha, indexA, blockB, strideB, offsetB,
|
||||
result);
|
||||
} else {
|
||||
colLoopBodyExtra<num_packets, false, lhsExtraRows>(col, depth, cols, rows, pAlpha, indexA, blockB, strideB, 0,
|
||||
result);
|
||||
}
|
||||
}
|
||||
|
||||
EIGEN_ALWAYS_INLINE Packet8bf convertF32toBF16(const float* res) {
|
||||
Packet16uc fp16[2];
|
||||
__vector_pair fp16_vp = *reinterpret_cast<__vector_pair*>(const_cast<float*>(res));
|
||||
__builtin_vsx_disassemble_pair(reinterpret_cast<void*>(fp16), &fp16_vp);
|
||||
fp16[0] = __builtin_vsx_xvcvspbf16(fp16[0]);
|
||||
fp16[1] = __builtin_vsx_xvcvspbf16(fp16[1]);
|
||||
return vec_pack(reinterpret_cast<Packet4ui>(fp16[0]), reinterpret_cast<Packet4ui>(fp16[1]));
|
||||
}
|
||||
|
||||
template <typename DataMapper, const Index size>
|
||||
EIGEN_ALWAYS_INLINE void convertArrayF32toBF16Col(float* result, Index col, Index rows, const DataMapper& res) {
|
||||
const DataMapper res2 = res.getSubMapper(0, col);
|
||||
Index row;
|
||||
float* result2 = result + col * rows;
|
||||
for (row = 0; row + 8 <= rows; row += 8, result2 += 8) {
|
||||
// get and save block
|
||||
PacketBlock<Packet8bf, size> block;
|
||||
BFLOAT16_UNROLL
|
||||
for (Index j = 0; j < size; j++) {
|
||||
block.packet[j] = convertF32toBF16(result2 + j * rows);
|
||||
}
|
||||
res2.template storePacketBlock<Packet8bf, size>(row, 0, block);
|
||||
}
|
||||
// extra rows
|
||||
if (row < rows) {
|
||||
BFLOAT16_UNROLL
|
||||
for (Index j = 0; j < size; j++) {
|
||||
Packet8bf fp16 = convertF32toBF16(result2 + j * rows);
|
||||
res2.template storePacketPartial<Packet8bf>(row, j, fp16, rows & 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <const Index size, bool non_unit_stride = false>
|
||||
EIGEN_ALWAYS_INLINE void convertPointerF32toBF16(Index& i, float* result, Index rows, bfloat16*& dst,
|
||||
Index resInc = 1) {
|
||||
constexpr Index extra = ((size < 8) ? 8 : size);
|
||||
while (i + size <= rows) {
|
||||
PacketBlock<Packet8bf, (size + 7) / 8> r32;
|
||||
r32.packet[0] = convertF32toBF16(result + i + 0);
|
||||
if (size >= 16) {
|
||||
r32.packet[1] = convertF32toBF16(result + i + 8);
|
||||
}
|
||||
if (size >= 32) {
|
||||
r32.packet[2] = convertF32toBF16(result + i + 16);
|
||||
r32.packet[3] = convertF32toBF16(result + i + 24);
|
||||
}
|
||||
storeBF16fromResult<size, non_unit_stride, 0>(dst, r32.packet[0], resInc, rows & 7);
|
||||
if (size >= 16) {
|
||||
storeBF16fromResult<size, non_unit_stride, 8>(dst, r32.packet[1], resInc);
|
||||
}
|
||||
if (size >= 32) {
|
||||
storeBF16fromResult<size, non_unit_stride, 16>(dst, r32.packet[2], resInc);
|
||||
storeBF16fromResult<size, non_unit_stride, 24>(dst, r32.packet[3], resInc);
|
||||
}
|
||||
i += extra;
|
||||
dst += extra * resInc;
|
||||
if (size != 32) break;
|
||||
}
|
||||
}
|
||||
|
||||
template <bool non_unit_stride = false>
|
||||
EIGEN_ALWAYS_INLINE void convertArrayPointerF32toBF16(float* result, Index rows, bfloat16* dst, Index resInc = 1) {
|
||||
Index i = 0;
|
||||
convertPointerF32toBF16<32, non_unit_stride>(i, result, rows, dst, resInc);
|
||||
convertPointerF32toBF16<16, non_unit_stride>(i, result, rows, dst, resInc);
|
||||
convertPointerF32toBF16<8, non_unit_stride>(i, result, rows, dst, resInc);
|
||||
convertPointerF32toBF16<1, non_unit_stride>(i, result, rows, dst, resInc);
|
||||
}
|
||||
|
||||
template <typename DataMapper>
|
||||
EIGEN_ALWAYS_INLINE void convertArrayF32toBF16(float* result, Index cols, Index rows, const DataMapper& res) {
|
||||
Index col;
|
||||
for (col = 0; col + 4 <= cols; col += 4) {
|
||||
convertArrayF32toBF16Col<DataMapper, 4>(result, col, rows, res);
|
||||
}
|
||||
// extra cols
|
||||
switch (cols - col) {
|
||||
case 1:
|
||||
convertArrayF32toBF16Col<DataMapper, 1>(result, col, rows, res);
|
||||
break;
|
||||
case 2:
|
||||
convertArrayF32toBF16Col<DataMapper, 2>(result, col, rows, res);
|
||||
break;
|
||||
case 3:
|
||||
convertArrayF32toBF16Col<DataMapper, 3>(result, col, rows, res);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <Index size>
|
||||
EIGEN_ALWAYS_INLINE void calcColLoops(const bfloat16*& indexA, Index& row, Index depth, Index cols, Index rows,
|
||||
const Packet4f pAlpha, const bfloat16* indexB, Index strideB, Index offsetA,
|
||||
Index offsetB, Index bigSuffix, float* result) {
|
||||
if ((size == 16) || (rows & size)) {
|
||||
indexA += size * offsetA;
|
||||
colLoops<size>(depth, cols, rows, pAlpha, indexA, indexB, strideB, offsetB, result + row);
|
||||
row += size;
|
||||
indexA += bigSuffix * size / 16;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DataMapper>
|
||||
void gemmMMAbfloat16(const DataMapper& res, const bfloat16* indexA, const bfloat16* indexB, Index rows, Index depth,
|
||||
Index cols, bfloat16 alpha, Index strideA, Index strideB, Index offsetA, Index offsetB) {
|
||||
float falpha = Eigen::bfloat16_impl::bfloat16_to_float(alpha);
|
||||
const Packet4f pAlpha = pset1<Packet4f>(falpha);
|
||||
ei_declare_aligned_stack_constructed_variable(float, result, cols* rows, 0);
|
||||
|
||||
convertArrayBF16toF32<DataMapper>(result, cols, rows, res);
|
||||
|
||||
if (strideA == -1) strideA = depth;
|
||||
if (strideB == -1) strideB = depth;
|
||||
// Packing is done in blocks.
|
||||
// There's 4 possible sizes of blocks
|
||||
// Blocks of 8 columns with 16 elements (8x16)
|
||||
// Blocks of 8 columns with 8 elements (8x8). This happens when there's 16 > rows >= 8
|
||||
// Blocks of 8 columns with 4 elements (8x4). This happens when there's 8 > rows >= 4
|
||||
// Blocks of 8 columns with < 4 elements. This happens when there's less than 4 remaining rows
|
||||
|
||||
// Loop for LHS standard block (8x16)
|
||||
Index bigSuffix = (2 * 8) * (strideA - offsetA);
|
||||
indexB += 4 * offsetB;
|
||||
strideB *= 4;
|
||||
offsetB *= 3;
|
||||
|
||||
Index row = 0;
|
||||
while (row + 16 <= rows) {
|
||||
calcColLoops<16>(indexA, row, depth, cols, rows, pAlpha, indexB, strideB, offsetA, offsetB, bigSuffix, result);
|
||||
}
|
||||
// LHS (8x8) block
|
||||
calcColLoops<8>(indexA, row, depth, cols, rows, pAlpha, indexB, strideB, offsetA, offsetB, bigSuffix, result);
|
||||
// LHS (8x4) block
|
||||
calcColLoops<4>(indexA, row, depth, cols, rows, pAlpha, indexB, strideB, offsetA, offsetB, bigSuffix, result);
|
||||
// extra rows
|
||||
if (rows & 3) {
|
||||
// This index is the beginning of remaining block.
|
||||
colLoops<4, true>(depth, cols, rows, pAlpha, indexA, indexB, strideB, offsetB, result + row);
|
||||
}
|
||||
|
||||
// Convert back to bfloat16
|
||||
convertArrayF32toBF16<DataMapper>(result, cols, rows, res);
|
||||
}
|
||||
|
||||
#undef MAX_BFLOAT16_ACC
|
||||
|
||||
#if !EIGEN_ALTIVEC_DISABLE_MMA
|
||||
template <Index num_acc, typename LhsMapper, bool zero>
|
||||
EIGEN_ALWAYS_INLINE void loadVecLoop(Index k, LhsMapper& lhs, Packet8bf (&a0)[num_acc], Packet8bf b1) {
|
||||
a0[k + 0] = lhs.template loadPacket<Packet8bf>(k * 4, 0);
|
||||
if (!zero) {
|
||||
b1 = lhs.template loadPacket<Packet8bf>(k * 4, 1);
|
||||
}
|
||||
if (num_acc > (k + 1)) {
|
||||
a0[k + 1] = vec_mergel(a0[k + 0].m_val, b1.m_val);
|
||||
}
|
||||
a0[k + 0] = vec_mergeh(a0[k + 0].m_val, b1.m_val);
|
||||
}
|
||||
|
||||
template <Index num_acc>
|
||||
EIGEN_ALWAYS_INLINE void multVec(__vector_quad (&quad_acc)[num_acc], Packet8bf (&a0)[num_acc], Packet8bf b0) {
|
||||
BFLOAT16_UNROLL
|
||||
for (Index k = 0; k < num_acc; k++) {
|
||||
__builtin_mma_xvbf16ger2pp(&(quad_acc[k]), reinterpret_cast<Packet16uc>(b0.m_val),
|
||||
reinterpret_cast<Packet16uc>(a0[k].m_val));
|
||||
}
|
||||
}
|
||||
|
||||
template <Index num_acc, typename LhsMapper, typename RhsMapper, bool zero, bool linear>
|
||||
EIGEN_ALWAYS_INLINE void vecColLoop(Index j, LhsMapper& lhs, RhsMapper& rhs, __vector_quad (&quad_acc)[num_acc]) {
|
||||
Packet8bf a0[num_acc];
|
||||
Packet8bf b1 = pset1<Packet8bf>(Eigen::bfloat16(0));
|
||||
Packet8bf b0 = loadColData<RhsMapper, linear>(rhs, j);
|
||||
|
||||
if (zero) {
|
||||
b0 = vec_mergeh(b0.m_val, b1.m_val);
|
||||
}
|
||||
|
||||
using LhsSubMapper = typename LhsMapper::SubMapper;
|
||||
|
||||
LhsSubMapper lhs2 = lhs.getSubMapper(0, j);
|
||||
BFLOAT16_UNROLL
|
||||
for (Index k = 0; k < num_acc; k += 2) {
|
||||
loadVecLoop<num_acc, LhsSubMapper, zero>(k, lhs2, a0, b1);
|
||||
}
|
||||
|
||||
multVec<num_acc>(quad_acc, a0, b0);
|
||||
}
|
||||
|
||||
#define MAX_BFLOAT16_VEC_ACC 8
|
||||
|
||||
template <const Index num_acc, typename LhsMapper, typename RhsMapper, bool extraRows, bool linear>
|
||||
void colVecColLoopBody(Index& row, Index cend, Index rows, LhsMapper& lhs, RhsMapper& rhs, const Packet4f pAlpha,
|
||||
float* result) {
|
||||
constexpr Index step = (num_acc * 4);
|
||||
const Index extra_rows = (extraRows) ? (rows & 3) : 0;
|
||||
constexpr bool multiIters = !extraRows && (num_acc == MAX_BFLOAT16_VEC_ACC);
|
||||
|
||||
do {
|
||||
Packet4f acc[num_acc][4];
|
||||
__vector_quad quad_acc[num_acc];
|
||||
|
||||
zeroAccumulators<num_acc>(quad_acc);
|
||||
|
||||
using LhsSubMapper = typename LhsMapper::SubMapper;
|
||||
|
||||
LhsSubMapper lhs2 = lhs.getSubMapper(row, 0);
|
||||
for (Index j = 0; j + 2 <= cend; j += 2) {
|
||||
vecColLoop<num_acc, LhsSubMapper, RhsMapper, false, linear>(j, lhs2, rhs, quad_acc);
|
||||
}
|
||||
if (cend & 1) {
|
||||
vecColLoop<num_acc, LhsSubMapper, RhsMapper, true, linear>(cend - 1, lhs2, rhs, quad_acc);
|
||||
}
|
||||
|
||||
disassembleAccumulators<num_acc>(quad_acc, acc);
|
||||
|
||||
outputVecColResults<num_acc, extraRows>(acc, result, pAlpha, extra_rows);
|
||||
|
||||
result += step;
|
||||
} while (multiIters && (step <= rows - (row += step)));
|
||||
}
|
||||
|
||||
template <const Index num_acc, typename LhsMapper, typename RhsMapper, bool extraRows, bool linear>
|
||||
EIGEN_ALWAYS_INLINE void colVecColLoopBodyExtraN(Index& row, Index cend, Index rows, LhsMapper& lhs, RhsMapper& rhs,
|
||||
const Packet4f pAlpha, float* result) {
|
||||
if (MAX_BFLOAT16_VEC_ACC > num_acc) {
|
||||
colVecColLoopBody<num_acc + (extraRows ? 1 : 0), LhsMapper, RhsMapper, extraRows, linear>(row, cend, rows, lhs, rhs,
|
||||
pAlpha, result);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename LhsMapper, typename RhsMapper, bool extraRows, bool linear>
|
||||
EIGEN_ALWAYS_INLINE void colVecColLoopBodyExtra(Index& row, Index cend, Index rows, LhsMapper& lhs, RhsMapper& rhs,
|
||||
const Packet4f pAlpha, float* result) {
|
||||
switch ((rows - row) >> 2) {
|
||||
case 7:
|
||||
colVecColLoopBodyExtraN<7, LhsMapper, RhsMapper, extraRows, linear>(row, cend, rows, lhs, rhs, pAlpha, result);
|
||||
break;
|
||||
case 6:
|
||||
colVecColLoopBodyExtraN<6, LhsMapper, RhsMapper, extraRows, linear>(row, cend, rows, lhs, rhs, pAlpha, result);
|
||||
break;
|
||||
case 5:
|
||||
colVecColLoopBodyExtraN<5, LhsMapper, RhsMapper, extraRows, linear>(row, cend, rows, lhs, rhs, pAlpha, result);
|
||||
break;
|
||||
case 4:
|
||||
colVecColLoopBodyExtraN<4, LhsMapper, RhsMapper, extraRows, linear>(row, cend, rows, lhs, rhs, pAlpha, result);
|
||||
break;
|
||||
case 3:
|
||||
colVecColLoopBodyExtraN<3, LhsMapper, RhsMapper, extraRows, linear>(row, cend, rows, lhs, rhs, pAlpha, result);
|
||||
break;
|
||||
case 2:
|
||||
colVecColLoopBodyExtraN<2, LhsMapper, RhsMapper, extraRows, linear>(row, cend, rows, lhs, rhs, pAlpha, result);
|
||||
break;
|
||||
case 1:
|
||||
colVecColLoopBodyExtraN<1, LhsMapper, RhsMapper, extraRows, linear>(row, cend, rows, lhs, rhs, pAlpha, result);
|
||||
break;
|
||||
default:
|
||||
if (extraRows) {
|
||||
colVecColLoopBody<1, LhsMapper, RhsMapper, true, linear>(row, cend, rows, lhs, rhs, pAlpha, result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename LhsMapper, typename RhsMapper, bool linear>
|
||||
EIGEN_ALWAYS_INLINE void calcVecColLoops(Index cend, Index rows, LhsMapper& lhs, RhsMapper& rhs, const Packet4f pAlpha,
|
||||
float* result) {
|
||||
Index row = 0;
|
||||
if (rows >= (MAX_BFLOAT16_VEC_ACC * 4)) {
|
||||
colVecColLoopBody<MAX_BFLOAT16_VEC_ACC, LhsMapper, RhsMapper, false, linear>(row, cend, rows, lhs, rhs, pAlpha,
|
||||
result);
|
||||
result += row;
|
||||
}
|
||||
if (rows & 3) {
|
||||
colVecColLoopBodyExtra<LhsMapper, RhsMapper, true, linear>(row, cend, rows, lhs, rhs, pAlpha, result);
|
||||
} else {
|
||||
colVecColLoopBodyExtra<LhsMapper, RhsMapper, false, linear>(row, cend, rows, lhs, rhs, pAlpha, result);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename RhsMapper, typename LhsMapper, typename = void>
|
||||
struct UseMMAStride : std::false_type {
|
||||
static EIGEN_ALWAYS_INLINE void run(Index j2, Index jend, Index rows, LhsMapper& lhs, RhsMapper& rhs, Packet4f pAlpha,
|
||||
float* result) {
|
||||
using RhsSubMapper = typename RhsMapper::SubMapper;
|
||||
|
||||
RhsSubMapper rhs2 = rhs.getSubMapper(j2, 0);
|
||||
calcVecColLoops<LhsMapper, RhsSubMapper, false>(jend - j2, rows, lhs, rhs2, pAlpha, result);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename RhsMapper, typename LhsMapper>
|
||||
struct UseMMAStride<RhsMapper, LhsMapper,
|
||||
std::enable_if_t<std::is_member_function_pointer<decltype(&RhsMapper::stride)>::value>>
|
||||
: std::true_type {
|
||||
static EIGEN_ALWAYS_INLINE void run(Index j2, Index jend, Index rows, LhsMapper& lhs, RhsMapper& rhs, Packet4f pAlpha,
|
||||
float* result) {
|
||||
using RhsSubMapper = typename RhsMapper::SubMapper;
|
||||
|
||||
RhsSubMapper rhs2 = rhs.getSubMapper(j2, 0);
|
||||
if (rhs.stride() == 1) {
|
||||
calcVecColLoops<LhsMapper, RhsSubMapper, true>(jend - j2, rows, lhs, rhs2, pAlpha, result);
|
||||
} else {
|
||||
calcVecColLoops<LhsMapper, RhsSubMapper, false>(jend - j2, rows, lhs, rhs2, pAlpha, result);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename LhsMapper, typename RhsMapper>
|
||||
void gemvMMA_bfloat16_col(Index rows, Index cols, const LhsMapper& alhs, const RhsMapper& rhs, bfloat16* res,
|
||||
Index resIncr, bfloat16 alpha) {
|
||||
EIGEN_UNUSED_VARIABLE(resIncr);
|
||||
eigen_internal_assert(resIncr == 1);
|
||||
|
||||
// The following copy tells the compiler that lhs's attributes are not modified outside this function
|
||||
// This helps GCC to generate proper code.
|
||||
LhsMapper lhs(alhs);
|
||||
RhsMapper rhs2(rhs);
|
||||
|
||||
const Index lhsStride = lhs.stride();
|
||||
|
||||
// TODO: improve the following heuristic:
|
||||
const Index block_cols = cols < 128 ? cols : (lhsStride * sizeof(bfloat16) < 16000 ? 16 : 8);
|
||||
float falpha = Eigen::bfloat16_impl::bfloat16_to_float(alpha);
|
||||
Packet4f pAlpha = pset1<Packet4f>(falpha);
|
||||
|
||||
ei_declare_aligned_stack_constructed_variable(float, result, rows, 0);
|
||||
|
||||
convertArrayPointerBF16toF32(result, 1, rows, res);
|
||||
|
||||
for (Index j2 = 0; j2 < cols; j2 += block_cols) {
|
||||
Index jend = numext::mini(j2 + block_cols, cols);
|
||||
|
||||
using LhsSubMapper = typename LhsMapper::SubMapper;
|
||||
|
||||
LhsSubMapper lhs2 = lhs.getSubMapper(0, j2);
|
||||
UseMMAStride<RhsMapper, LhsSubMapper>::run(j2, jend, rows, lhs2, rhs2, pAlpha, result);
|
||||
}
|
||||
|
||||
convertArrayPointerF32toBF16(result, rows, res);
|
||||
}
|
||||
|
||||
static Packet16uc p16uc_ELEMENT_VEC3 = {0x0c, 0x0d, 0x0e, 0x0f, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x0c, 0x0d, 0x0e, 0x0f, 0x1c, 0x1d, 0x1e, 0x1f};
|
||||
|
||||
template <Index num_acc>
|
||||
EIGEN_ALWAYS_INLINE void preduxVecResults2(Packet4f (&acc)[num_acc][4], Index k) {
|
||||
if (num_acc > (k + 1)) {
|
||||
acc[k][0] = vec_mergeh(acc[k][0], acc[k + 1][0]);
|
||||
acc[k][1] = vec_mergeo(acc[k][1], acc[k + 1][1]);
|
||||
acc[k][2] = vec_mergel(acc[k][2], acc[k + 1][2]);
|
||||
acc[k][3] = vec_perm(acc[k][3], acc[k + 1][3], p16uc_ELEMENT_VEC3);
|
||||
|
||||
acc[k][0] = (acc[k][0] + acc[k][2]) + (acc[k][1] + acc[k][3]);
|
||||
} else {
|
||||
acc[k][0] = vec_mergeh(acc[k][0], acc[k][1]);
|
||||
acc[k][0] += vec_mergel(acc[k][2], acc[k][3]);
|
||||
#ifdef _BIG_ENDIAN
|
||||
acc[k][0] += vec_sld(acc[k][0], acc[k][0], 12);
|
||||
#else
|
||||
acc[k][0] += vec_sld(acc[k][0], acc[k][0], 4);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
template <Index num_acc>
|
||||
EIGEN_ALWAYS_INLINE void preduxVecResults(Packet4f (&acc)[num_acc][4]) {
|
||||
BFLOAT16_UNROLL
|
||||
for (Index k = 0; k < num_acc; k += 4) {
|
||||
preduxVecResults2<num_acc>(acc, k + 0);
|
||||
if (num_acc > (k + 2)) {
|
||||
preduxVecResults2<num_acc>(acc, k + 2);
|
||||
acc[k + 0][0] = reinterpret_cast<Packet4f>(
|
||||
vec_mergeh(reinterpret_cast<Packet2ul>(acc[k + 0][0]), reinterpret_cast<Packet2ul>(acc[k + 2][0])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <Index num_acc, typename LhsMapper, typename RhsMapper, bool extra>
|
||||
EIGEN_ALWAYS_INLINE void multVecLoop(__vector_quad (&quad_acc)[num_acc], const LhsMapper& lhs, RhsMapper& rhs, Index j,
|
||||
Index extra_cols) {
|
||||
Packet8bf a0[num_acc], b0;
|
||||
|
||||
if (extra) {
|
||||
b0 = rhs.template loadPacketPartial<Packet8bf>(j, extra_cols);
|
||||
} else {
|
||||
b0 = rhs.template loadPacket<Packet8bf>(j);
|
||||
}
|
||||
|
||||
const LhsMapper lhs2 = lhs.getSubMapper(0, j);
|
||||
BFLOAT16_UNROLL
|
||||
for (Index k = 0; k < num_acc; k++) {
|
||||
if (extra) {
|
||||
a0[k] = lhs2.template loadPacketPartial<Packet8bf>(k, 0, extra_cols);
|
||||
} else {
|
||||
a0[k] = lhs2.template loadPacket<Packet8bf>(k, 0);
|
||||
}
|
||||
}
|
||||
|
||||
multVec<num_acc>(quad_acc, a0, b0);
|
||||
}
|
||||
|
||||
template <Index num_acc, typename LhsMapper, typename RhsMapper>
|
||||
EIGEN_ALWAYS_INLINE void vecLoop(Index cols, const LhsMapper& lhs, RhsMapper& rhs, __vector_quad (&quad_acc)[num_acc],
|
||||
Index extra_cols) {
|
||||
Index j = 0;
|
||||
for (; j + 8 <= cols; j += 8) {
|
||||
multVecLoop<num_acc, LhsMapper, RhsMapper, false>(quad_acc, lhs, rhs, j, extra_cols);
|
||||
}
|
||||
|
||||
if (extra_cols) {
|
||||
multVecLoop<num_acc, LhsMapper, RhsMapper, true>(quad_acc, lhs, rhs, j, extra_cols);
|
||||
}
|
||||
}
|
||||
|
||||
template <const Index num_acc, typename LhsMapper, typename RhsMapper>
|
||||
void colVecLoopBody(Index& row, Index cols, Index rows, LhsMapper& lhs, RhsMapper& rhs, const Packet4f pAlpha,
|
||||
float* result) {
|
||||
constexpr bool multiIters = (num_acc == MAX_BFLOAT16_VEC_ACC);
|
||||
const Index extra_cols = (cols & 7);
|
||||
|
||||
do {
|
||||
Packet4f acc[num_acc][4];
|
||||
__vector_quad quad_acc[num_acc];
|
||||
|
||||
zeroAccumulators<num_acc>(quad_acc);
|
||||
|
||||
const LhsMapper lhs2 = lhs.getSubMapper(row, 0);
|
||||
vecLoop<num_acc, LhsMapper, RhsMapper>(cols, lhs2, rhs, quad_acc, extra_cols);
|
||||
|
||||
disassembleAccumulators<num_acc>(quad_acc, acc);
|
||||
|
||||
preduxVecResults<num_acc>(acc);
|
||||
|
||||
outputVecResults<num_acc>(acc, result, pAlpha);
|
||||
|
||||
result += num_acc;
|
||||
} while (multiIters && (num_acc <= rows - (row += num_acc)));
|
||||
}
|
||||
|
||||
template <const Index num_acc, typename LhsMapper, typename RhsMapper>
|
||||
EIGEN_ALWAYS_INLINE void colVecLoopBodyExtraN(Index& row, Index cols, Index rows, LhsMapper& lhs, RhsMapper& rhs,
|
||||
const Packet4f pAlpha, float* result) {
|
||||
if (MAX_BFLOAT16_VEC_ACC > num_acc) {
|
||||
colVecLoopBody<num_acc, LhsMapper, RhsMapper>(row, cols, rows, lhs, rhs, pAlpha, result);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename LhsMapper, typename RhsMapper>
|
||||
EIGEN_ALWAYS_INLINE void colVecLoopBodyExtra(Index& row, Index cols, Index rows, LhsMapper& lhs, RhsMapper& rhs,
|
||||
const Packet4f pAlpha, float* result) {
|
||||
switch (rows - row) {
|
||||
case 7:
|
||||
colVecLoopBodyExtraN<7, LhsMapper, RhsMapper>(row, cols, rows, lhs, rhs, pAlpha, result);
|
||||
break;
|
||||
case 6:
|
||||
colVecLoopBodyExtraN<6, LhsMapper, RhsMapper>(row, cols, rows, lhs, rhs, pAlpha, result);
|
||||
break;
|
||||
case 5:
|
||||
colVecLoopBodyExtraN<5, LhsMapper, RhsMapper>(row, cols, rows, lhs, rhs, pAlpha, result);
|
||||
break;
|
||||
case 4:
|
||||
colVecLoopBodyExtraN<4, LhsMapper, RhsMapper>(row, cols, rows, lhs, rhs, pAlpha, result);
|
||||
break;
|
||||
case 3:
|
||||
colVecLoopBodyExtraN<3, LhsMapper, RhsMapper>(row, cols, rows, lhs, rhs, pAlpha, result);
|
||||
break;
|
||||
case 2:
|
||||
colVecLoopBodyExtraN<2, LhsMapper, RhsMapper>(row, cols, rows, lhs, rhs, pAlpha, result);
|
||||
break;
|
||||
case 1:
|
||||
colVecLoopBodyExtraN<1, LhsMapper, RhsMapper>(row, cols, rows, lhs, rhs, pAlpha, result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename LhsMapper, typename RhsMapper>
|
||||
EIGEN_ALWAYS_INLINE void calcVecLoops(Index cols, Index rows, LhsMapper& lhs, RhsMapper& rhs, const Packet4f pAlpha,
|
||||
float* result) {
|
||||
Index row = 0;
|
||||
if (rows >= MAX_BFLOAT16_VEC_ACC) {
|
||||
colVecLoopBody<MAX_BFLOAT16_VEC_ACC, LhsMapper, RhsMapper>(row, cols, rows, lhs, rhs, pAlpha, result);
|
||||
result += row;
|
||||
}
|
||||
colVecLoopBodyExtra<LhsMapper, RhsMapper>(row, cols, rows, lhs, rhs, pAlpha, result);
|
||||
}
|
||||
|
||||
template <typename LhsMapper, typename RhsMapper>
|
||||
EIGEN_STRONG_INLINE void gemvMMA_bfloat16_row(Index rows, Index cols, const LhsMapper& alhs, const RhsMapper& rhs,
|
||||
bfloat16* res, Index resIncr, bfloat16 alpha) {
|
||||
typedef typename RhsMapper::LinearMapper LinearMapper;
|
||||
|
||||
// The following copy tells the compiler that lhs's attributes are not modified outside this function
|
||||
// This helps GCC to generate proper code.
|
||||
LhsMapper lhs(alhs);
|
||||
LinearMapper rhs2 = rhs.getLinearMapper(0, 0);
|
||||
|
||||
eigen_internal_assert(rhs.stride() == 1);
|
||||
|
||||
float falpha = Eigen::bfloat16_impl::bfloat16_to_float(alpha);
|
||||
const Packet4f pAlpha = pset1<Packet4f>(falpha);
|
||||
|
||||
ei_declare_aligned_stack_constructed_variable(float, result, rows, 0);
|
||||
if (resIncr == 1) {
|
||||
convertArrayPointerBF16toF32(result, 1, rows, res);
|
||||
} else {
|
||||
convertArrayPointerBF16toF32<true>(result, 1, rows, res, resIncr);
|
||||
}
|
||||
calcVecLoops<LhsMapper, LinearMapper>(cols, rows, lhs, rhs2, pAlpha, result);
|
||||
if (resIncr == 1) {
|
||||
convertArrayPointerF32toBF16(result, rows, res);
|
||||
} else {
|
||||
convertArrayPointerF32toBF16<true>(result, rows, res, resIncr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef MAX_BFLOAT16_VEC_ACC
|
||||
#undef BFLOAT16_UNROLL
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Eigen
|
||||
#endif // EIGEN_MATRIX_PRODUCT_MMA_BFLOAT16_ALTIVEC_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,153 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2019 Rasmus Munk Larsen <rmlarsen@google.com>
|
||||
// Copyright (C) 2023 Chip Kerchner (chip.kerchner@ibm.com)
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_TYPE_CASTING_ALTIVEC_H
|
||||
#define EIGEN_TYPE_CASTING_ALTIVEC_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "../../InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
template <>
|
||||
struct type_casting_traits<float, int> {
|
||||
enum { VectorizedCast = 1, SrcCoeffRatio = 1, TgtCoeffRatio = 1 };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct type_casting_traits<int, float> {
|
||||
enum { VectorizedCast = 1, SrcCoeffRatio = 1, TgtCoeffRatio = 1 };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct type_casting_traits<bfloat16, unsigned short int> {
|
||||
enum { VectorizedCast = 1, SrcCoeffRatio = 1, TgtCoeffRatio = 1 };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct type_casting_traits<unsigned short int, bfloat16> {
|
||||
enum { VectorizedCast = 1, SrcCoeffRatio = 1, TgtCoeffRatio = 1 };
|
||||
};
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4i pcast<Packet4f, Packet4i>(const Packet4f& a) {
|
||||
return vec_cts(a, 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4ui pcast<Packet4f, Packet4ui>(const Packet4f& a) {
|
||||
return vec_ctu(a, 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4f pcast<Packet4i, Packet4f>(const Packet4i& a) {
|
||||
return vec_ctf(a, 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4f pcast<Packet4ui, Packet4f>(const Packet4ui& a) {
|
||||
return vec_ctf(a, 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8us pcast<Packet8bf, Packet8us>(const Packet8bf& a) {
|
||||
Packet4f float_even = Bf16ToF32Even(a);
|
||||
Packet4f float_odd = Bf16ToF32Odd(a);
|
||||
Packet4ui int_even = pcast<Packet4f, Packet4ui>(float_even);
|
||||
Packet4ui int_odd = pcast<Packet4f, Packet4ui>(float_odd);
|
||||
const EIGEN_DECLARE_CONST_FAST_Packet4ui(low_mask, 0x0000FFFF);
|
||||
Packet4ui low_even = pand<Packet4ui>(int_even, p4ui_low_mask);
|
||||
Packet4ui low_odd = pand<Packet4ui>(int_odd, p4ui_low_mask);
|
||||
|
||||
// Check values that are bigger than USHRT_MAX (0xFFFF)
|
||||
Packet4bi overflow_selector;
|
||||
if (vec_any_gt(int_even, p4ui_low_mask)) {
|
||||
overflow_selector = vec_cmpgt(int_even, p4ui_low_mask);
|
||||
low_even = vec_sel(low_even, p4ui_low_mask, overflow_selector);
|
||||
}
|
||||
if (vec_any_gt(int_odd, p4ui_low_mask)) {
|
||||
overflow_selector = vec_cmpgt(int_odd, p4ui_low_mask);
|
||||
low_odd = vec_sel(low_even, p4ui_low_mask, overflow_selector);
|
||||
}
|
||||
|
||||
return pmerge(low_even, low_odd);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8bf pcast<Packet8us, Packet8bf>(const Packet8us& a) {
|
||||
// short -> int -> float -> bfloat16
|
||||
const EIGEN_DECLARE_CONST_FAST_Packet4ui(low_mask, 0x0000FFFF);
|
||||
Packet4ui int_cast = reinterpret_cast<Packet4ui>(a);
|
||||
Packet4ui int_even = pand<Packet4ui>(int_cast, p4ui_low_mask);
|
||||
Packet4ui int_odd = plogical_shift_right<16>(int_cast);
|
||||
Packet4f float_even = pcast<Packet4ui, Packet4f>(int_even);
|
||||
Packet4f float_odd = pcast<Packet4ui, Packet4f>(int_odd);
|
||||
return F32ToBf16(float_even, float_odd);
|
||||
}
|
||||
|
||||
template <>
|
||||
struct type_casting_traits<bfloat16, float> {
|
||||
enum { VectorizedCast = 1, SrcCoeffRatio = 1, TgtCoeffRatio = 2 };
|
||||
};
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4f pcast<Packet8bf, Packet4f>(const Packet8bf& a) {
|
||||
Packet8us z = pset1<Packet8us>(0);
|
||||
#ifdef _BIG_ENDIAN
|
||||
return reinterpret_cast<Packet4f>(vec_mergeh(a.m_val, z));
|
||||
#else
|
||||
return reinterpret_cast<Packet4f>(vec_mergeh(z, a.m_val));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <>
|
||||
struct type_casting_traits<float, bfloat16> {
|
||||
enum { VectorizedCast = 1, SrcCoeffRatio = 2, TgtCoeffRatio = 1 };
|
||||
};
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8bf pcast<Packet4f, Packet8bf>(const Packet4f& a, const Packet4f& b) {
|
||||
return F32ToBf16Both(a, b);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4i preinterpret<Packet4i, Packet4f>(const Packet4f& a) {
|
||||
return reinterpret_cast<Packet4i>(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4f preinterpret<Packet4f, Packet4i>(const Packet4i& a) {
|
||||
return reinterpret_cast<Packet4f>(a);
|
||||
}
|
||||
|
||||
#ifdef EIGEN_VECTORIZE_VSX
|
||||
template <>
|
||||
inline Packet2l pcast<Packet2d, Packet2l>(const Packet2d& x) {
|
||||
EIGEN_ALIGN_MAX double dtmp[2];
|
||||
pstore(dtmp, x);
|
||||
EIGEN_ALIGN_MAX long long itmp[2] = {static_cast<long long>(dtmp[0]), static_cast<long long>(dtmp[1])};
|
||||
return vec_xl(0, itmp);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline Packet2d pcast<Packet2l, Packet2d>(const Packet2l& x) {
|
||||
EIGEN_ALIGN_MAX long long itmp[2];
|
||||
vec_xst(x, 0, itmp);
|
||||
EIGEN_ALIGN_MAX double dtmp[2] = {static_cast<double>(itmp[0]), static_cast<double>(itmp[1])};
|
||||
return pload<Packet2d>(dtmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_TYPE_CASTING_ALTIVEC_H
|
||||
@@ -0,0 +1,244 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
// Copyright (C) 2021 C. Antonio Sanchez <cantonios@google.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_COMPLEX_GPU_H
|
||||
#define EIGEN_COMPLEX_GPU_H
|
||||
|
||||
// Many std::complex methods such as operator+, operator-, operator* and
|
||||
// operator/ are not constexpr. Due to this, GCC and older versions of clang do
|
||||
// not treat them as device functions and thus Eigen functors making use of
|
||||
// these operators fail to compile. Here, we manually specialize these
|
||||
// operators and functors for complex types when building for CUDA to enable
|
||||
// their use on-device.
|
||||
//
|
||||
// NOTES:
|
||||
// - Compound assignment operators +=,-=,*=,/=(Scalar) will not work on device,
|
||||
// since they are already specialized in the standard. Using them will result
|
||||
// in silent kernel failures.
|
||||
// - Compiling with MSVC and using +=,-=,*=,/=(std::complex<Scalar>) will lead
|
||||
// to duplicate definition errors, since these are already specialized in
|
||||
// Visual Studio's <complex> header (contrary to the standard). This is
|
||||
// preferable to removing such definitions, which will lead to silent kernel
|
||||
// failures.
|
||||
// - Compiling with ICC requires defining _USE_COMPLEX_SPECIALIZATION_ prior
|
||||
// to the first inclusion of <complex>.
|
||||
|
||||
#if defined(EIGEN_GPUCC) && defined(EIGEN_GPU_COMPILE_PHASE)
|
||||
|
||||
// ICC already specializes std::complex<float> and std::complex<double>
|
||||
// operators, preventing us from making them device functions here.
|
||||
// This will lead to silent runtime errors if the operators are used on device.
|
||||
//
|
||||
// To allow std::complex operator use on device, define _OVERRIDE_COMPLEX_SPECIALIZATION_
|
||||
// prior to first inclusion of <complex>. This prevents ICC from adding
|
||||
// its own specializations, so our custom ones below can be used instead.
|
||||
#if !(EIGEN_COMP_ICC && defined(_USE_COMPLEX_SPECIALIZATION_))
|
||||
|
||||
// Import Eigen's internal operator specializations.
|
||||
#define EIGEN_USING_STD_COMPLEX_OPERATORS \
|
||||
using Eigen::complex_operator_detail::operator+; \
|
||||
using Eigen::complex_operator_detail::operator-; \
|
||||
using Eigen::complex_operator_detail::operator*; \
|
||||
using Eigen::complex_operator_detail::operator/; \
|
||||
using Eigen::complex_operator_detail::operator+=; \
|
||||
using Eigen::complex_operator_detail::operator-=; \
|
||||
using Eigen::complex_operator_detail::operator*=; \
|
||||
using Eigen::complex_operator_detail::operator/=; \
|
||||
using Eigen::complex_operator_detail::operator==; \
|
||||
using Eigen::complex_operator_detail::operator!=;
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "../../InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
// Specialized std::complex overloads.
|
||||
namespace complex_operator_detail {
|
||||
|
||||
template <typename T>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T> complex_multiply(const std::complex<T>& a,
|
||||
const std::complex<T>& b) {
|
||||
const T a_real = numext::real(a);
|
||||
const T a_imag = numext::imag(a);
|
||||
const T b_real = numext::real(b);
|
||||
const T b_imag = numext::imag(b);
|
||||
return std::complex<T>(a_real * b_real - a_imag * b_imag, a_imag * b_real + a_real * b_imag);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T> complex_divide_fast(const std::complex<T>& a,
|
||||
const std::complex<T>& b) {
|
||||
const T a_real = numext::real(a);
|
||||
const T a_imag = numext::imag(a);
|
||||
const T b_real = numext::real(b);
|
||||
const T b_imag = numext::imag(b);
|
||||
const T norm = (b_real * b_real + b_imag * b_imag);
|
||||
return std::complex<T>((a_real * b_real + a_imag * b_imag) / norm, (a_imag * b_real - a_real * b_imag) / norm);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T> complex_divide_stable(const std::complex<T>& a,
|
||||
const std::complex<T>& b) {
|
||||
const T a_real = numext::real(a);
|
||||
const T a_imag = numext::imag(a);
|
||||
const T b_real = numext::real(b);
|
||||
const T b_imag = numext::imag(b);
|
||||
// Smith's complex division (https://arxiv.org/pdf/1210.4539.pdf),
|
||||
// guards against over/under-flow.
|
||||
const bool scale_imag = numext::abs(b_imag) <= numext::abs(b_real);
|
||||
const T rscale = scale_imag ? T(1) : b_real / b_imag;
|
||||
const T iscale = scale_imag ? b_imag / b_real : T(1);
|
||||
const T denominator = b_real * rscale + b_imag * iscale;
|
||||
return std::complex<T>((a_real * rscale + a_imag * iscale) / denominator,
|
||||
(a_imag * rscale - a_real * iscale) / denominator);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T> complex_divide(const std::complex<T>& a,
|
||||
const std::complex<T>& b) {
|
||||
#if EIGEN_FAST_MATH
|
||||
return complex_divide_fast(a, b);
|
||||
#else
|
||||
return complex_divide_stable(a, b);
|
||||
#endif
|
||||
}
|
||||
|
||||
// NOTE: We cannot specialize compound assignment operators with Scalar T,
|
||||
// (i.e. operator@=(const T&), for @=+,-,*,/)
|
||||
// since they are already specialized for float/double/long double within
|
||||
// the standard <complex> header. We also do not specialize the stream
|
||||
// operators.
|
||||
#define EIGEN_CREATE_STD_COMPLEX_OPERATOR_SPECIALIZATIONS(T) \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T> operator+(const std::complex<T>& a) { return a; } \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T> operator-(const std::complex<T>& a) { \
|
||||
return std::complex<T>(-numext::real(a), -numext::imag(a)); \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T> operator+(const std::complex<T>& a, \
|
||||
const std::complex<T>& b) { \
|
||||
return std::complex<T>(numext::real(a) + numext::real(b), numext::imag(a) + numext::imag(b)); \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T> operator+(const std::complex<T>& a, const T& b) { \
|
||||
return std::complex<T>(numext::real(a) + b, numext::imag(a)); \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T> operator+(const T& a, const std::complex<T>& b) { \
|
||||
return std::complex<T>(a + numext::real(b), numext::imag(b)); \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T> operator-(const std::complex<T>& a, \
|
||||
const std::complex<T>& b) { \
|
||||
return std::complex<T>(numext::real(a) - numext::real(b), numext::imag(a) - numext::imag(b)); \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T> operator-(const std::complex<T>& a, const T& b) { \
|
||||
return std::complex<T>(numext::real(a) - b, numext::imag(a)); \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T> operator-(const T& a, const std::complex<T>& b) { \
|
||||
return std::complex<T>(a - numext::real(b), -numext::imag(b)); \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T> operator*(const std::complex<T>& a, \
|
||||
const std::complex<T>& b) { \
|
||||
return complex_multiply(a, b); \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T> operator*(const std::complex<T>& a, const T& b) { \
|
||||
return std::complex<T>(numext::real(a) * b, numext::imag(a) * b); \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T> operator*(const T& a, const std::complex<T>& b) { \
|
||||
return std::complex<T>(a * numext::real(b), a * numext::imag(b)); \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T> operator/(const std::complex<T>& a, \
|
||||
const std::complex<T>& b) { \
|
||||
return complex_divide(a, b); \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T> operator/(const std::complex<T>& a, const T& b) { \
|
||||
return std::complex<T>(numext::real(a) / b, numext::imag(a) / b); \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T> operator/(const T& a, const std::complex<T>& b) { \
|
||||
return complex_divide(std::complex<T>(a, 0), b); \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T>& operator+=(std::complex<T>& a, const std::complex<T>& b) { \
|
||||
numext::real_ref(a) += numext::real(b); \
|
||||
numext::imag_ref(a) += numext::imag(b); \
|
||||
return a; \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T>& operator-=(std::complex<T>& a, const std::complex<T>& b) { \
|
||||
numext::real_ref(a) -= numext::real(b); \
|
||||
numext::imag_ref(a) -= numext::imag(b); \
|
||||
return a; \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T>& operator*=(std::complex<T>& a, const std::complex<T>& b) { \
|
||||
a = complex_multiply(a, b); \
|
||||
return a; \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE std::complex<T>& operator/=(std::complex<T>& a, const std::complex<T>& b) { \
|
||||
a = complex_divide(a, b); \
|
||||
return a; \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator==(const std::complex<T>& a, const std::complex<T>& b) { \
|
||||
return numext::real(a) == numext::real(b) && numext::imag(a) == numext::imag(b); \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator==(const std::complex<T>& a, const T& b) { \
|
||||
return numext::real(a) == b && numext::imag(a) == 0; \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator==(const T& a, const std::complex<T>& b) { \
|
||||
return a == numext::real(b) && 0 == numext::imag(b); \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator!=(const std::complex<T>& a, const std::complex<T>& b) { \
|
||||
return !(a == b); \
|
||||
} \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator!=(const std::complex<T>& a, const T& b) { return !(a == b); } \
|
||||
\
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool operator!=(const T& a, const std::complex<T>& b) { return !(a == b); }
|
||||
|
||||
// Do not specialize for long double, since that reduces to double on device.
|
||||
EIGEN_CREATE_STD_COMPLEX_OPERATOR_SPECIALIZATIONS(float)
|
||||
EIGEN_CREATE_STD_COMPLEX_OPERATOR_SPECIALIZATIONS(double)
|
||||
|
||||
#undef EIGEN_CREATE_STD_COMPLEX_OPERATOR_SPECIALIZATIONS
|
||||
|
||||
} // namespace complex_operator_detail
|
||||
|
||||
EIGEN_USING_STD_COMPLEX_OPERATORS
|
||||
|
||||
namespace numext {
|
||||
EIGEN_USING_STD_COMPLEX_OPERATORS
|
||||
} // namespace numext
|
||||
|
||||
namespace internal {
|
||||
EIGEN_USING_STD_COMPLEX_OPERATORS
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // !(EIGEN_COMP_ICC && _USE_COMPLEX_SPECIALIZATION_)
|
||||
|
||||
#endif // EIGEN_GPUCC && EIGEN_GPU_COMPILE_PHASE
|
||||
|
||||
#endif // EIGEN_COMPLEX_GPU_H
|
||||
@@ -0,0 +1,268 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2021 The Eigen Team
|
||||
//
|
||||
// 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_TUPLE_GPU
|
||||
#define EIGEN_TUPLE_GPU
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
// This is a replacement of std::tuple that can be used in device code.
|
||||
|
||||
namespace Eigen {
|
||||
namespace internal {
|
||||
namespace tuple_impl {
|
||||
|
||||
// Internal tuple implementation.
|
||||
template <size_t N, typename... Types>
|
||||
class TupleImpl;
|
||||
|
||||
// Generic recursive tuple.
|
||||
template <size_t N, typename T1, typename... Ts>
|
||||
class TupleImpl<N, T1, Ts...> {
|
||||
public:
|
||||
// Tuple may contain Eigen types.
|
||||
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
|
||||
|
||||
// Default constructor, enable if all types are default-constructible.
|
||||
template <typename U1 = T1,
|
||||
typename EnableIf = std::enable_if_t<std::is_default_constructible<U1>::value &&
|
||||
reduce_all<std::is_default_constructible<Ts>::value...>::value>>
|
||||
constexpr EIGEN_DEVICE_FUNC TupleImpl() : head_{}, tail_{} {}
|
||||
|
||||
// Element constructor.
|
||||
template <typename U1, typename... Us,
|
||||
// Only enable if...
|
||||
typename EnableIf = std::enable_if_t<
|
||||
// the number of input arguments match, and ...
|
||||
sizeof...(Us) == sizeof...(Ts) && (
|
||||
// this does not look like a copy/move constructor.
|
||||
N > 1 || std::is_convertible<U1, T1>::value)>>
|
||||
constexpr EIGEN_DEVICE_FUNC TupleImpl(U1&& arg1, Us&&... args)
|
||||
: head_(std::forward<U1>(arg1)), tail_(std::forward<Us>(args)...) {}
|
||||
|
||||
// The first stored value.
|
||||
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T1& head() { return head_; }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE const T1& head() const { return head_; }
|
||||
|
||||
// The tail values.
|
||||
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE TupleImpl<N - 1, Ts...>& tail() { return tail_; }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE const TupleImpl<N - 1, Ts...>& tail() const { return tail_; }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void swap(TupleImpl& other) {
|
||||
using numext::swap;
|
||||
swap(head_, other.head_);
|
||||
swap(tail_, other.tail_);
|
||||
}
|
||||
|
||||
template <typename... UTypes>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TupleImpl& operator=(const TupleImpl<N, UTypes...>& other) {
|
||||
head_ = other.head_;
|
||||
tail_ = other.tail_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... UTypes>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TupleImpl& operator=(TupleImpl<N, UTypes...>&& other) {
|
||||
head_ = std::move(other.head_);
|
||||
tail_ = std::move(other.tail_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
// Allow related tuples to reference head_/tail_.
|
||||
template <size_t M, typename... UTypes>
|
||||
friend class TupleImpl;
|
||||
|
||||
T1 head_;
|
||||
TupleImpl<N - 1, Ts...> tail_;
|
||||
};
|
||||
|
||||
// Empty tuple specialization.
|
||||
template <>
|
||||
class TupleImpl<size_t(0)> {};
|
||||
|
||||
template <typename TupleType>
|
||||
struct is_tuple : std::false_type {};
|
||||
|
||||
template <typename... Types>
|
||||
struct is_tuple<TupleImpl<sizeof...(Types), Types...>> : std::true_type {};
|
||||
|
||||
// Gets an element from a tuple.
|
||||
template <size_t Idx, typename T1, typename... Ts>
|
||||
struct tuple_get_impl {
|
||||
using TupleType = TupleImpl<sizeof...(Ts) + 1, T1, Ts...>;
|
||||
using ReturnType = typename tuple_get_impl<Idx - 1, Ts...>::ReturnType;
|
||||
|
||||
static constexpr EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE ReturnType& run(TupleType& tuple) {
|
||||
return tuple_get_impl<Idx - 1, Ts...>::run(tuple.tail());
|
||||
}
|
||||
|
||||
static constexpr EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE const ReturnType& run(const TupleType& tuple) {
|
||||
return tuple_get_impl<Idx - 1, Ts...>::run(tuple.tail());
|
||||
}
|
||||
};
|
||||
|
||||
// Base case, getting the head element.
|
||||
template <typename T1, typename... Ts>
|
||||
struct tuple_get_impl<0, T1, Ts...> {
|
||||
using TupleType = TupleImpl<sizeof...(Ts) + 1, T1, Ts...>;
|
||||
using ReturnType = T1;
|
||||
|
||||
static constexpr EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE T1& run(TupleType& tuple) { return tuple.head(); }
|
||||
|
||||
static constexpr EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE const T1& run(const TupleType& tuple) { return tuple.head(); }
|
||||
};
|
||||
|
||||
// Concatenates N Tuples.
|
||||
template <size_t NTuples, typename... Tuples>
|
||||
struct tuple_cat_impl;
|
||||
|
||||
template <size_t NTuples, size_t N1, typename... Args1, size_t N2, typename... Args2, typename... Tuples>
|
||||
struct tuple_cat_impl<NTuples, TupleImpl<N1, Args1...>, TupleImpl<N2, Args2...>, Tuples...> {
|
||||
using TupleType1 = TupleImpl<N1, Args1...>;
|
||||
using TupleType2 = TupleImpl<N2, Args2...>;
|
||||
using MergedTupleType = TupleImpl<N1 + N2, Args1..., Args2...>;
|
||||
|
||||
using ReturnType = typename tuple_cat_impl<NTuples - 1, MergedTupleType, Tuples...>::ReturnType;
|
||||
|
||||
// Uses the index sequences to extract and merge elements from tuple1 and tuple2,
|
||||
// then recursively calls again.
|
||||
template <typename Tuple1, size_t... I1s, typename Tuple2, size_t... I2s, typename... MoreTuples>
|
||||
static constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ReturnType run(Tuple1&& tuple1, std::index_sequence<I1s...>,
|
||||
Tuple2&& tuple2, std::index_sequence<I2s...>,
|
||||
MoreTuples&&... tuples) {
|
||||
return tuple_cat_impl<NTuples - 1, MergedTupleType, Tuples...>::run(
|
||||
MergedTupleType(tuple_get_impl<I1s, Args1...>::run(std::forward<Tuple1>(tuple1))...,
|
||||
tuple_get_impl<I2s, Args2...>::run(std::forward<Tuple2>(tuple2))...),
|
||||
std::forward<MoreTuples>(tuples)...);
|
||||
}
|
||||
|
||||
// Concatenates the first two tuples.
|
||||
template <typename Tuple1, typename Tuple2, typename... MoreTuples>
|
||||
static constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ReturnType run(Tuple1&& tuple1, Tuple2&& tuple2,
|
||||
MoreTuples&&... tuples) {
|
||||
return run(std::forward<Tuple1>(tuple1), std::make_index_sequence<N1>{}, std::forward<Tuple2>(tuple2),
|
||||
std::make_index_sequence<N2>{}, std::forward<MoreTuples>(tuples)...);
|
||||
}
|
||||
};
|
||||
|
||||
// Base case with a single tuple.
|
||||
template <size_t N, typename... Args>
|
||||
struct tuple_cat_impl<1, TupleImpl<N, Args...>> {
|
||||
using ReturnType = TupleImpl<N, Args...>;
|
||||
|
||||
template <typename Tuple1>
|
||||
static constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ReturnType run(Tuple1&& tuple1) {
|
||||
return tuple1;
|
||||
}
|
||||
};
|
||||
|
||||
// Special case of no tuples.
|
||||
template <>
|
||||
struct tuple_cat_impl<0> {
|
||||
using ReturnType = TupleImpl<0>;
|
||||
static constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ReturnType run() { return ReturnType{}; }
|
||||
};
|
||||
|
||||
// For use in make_tuple, unwraps a reference_wrapper.
|
||||
template <typename T>
|
||||
struct unwrap_reference_wrapper {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct unwrap_reference_wrapper<std::reference_wrapper<T>> {
|
||||
using type = T&;
|
||||
};
|
||||
|
||||
// For use in make_tuple, decays a type and unwraps a reference_wrapper.
|
||||
template <typename T>
|
||||
struct unwrap_decay {
|
||||
using type = typename unwrap_reference_wrapper<typename std::decay<T>::type>::type;
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility for determining a tuple's size.
|
||||
*/
|
||||
template <typename Tuple>
|
||||
struct tuple_size;
|
||||
|
||||
template <typename... Types>
|
||||
struct tuple_size<TupleImpl<sizeof...(Types), Types...>> : std::integral_constant<size_t, sizeof...(Types)> {};
|
||||
|
||||
/**
|
||||
* Gets an element of a tuple.
|
||||
* \tparam Idx index of the element.
|
||||
* \tparam Types ... tuple element types.
|
||||
* \param tuple the tuple.
|
||||
* \return a reference to the desired element.
|
||||
*/
|
||||
template <size_t Idx, typename... Types>
|
||||
constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const typename tuple_get_impl<Idx, Types...>::ReturnType& get(
|
||||
const TupleImpl<sizeof...(Types), Types...>& tuple) {
|
||||
return tuple_get_impl<Idx, Types...>::run(tuple);
|
||||
}
|
||||
|
||||
template <size_t Idx, typename... Types>
|
||||
constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE typename tuple_get_impl<Idx, Types...>::ReturnType& get(
|
||||
TupleImpl<sizeof...(Types), Types...>& tuple) {
|
||||
return tuple_get_impl<Idx, Types...>::run(tuple);
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate multiple tuples.
|
||||
* \param tuples ... list of tuples.
|
||||
* \return concatenated tuple.
|
||||
*/
|
||||
template <typename... Tuples, typename EnableIf = std::enable_if_t<
|
||||
internal::reduce_all<is_tuple<typename std::decay<Tuples>::type>::value...>::value>>
|
||||
constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
|
||||
typename tuple_cat_impl<sizeof...(Tuples), typename std::decay<Tuples>::type...>::ReturnType
|
||||
tuple_cat(Tuples&&... tuples) {
|
||||
return tuple_cat_impl<sizeof...(Tuples), typename std::decay<Tuples>::type...>::run(std::forward<Tuples>(tuples)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tie arguments together into a tuple.
|
||||
*/
|
||||
template <typename... Args, typename ReturnType = TupleImpl<sizeof...(Args), Args&...>>
|
||||
constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ReturnType tie(Args&... args) noexcept {
|
||||
return ReturnType{args...};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tuple of l-values with the supplied arguments.
|
||||
*/
|
||||
template <typename... Args, typename ReturnType = TupleImpl<sizeof...(Args), typename unwrap_decay<Args>::type...>>
|
||||
constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ReturnType make_tuple(Args&&... args) {
|
||||
return ReturnType{std::forward<Args>(args)...};
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward a set of arguments as a tuple.
|
||||
*/
|
||||
template <typename... Args>
|
||||
constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TupleImpl<sizeof...(Args), Args...> forward_as_tuple(Args&&... args) {
|
||||
return TupleImpl<sizeof...(Args), Args...>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternative to std::tuple that can be used on device.
|
||||
*/
|
||||
template <typename... Types>
|
||||
using tuple = TupleImpl<sizeof...(Types), Types...>;
|
||||
|
||||
} // namespace tuple_impl
|
||||
} // namespace internal
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_TUPLE_GPU
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,520 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// copyright (c) 2023 zang ruochen <zangruochen@loongson.cn>
|
||||
// copyright (c) 2024 XiWei Gu <guxiwei-hf@loongson.cn>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_COMPLEX_LSX_H
|
||||
#define EIGEN_COMPLEX_LSX_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "../../InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
//---------- float ----------
|
||||
struct Packet2cf {
|
||||
EIGEN_STRONG_INLINE Packet2cf() {}
|
||||
EIGEN_STRONG_INLINE explicit Packet2cf(const __m128& a) : v(a) {}
|
||||
Packet4f v;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct packet_traits<std::complex<float> > : default_packet_traits {
|
||||
typedef Packet2cf type;
|
||||
typedef Packet2cf half;
|
||||
enum {
|
||||
Vectorizable = 1,
|
||||
AlignedOnScalar = 1,
|
||||
size = 2,
|
||||
|
||||
HasAdd = 1,
|
||||
HasSub = 1,
|
||||
HasMul = 1,
|
||||
HasDiv = 1,
|
||||
HasNegate = 1,
|
||||
HasSqrt = 1,
|
||||
HasExp = 1,
|
||||
HasAbs = 0,
|
||||
HasLog = 1,
|
||||
HasAbs2 = 0,
|
||||
HasMin = 0,
|
||||
HasMax = 0,
|
||||
HasSetLinear = 0
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct unpacket_traits<Packet2cf> {
|
||||
typedef std::complex<float> type;
|
||||
typedef Packet2cf half;
|
||||
typedef Packet4f as_real;
|
||||
enum {
|
||||
size = 2,
|
||||
alignment = Aligned16,
|
||||
vectorizable = true,
|
||||
masked_load_available = false,
|
||||
masked_store_available = false
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf padd<Packet2cf>(const Packet2cf& a, const Packet2cf& b) {
|
||||
return Packet2cf(__lsx_vfadd_s(a.v, b.v));
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf psub<Packet2cf>(const Packet2cf& a, const Packet2cf& b) {
|
||||
return Packet2cf(__lsx_vfsub_s(a.v, b.v));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf pnegate(const Packet2cf& a) {
|
||||
const uint32_t b[4] = {0x80000000u, 0x80000000u, 0x80000000u, 0x80000000u};
|
||||
Packet4i mask = (Packet4i)__lsx_vld(b, 0);
|
||||
Packet2cf res;
|
||||
res.v = (Packet4f)__lsx_vxor_v((__m128i)a.v, mask);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf pconj(const Packet2cf& a) {
|
||||
const uint32_t b[4] = {0x00000000u, 0x80000000u, 0x00000000u, 0x80000000u};
|
||||
Packet4i mask = (__m128i)__lsx_vld(b, 0);
|
||||
Packet2cf res;
|
||||
res.v = (Packet4f)__lsx_vxor_v((__m128i)a.v, mask);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf pmul<Packet2cf>(const Packet2cf& a, const Packet2cf& b) {
|
||||
Packet4f part0_tmp = (Packet4f)__lsx_vfmul_s(a.v, b.v);
|
||||
Packet4f part0 = __lsx_vfsub_s(part0_tmp, (__m128)__lsx_vshuf4i_w(part0_tmp, 0x31));
|
||||
Packet4f part1_tmp = __lsx_vfmul_s((__m128)__lsx_vshuf4i_w(a.v, 0xb1), b.v);
|
||||
Packet4f part1 = __lsx_vfadd_s(part1_tmp, (__m128)__lsx_vshuf4i_w(part1_tmp, 0x31));
|
||||
Packet2cf res;
|
||||
res.v = (Packet4f)__lsx_vpackev_w((__m128i)part1, (__m128i)part0);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf ptrue<Packet2cf>(const Packet2cf& a) {
|
||||
return Packet2cf(ptrue(Packet4f(a.v)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf pand<Packet2cf>(const Packet2cf& a, const Packet2cf& b) {
|
||||
Packet2cf res;
|
||||
res.v = (Packet4f)__lsx_vand_v((__m128i)a.v, (__m128i)b.v);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf por<Packet2cf>(const Packet2cf& a, const Packet2cf& b) {
|
||||
Packet2cf res;
|
||||
res.v = (Packet4f)__lsx_vor_v((__m128i)a.v, (__m128i)b.v);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf pxor<Packet2cf>(const Packet2cf& a, const Packet2cf& b) {
|
||||
Packet2cf res;
|
||||
res.v = (Packet4f)__lsx_vxor_v((__m128i)a.v, (__m128i)b.v);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf pandnot<Packet2cf>(const Packet2cf& a, const Packet2cf& b) {
|
||||
Packet2cf res;
|
||||
res.v = (Packet4f)__lsx_vandn_v((__m128i)b.v, (__m128i)a.v);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf pload<Packet2cf>(const std::complex<float>* from) {
|
||||
EIGEN_DEBUG_ALIGNED_LOAD return Packet2cf(pload<Packet4f>(&numext::real_ref(*from)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf ploadu<Packet2cf>(const std::complex<float>* from) {
|
||||
EIGEN_DEBUG_UNALIGNED_LOAD return Packet2cf(ploadu<Packet4f>(&numext::real_ref(*from)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf pset1<Packet2cf>(const std::complex<float>& from) {
|
||||
float f0 = from.real(), f1 = from.imag();
|
||||
Packet4f re = {f0, f0, f0, f0};
|
||||
Packet4f im = {f1, f1, f1, f1};
|
||||
return Packet2cf((Packet4f)__lsx_vilvl_w((__m128i)im, (__m128i)re));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf ploaddup<Packet2cf>(const std::complex<float>* from) {
|
||||
return pset1<Packet2cf>(*from);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE void pstore<std::complex<float> >(std::complex<float>* to, const Packet2cf& from) {
|
||||
EIGEN_DEBUG_ALIGNED_STORE pstore(&numext::real_ref(*to), Packet4f(from.v));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE void pstoreu<std::complex<float> >(std::complex<float>* to, const Packet2cf& from) {
|
||||
EIGEN_DEBUG_UNALIGNED_STORE pstoreu(&numext::real_ref(*to), Packet4f(from.v));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_DEVICE_FUNC inline Packet2cf pgather<std::complex<float>, Packet2cf>(const std::complex<float>* from,
|
||||
Index stride) {
|
||||
Packet2cf res;
|
||||
__m128i tmp = __lsx_vldrepl_d(from, 0);
|
||||
__m128i tmp1 = __lsx_vldrepl_d(from + stride, 0);
|
||||
tmp = __lsx_vilvl_d(tmp1, tmp);
|
||||
res.v = (__m128)tmp;
|
||||
return res;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_DEVICE_FUNC inline void pscatter<std::complex<float>, Packet2cf>(std::complex<float>* to, const Packet2cf& from,
|
||||
Index stride) {
|
||||
__lsx_vstelm_d((__m128i)from.v, to, 0, 0);
|
||||
__lsx_vstelm_d((__m128i)from.v, to + stride, 0, 1);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE void prefetch<std::complex<float> >(const std::complex<float>* addr) {
|
||||
__builtin_prefetch(addr);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE std::complex<float> pfirst<Packet2cf>(const Packet2cf& a) {
|
||||
EIGEN_ALIGN16 std::complex<float> res[2];
|
||||
__lsx_vst(a.v, res, 0);
|
||||
return res[0];
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf preverse(const Packet2cf& a) {
|
||||
Packet2cf res;
|
||||
res.v = (Packet4f)__lsx_vshuf4i_w(a.v, 0x4e);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE std::complex<float> predux<Packet2cf>(const Packet2cf& a) {
|
||||
return pfirst(Packet2cf(__lsx_vfadd_s(a.v, vec4f_movehl(a.v, a.v))));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE std::complex<float> predux_mul<Packet2cf>(const Packet2cf& a) {
|
||||
return pfirst(pmul(a, Packet2cf(vec4f_movehl(a.v, a.v))));
|
||||
}
|
||||
|
||||
EIGEN_STRONG_INLINE Packet2cf pcplxflip /* <Packet2cf> */ (const Packet2cf& x) {
|
||||
return Packet2cf(vec4f_swizzle1(x.v, 1, 0, 3, 2));
|
||||
}
|
||||
|
||||
EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(Packet2cf, Packet4f)
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf pdiv<Packet2cf>(const Packet2cf& a, const Packet2cf& b) {
|
||||
return pdiv_complex(a, b);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf plog<Packet2cf>(const Packet2cf& a) {
|
||||
return plog_complex(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf pzero(const Packet2cf& /* a */) {
|
||||
__m128 v = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
return (Packet2cf)v;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf pmadd<Packet2cf>(const Packet2cf& a, const Packet2cf& b, const Packet2cf& c) {
|
||||
Packet2cf result, t0, t1, t2;
|
||||
t1 = pzero(t1);
|
||||
t0.v = (__m128)__lsx_vpackev_w((__m128i)a.v, (__m128i)a.v);
|
||||
t2.v = __lsx_vfmadd_s(t0.v, b.v, c.v);
|
||||
result.v = __lsx_vfadd_s(t2.v, t1.v);
|
||||
t1.v = __lsx_vfsub_s(t1.v, a.v);
|
||||
t1.v = (__m128)__lsx_vpackod_w((__m128i)a.v, (__m128i)t1.v);
|
||||
t2.v = (__m128)__lsx_vshuf4i_w((__m128i)b.v, 0xb1);
|
||||
result.v = __lsx_vfmadd_s(t1.v, t2.v, result.v);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf pexp<Packet2cf>(const Packet2cf& a) {
|
||||
return pexp_complex(a);
|
||||
}
|
||||
|
||||
//---------- double ----------
|
||||
struct Packet1cd {
|
||||
EIGEN_STRONG_INLINE Packet1cd() {}
|
||||
EIGEN_STRONG_INLINE explicit Packet1cd(const __m128d& a) : v(a) {}
|
||||
Packet2d v;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct packet_traits<std::complex<double> > : default_packet_traits {
|
||||
typedef Packet1cd type;
|
||||
typedef Packet1cd half;
|
||||
enum {
|
||||
Vectorizable = 1,
|
||||
AlignedOnScalar = 0,
|
||||
size = 1,
|
||||
|
||||
HasAdd = 1,
|
||||
HasSub = 1,
|
||||
HasMul = 1,
|
||||
HasDiv = 1,
|
||||
HasNegate = 1,
|
||||
HasSqrt = 1,
|
||||
HasAbs = 0,
|
||||
HasLog = 1,
|
||||
HasAbs2 = 0,
|
||||
HasMin = 0,
|
||||
HasMax = 0,
|
||||
HasSetLinear = 0
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct unpacket_traits<Packet1cd> {
|
||||
typedef std::complex<double> type;
|
||||
typedef Packet1cd half;
|
||||
typedef Packet2d as_real;
|
||||
enum {
|
||||
size = 1,
|
||||
alignment = Aligned16,
|
||||
vectorizable = true,
|
||||
masked_load_available = false,
|
||||
masked_store_available = false
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd padd<Packet1cd>(const Packet1cd& a, const Packet1cd& b) {
|
||||
return Packet1cd(__lsx_vfadd_d(a.v, b.v));
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd psub<Packet1cd>(const Packet1cd& a, const Packet1cd& b) {
|
||||
return Packet1cd(__lsx_vfsub_d(a.v, b.v));
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd pnegate(const Packet1cd& a) {
|
||||
return Packet1cd(pnegate(Packet2d(a.v)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd pconj(const Packet1cd& a) {
|
||||
const uint64_t tmp[2] = {0x0000000000000000u, 0x8000000000000000u};
|
||||
__m128i mask = __lsx_vld(tmp, 0);
|
||||
Packet1cd res;
|
||||
res.v = (Packet2d)__lsx_vxor_v((__m128i)a.v, mask);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd pmul<Packet1cd>(const Packet1cd& a, const Packet1cd& b) {
|
||||
Packet2d tmp_real = __lsx_vfmul_d(a.v, b.v);
|
||||
Packet2d real = __lsx_vfsub_d(tmp_real, preverse(tmp_real));
|
||||
|
||||
Packet2d tmp_imag = __lsx_vfmul_d(preverse(a.v), b.v);
|
||||
Packet2d imag = (__m128d)__lsx_vfadd_d((__m128d)tmp_imag, preverse(tmp_imag));
|
||||
Packet1cd res;
|
||||
res.v = (__m128d)__lsx_vilvl_d((__m128i)imag, (__m128i)real);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd ptrue<Packet1cd>(const Packet1cd& a) {
|
||||
return Packet1cd(ptrue(Packet2d(a.v)));
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd pand<Packet1cd>(const Packet1cd& a, const Packet1cd& b) {
|
||||
Packet1cd res;
|
||||
res.v = (Packet2d)__lsx_vand_v((__m128i)a.v, (__m128i)b.v);
|
||||
return res;
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd por<Packet1cd>(const Packet1cd& a, const Packet1cd& b) {
|
||||
Packet1cd res;
|
||||
res.v = (Packet2d)__lsx_vor_v((__m128i)a.v, (__m128i)b.v);
|
||||
return res;
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd pxor<Packet1cd>(const Packet1cd& a, const Packet1cd& b) {
|
||||
Packet1cd res;
|
||||
res.v = (Packet2d)__lsx_vxor_v((__m128i)a.v, (__m128i)b.v);
|
||||
return res;
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd pandnot<Packet1cd>(const Packet1cd& a, const Packet1cd& b) {
|
||||
Packet1cd res;
|
||||
res.v = (Packet2d)__lsx_vandn_v((__m128i)b.v, (__m128i)a.v);
|
||||
return res;
|
||||
}
|
||||
|
||||
// FIXME force unaligned load, this is a temporary fix
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd pload<Packet1cd>(const std::complex<double>* from) {
|
||||
EIGEN_DEBUG_ALIGNED_LOAD return Packet1cd(pload<Packet2d>((const double*)from));
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd ploadu<Packet1cd>(const std::complex<double>* from) {
|
||||
EIGEN_DEBUG_UNALIGNED_LOAD return Packet1cd(ploadu<Packet2d>((const double*)from));
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd
|
||||
pset1<Packet1cd>(const std::complex<double>& from) { /* here we really have to use unaligned loads :( */
|
||||
return ploadu<Packet1cd>(&from);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd ploaddup<Packet1cd>(const std::complex<double>* from) {
|
||||
return pset1<Packet1cd>(*from);
|
||||
}
|
||||
|
||||
// FIXME force unaligned store, this is a temporary fix
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE void pstore<std::complex<double> >(std::complex<double>* to, const Packet1cd& from) {
|
||||
EIGEN_DEBUG_ALIGNED_STORE pstore((double*)to, Packet2d(from.v));
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE void pstoreu<std::complex<double> >(std::complex<double>* to, const Packet1cd& from) {
|
||||
EIGEN_DEBUG_UNALIGNED_STORE pstoreu((double*)to, Packet2d(from.v));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE void prefetch<std::complex<double> >(const std::complex<double>* addr) {
|
||||
__builtin_prefetch(addr);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE std::complex<double> pfirst<Packet1cd>(const Packet1cd& a) {
|
||||
EIGEN_ALIGN16 double res[2];
|
||||
__lsx_vst(a.v, res, 0);
|
||||
return std::complex<double>(res[0], res[1]);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd preverse(const Packet1cd& a) {
|
||||
return a;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE std::complex<double> predux<Packet1cd>(const Packet1cd& a) {
|
||||
return pfirst(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE std::complex<double> predux_mul<Packet1cd>(const Packet1cd& a) {
|
||||
return pfirst(a);
|
||||
}
|
||||
|
||||
EIGEN_MAKE_CONJ_HELPER_CPLX_REAL(Packet1cd, Packet2d)
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd pdiv<Packet1cd>(const Packet1cd& a, const Packet1cd& b) {
|
||||
return pdiv_complex(a, b);
|
||||
}
|
||||
|
||||
EIGEN_STRONG_INLINE Packet1cd pcplxflip /* <Packet1cd> */ (const Packet1cd& x) {
|
||||
return Packet1cd(preverse(Packet2d(x.v)));
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC inline void ptranspose(PacketBlock<Packet2cf, 2>& kernel) {
|
||||
Packet4f tmp1 = (Packet4f)__lsx_vilvl_w((__m128i)kernel.packet[1].v, (__m128i)kernel.packet[0].v);
|
||||
Packet4f tmp2 = (Packet4f)__lsx_vilvh_w((__m128i)kernel.packet[1].v, (__m128i)kernel.packet[0].v);
|
||||
kernel.packet[0].v = (Packet4f)__lsx_vshuf4i_w(tmp1, 0xd8);
|
||||
kernel.packet[1].v = (Packet4f)__lsx_vshuf4i_w(tmp2, 0xd8);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf pcmp_eq(const Packet2cf& a, const Packet2cf& b) {
|
||||
Packet4f eq = (Packet4f)__lsx_vfcmp_ceq_s(a.v, b.v);
|
||||
return Packet2cf(pand<Packet4f>(eq, vec4f_swizzle1(eq, 1, 0, 3, 2)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd pcmp_eq(const Packet1cd& a, const Packet1cd& b) {
|
||||
Packet2d eq = (Packet2d)__lsx_vfcmp_ceq_d(a.v, b.v);
|
||||
return Packet1cd(pand<Packet2d>(eq, preverse(eq)));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_DEVICE_FUNC inline Packet2cf pselect(const Packet2cf& mask, const Packet2cf& a, const Packet2cf& b) {
|
||||
Packet2cf res;
|
||||
res.v = (Packet4f)__lsx_vbitsel_v((__m128i)b.v, (__m128i)a.v, (__m128i)mask.v);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd psqrt<Packet1cd>(const Packet1cd& a) {
|
||||
return psqrt_complex<Packet1cd>(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2cf psqrt<Packet2cf>(const Packet2cf& a) {
|
||||
return psqrt_complex<Packet2cf>(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd plog<Packet1cd>(const Packet1cd& a) {
|
||||
return plog_complex(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd pzero<Packet1cd>(const Packet1cd& /* a */) {
|
||||
__m128d v = {0.0, 0.0};
|
||||
return (Packet1cd)v;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet1cd pmadd<Packet1cd>(const Packet1cd& a, const Packet1cd& b, const Packet1cd& c) {
|
||||
Packet1cd result, t0, t1, t2;
|
||||
t1 = pzero(t1);
|
||||
t0.v = (__m128d)__lsx_vpackev_d((__m128i)a.v, (__m128i)a.v);
|
||||
t2.v = __lsx_vfmadd_d(t0.v, b.v, c.v);
|
||||
result.v = __lsx_vfadd_d(t2.v, t1.v);
|
||||
t1.v = __lsx_vfsub_d(t1.v, a.v);
|
||||
t1.v = (__m128d)__lsx_vpackod_d((__m128i)a.v, (__m128i)t1.v);
|
||||
t2.v = (__m128d)__lsx_vshuf4i_d((__m128i)t2.v, (__m128i)b.v, 0xb);
|
||||
result.v = __lsx_vfmadd_d(t1.v, t2.v, result.v);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_DEVICE_FUNC inline Packet1cd pgather<std::complex<double>, Packet1cd>(const std::complex<double>* from,
|
||||
Index /* stride */) {
|
||||
Packet1cd res;
|
||||
__m128i tmp = __lsx_vld((void*)from, 0);
|
||||
res.v = (__m128d)tmp;
|
||||
return res;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_DEVICE_FUNC inline void pscatter<std::complex<double>, Packet1cd>(std::complex<double>* to, const Packet1cd& from,
|
||||
Index /* stride */) {
|
||||
__lsx_vst((__m128i)from.v, (void*)to, 0);
|
||||
}
|
||||
|
||||
EIGEN_STRONG_INLINE void ptranspose(PacketBlock<Packet1cd, 2>& kernel) {
|
||||
Packet2d tmp = (__m128d)__lsx_vilvl_d((__m128i)kernel.packet[1].v, (__m128i)kernel.packet[0].v);
|
||||
kernel.packet[1].v = (__m128d)__lsx_vilvh_d((__m128i)kernel.packet[1].v, (__m128i)kernel.packet[0].v);
|
||||
kernel.packet[0].v = tmp;
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_COMPLEX_LSX_H
|
||||
@@ -0,0 +1,23 @@
|
||||
// IWYU pragma: private
|
||||
#include "../../InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
namespace internal {
|
||||
|
||||
#ifndef EIGEN_LSX_GEBP_NR
|
||||
#define EIGEN_LSX_GEBP_NR 8
|
||||
#endif
|
||||
|
||||
template <>
|
||||
struct gebp_traits<float, float, false, false, Architecture::LSX, GEBPPacketFull>
|
||||
: gebp_traits<float, float, false, false, Architecture::Generic, GEBPPacketFull> {
|
||||
enum { nr = EIGEN_LSX_GEBP_NR };
|
||||
};
|
||||
|
||||
template <>
|
||||
struct gebp_traits<double, double, false, false, Architecture::LSX, GEBPPacketFull>
|
||||
: gebp_traits<double, double, false, false, Architecture::Generic, GEBPPacketFull> {
|
||||
enum { nr = EIGEN_LSX_GEBP_NR };
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace Eigen
|
||||
@@ -0,0 +1,43 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2024 XiWei Gu (guxiwei-hf@loongson.cn)
|
||||
//
|
||||
// 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_MATH_FUNCTIONS_LSX_H
|
||||
#define EIGEN_MATH_FUNCTIONS_LSX_H
|
||||
|
||||
/* The sin and cos functions of this file are loosely derived from
|
||||
* Julien Pommier's sse math library: http://gruntthepeon.free.fr/ssemath/
|
||||
*/
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "../../InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
EIGEN_DOUBLE_PACKET_FUNCTION(atanh, Packet2d)
|
||||
EIGEN_DOUBLE_PACKET_FUNCTION(log, Packet2d)
|
||||
EIGEN_DOUBLE_PACKET_FUNCTION(log2, Packet2d)
|
||||
EIGEN_DOUBLE_PACKET_FUNCTION(tanh, Packet2d)
|
||||
|
||||
EIGEN_FLOAT_PACKET_FUNCTION(atanh, Packet4f)
|
||||
EIGEN_FLOAT_PACKET_FUNCTION(log, Packet4f)
|
||||
EIGEN_FLOAT_PACKET_FUNCTION(log2, Packet4f)
|
||||
EIGEN_FLOAT_PACKET_FUNCTION(tanh, Packet4f)
|
||||
|
||||
EIGEN_GENERIC_PACKET_FUNCTION(atan, Packet2d)
|
||||
EIGEN_GENERIC_PACKET_FUNCTION(atan, Packet4f)
|
||||
EIGEN_GENERIC_PACKET_FUNCTION(exp2, Packet2d)
|
||||
EIGEN_GENERIC_PACKET_FUNCTION(exp2, Packet4f)
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_MATH_FUNCTIONS_LSX_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,526 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2023 Zang Ruochen <zangruochen@loongson.cn>
|
||||
// Copyright (C) 2024 XiWei Gu <guxiwei-hf@loongson.cn>
|
||||
//
|
||||
// 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_TYPE_CASTING_LSX_H
|
||||
#define EIGEN_TYPE_CASTING_LSX_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "../../InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
//==============================================================================
|
||||
// preinterpret
|
||||
//==============================================================================
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4f preinterpret<Packet4f, Packet4i>(const Packet4i& a) {
|
||||
return (__m128)((__m128i)a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4f preinterpret<Packet4f, Packet4ui>(const Packet4ui& a) {
|
||||
return (__m128)((__m128i)a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2d preinterpret<Packet2d, Packet2l>(const Packet2l& a) {
|
||||
return (__m128d)((__m128i)a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2d preinterpret<Packet2d, Packet2ul>(const Packet2ul& a) {
|
||||
return (__m128d)((__m128i)a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2d preinterpret<Packet2d, Packet4i>(const Packet4i& a) {
|
||||
return (__m128d)((__m128i)a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16c preinterpret<Packet16c, Packet16uc>(const Packet16uc& a) {
|
||||
return (__m128i)a;
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8s preinterpret<Packet8s, Packet8us>(const Packet8us& a) {
|
||||
return (__m128i)a;
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4i preinterpret<Packet4i, Packet4f>(const Packet4f& a) {
|
||||
return (__m128i)a;
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4i preinterpret<Packet4i, Packet4ui>(const Packet4ui& a) {
|
||||
return (__m128i)a;
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4i preinterpret<Packet4i, Packet2d>(const Packet2d& a) {
|
||||
return (__m128i)a;
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2l preinterpret<Packet2l, Packet2d>(const Packet2d& a) {
|
||||
return (__m128i)a;
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16uc preinterpret<Packet16uc, Packet16c>(const Packet16c& a) {
|
||||
return (__m128i)a;
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8us preinterpret<Packet8us, Packet8s>(const Packet8s& a) {
|
||||
return (__m128i)a;
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4ui preinterpret<Packet4ui, Packet4f>(const Packet4f& a) {
|
||||
return (__m128i)a;
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4ui preinterpret<Packet4ui, Packet4i>(const Packet4i& a) {
|
||||
return (__m128i)a;
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2ul preinterpret<Packet2ul, Packet2d>(const Packet2d& a) {
|
||||
return (__m128i)a;
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2ul preinterpret<Packet2ul, Packet2l>(const Packet2l& a) {
|
||||
return (__m128i)a;
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2l pcast<Packet4f, Packet2l>(const Packet4f& a) {
|
||||
Packet2d tmp = __lsx_vfcvtl_d_s(a);
|
||||
return __lsx_vftint_l_d(tmp);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2ul pcast<Packet4f, Packet2ul>(const Packet4f& a) {
|
||||
Packet2d tmp = __lsx_vfcvtl_d_s(a);
|
||||
return __lsx_vftint_lu_d(tmp);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4i pcast<Packet4f, Packet4i>(const Packet4f& a) {
|
||||
return __lsx_vftint_w_s(a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4ui pcast<Packet4f, Packet4ui>(const Packet4f& a) {
|
||||
return __lsx_vftint_wu_s(a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8s pcast<Packet4f, Packet8s>(const Packet4f& a, const Packet4f& b) {
|
||||
return __lsx_vssrlni_h_w(__lsx_vftint_w_s(a), __lsx_vftint_w_s(b), 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8us pcast<Packet4f, Packet8us>(const Packet4f& a, const Packet4f& b) {
|
||||
return __lsx_vssrlni_hu_w(__lsx_vftint_wu_s(a), __lsx_vftint_wu_s(b), 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16c pcast<Packet4f, Packet16c>(const Packet4f& a, const Packet4f& b, const Packet4f& c,
|
||||
const Packet4f& d) {
|
||||
Packet8s tmp1 = __lsx_vssrlni_h_w(__lsx_vftint_w_s(a), __lsx_vftint_w_s(b), 0);
|
||||
Packet8s tmp2 = __lsx_vssrlni_h_w(__lsx_vftint_w_s(c), __lsx_vftint_w_s(d), 0);
|
||||
return __lsx_vssrlni_b_h((__m128i)tmp1, (__m128i)tmp2, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16uc pcast<Packet4f, Packet16uc>(const Packet4f& a, const Packet4f& b, const Packet4f& c,
|
||||
const Packet4f& d) {
|
||||
Packet8us tmp1 = __lsx_vssrlni_hu_w(__lsx_vftint_wu_s(a), __lsx_vftint_wu_s(b), 0);
|
||||
Packet8us tmp2 = __lsx_vssrlni_hu_w(__lsx_vftint_wu_s(c), __lsx_vftint_wu_s(d), 0);
|
||||
return __lsx_vssrlni_bu_h((__m128i)tmp1, (__m128i)tmp2, 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4f pcast<Packet16c, Packet4f>(const Packet16c& a) {
|
||||
Packet8s tmp1 = __lsx_vsllwil_h_b((__m128i)a, 0);
|
||||
Packet4i tmp2 = __lsx_vsllwil_w_h((__m128i)tmp1, 0);
|
||||
return __lsx_vffint_s_w(tmp2);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2l pcast<Packet16c, Packet2l>(const Packet16c& a) {
|
||||
Packet8s tmp1 = __lsx_vsllwil_h_b((__m128i)a, 0);
|
||||
Packet4i tmp2 = __lsx_vsllwil_w_h((__m128i)tmp1, 0);
|
||||
return __lsx_vsllwil_d_w((__m128i)tmp2, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2ul pcast<Packet16c, Packet2ul>(const Packet16c& a) {
|
||||
Packet8s tmp1 = __lsx_vsllwil_h_b((__m128i)a, 0);
|
||||
Packet4i tmp2 = __lsx_vsllwil_w_h((__m128i)tmp1, 0);
|
||||
return (Packet2ul)__lsx_vsllwil_d_w((__m128i)tmp2, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4i pcast<Packet16c, Packet4i>(const Packet16c& a) {
|
||||
Packet8s tmp1 = __lsx_vsllwil_h_b((__m128i)a, 0);
|
||||
return __lsx_vsllwil_w_h((__m128i)tmp1, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4ui pcast<Packet16c, Packet4ui>(const Packet16c& a) {
|
||||
Packet8s tmp1 = __lsx_vsllwil_h_b((__m128i)a, 0);
|
||||
return (Packet4ui)__lsx_vsllwil_w_h((__m128i)tmp1, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8s pcast<Packet16c, Packet8s>(const Packet16c& a) {
|
||||
return __lsx_vsllwil_h_b((__m128i)a, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8us pcast<Packet16c, Packet8us>(const Packet16c& a) {
|
||||
return (Packet8us)__lsx_vsllwil_h_b((__m128i)a, 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4f pcast<Packet16uc, Packet4f>(const Packet16uc& a) {
|
||||
Packet8us tmp1 = __lsx_vsllwil_hu_bu((__m128i)a, 0);
|
||||
Packet4ui tmp2 = __lsx_vsllwil_wu_hu((__m128i)tmp1, 0);
|
||||
return __lsx_vffint_s_wu(tmp2);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2ul pcast<Packet16uc, Packet2ul>(const Packet16uc& a) {
|
||||
Packet8us tmp1 = __lsx_vsllwil_hu_bu((__m128i)a, 0);
|
||||
Packet4ui tmp2 = __lsx_vsllwil_wu_hu((__m128i)tmp1, 0);
|
||||
return __lsx_vsllwil_du_wu((__m128i)tmp2, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2l pcast<Packet16uc, Packet2l>(const Packet16uc& a) {
|
||||
Packet8us tmp1 = __lsx_vsllwil_hu_bu((__m128i)a, 0);
|
||||
Packet4ui tmp2 = __lsx_vsllwil_wu_hu((__m128i)tmp1, 0);
|
||||
return (Packet2l)__lsx_vsllwil_du_wu((__m128i)tmp2, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4ui pcast<Packet16uc, Packet4ui>(const Packet16uc& a) {
|
||||
Packet8us tmp1 = __lsx_vsllwil_hu_bu((__m128i)a, 0);
|
||||
return __lsx_vsllwil_wu_hu((__m128i)tmp1, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4i pcast<Packet16uc, Packet4i>(const Packet16uc& a) {
|
||||
Packet8us tmp1 = __lsx_vsllwil_hu_bu((__m128i)a, 0);
|
||||
return (Packet4i)__lsx_vsllwil_wu_hu((__m128i)tmp1, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8us pcast<Packet16uc, Packet8us>(const Packet16uc& a) {
|
||||
return __lsx_vsllwil_hu_bu((__m128i)a, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8s pcast<Packet16uc, Packet8s>(const Packet16uc& a) {
|
||||
return (Packet8s)__lsx_vsllwil_hu_bu((__m128i)a, 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4f pcast<Packet8s, Packet4f>(const Packet8s& a) {
|
||||
Packet4i tmp1 = __lsx_vsllwil_w_h((__m128i)a, 0);
|
||||
return __lsx_vffint_s_w(tmp1);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2l pcast<Packet8s, Packet2l>(const Packet8s& a) {
|
||||
Packet4i tmp1 = __lsx_vsllwil_w_h((__m128i)a, 0);
|
||||
return __lsx_vsllwil_d_w((__m128i)tmp1, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2ul pcast<Packet8s, Packet2ul>(const Packet8s& a) {
|
||||
Packet4i tmp1 = __lsx_vsllwil_w_h((__m128i)a, 0);
|
||||
return (Packet2ul)__lsx_vsllwil_d_w((__m128i)tmp1, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4i pcast<Packet8s, Packet4i>(const Packet8s& a) {
|
||||
return __lsx_vsllwil_w_h((__m128i)a, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4ui pcast<Packet8s, Packet4ui>(const Packet8s& a) {
|
||||
return (Packet4ui)__lsx_vsllwil_w_h((__m128i)a, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16c pcast<Packet8s, Packet16c>(const Packet8s& a, const Packet8s& b) {
|
||||
return __lsx_vssrlni_b_h((__m128i)a, (__m128i)b, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16uc pcast<Packet8s, Packet16uc>(const Packet8s& a, const Packet8s& b) {
|
||||
return (Packet16uc)__lsx_vssrlni_b_h((__m128i)a, (__m128i)b, 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4f pcast<Packet8us, Packet4f>(const Packet8us& a) {
|
||||
Packet4ui tmp1 = __lsx_vsllwil_wu_hu((__m128i)a, 0);
|
||||
return __lsx_vffint_s_wu(tmp1);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2ul pcast<Packet8us, Packet2ul>(const Packet8us& a) {
|
||||
Packet4ui tmp1 = __lsx_vsllwil_wu_hu((__m128i)a, 0);
|
||||
return __lsx_vsllwil_du_wu((__m128i)tmp1, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2l pcast<Packet8us, Packet2l>(const Packet8us& a) {
|
||||
Packet4ui tmp1 = __lsx_vsllwil_wu_hu((__m128i)a, 0);
|
||||
return (Packet2l)__lsx_vsllwil_du_wu((__m128i)tmp1, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4ui pcast<Packet8us, Packet4ui>(const Packet8us& a) {
|
||||
return __lsx_vsllwil_wu_hu((__m128i)a, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4i pcast<Packet8us, Packet4i>(const Packet8us& a) {
|
||||
return (Packet4i)__lsx_vsllwil_wu_hu((__m128i)a, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16uc pcast<Packet8us, Packet16uc>(const Packet8us& a, const Packet8us& b) {
|
||||
return __lsx_vssrlni_bu_h((__m128i)a, (__m128i)b, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16c pcast<Packet8us, Packet16c>(const Packet8us& a, const Packet8us& b) {
|
||||
return (Packet16c)__lsx_vssrlni_bu_h((__m128i)a, (__m128i)b, 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4f pcast<Packet4i, Packet4f>(const Packet4i& a) {
|
||||
return __lsx_vffint_s_w(a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2l pcast<Packet4i, Packet2l>(const Packet4i& a) {
|
||||
return __lsx_vsllwil_d_w((__m128i)a, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2ul pcast<Packet4i, Packet2ul>(const Packet4i& a) {
|
||||
return (Packet2ul)__lsx_vsllwil_d_w((__m128i)a, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8s pcast<Packet4i, Packet8s>(const Packet4i& a, const Packet4i& b) {
|
||||
return __lsx_vssrlni_h_w((__m128i)a, (__m128i)b, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8us pcast<Packet4i, Packet8us>(const Packet4i& a, const Packet4i& b) {
|
||||
return (Packet8us)__lsx_vssrlni_h_w((__m128i)a, (__m128i)b, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16c pcast<Packet4i, Packet16c>(const Packet4i& a, const Packet4i& b, const Packet4i& c,
|
||||
const Packet4i& d) {
|
||||
Packet8s tmp1 = __lsx_vssrlni_h_w((__m128i)a, (__m128i)b, 0);
|
||||
Packet8s tmp2 = __lsx_vssrlni_h_w((__m128i)c, (__m128i)d, 0);
|
||||
return __lsx_vssrlni_b_h((__m128i)tmp1, (__m128i)tmp2, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16uc pcast<Packet4i, Packet16uc>(const Packet4i& a, const Packet4i& b, const Packet4i& c,
|
||||
const Packet4i& d) {
|
||||
Packet8s tmp1 = __lsx_vssrlni_h_w((__m128i)a, (__m128i)b, 0);
|
||||
Packet8s tmp2 = __lsx_vssrlni_h_w((__m128i)c, (__m128i)d, 0);
|
||||
return (Packet16uc)__lsx_vssrlni_b_h((__m128i)tmp1, (__m128i)tmp2, 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4f pcast<Packet4ui, Packet4f>(const Packet4ui& a) {
|
||||
return __lsx_vffint_s_wu(a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2ul pcast<Packet4ui, Packet2ul>(const Packet4ui& a) {
|
||||
return __lsx_vsllwil_du_wu((__m128i)a, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2l pcast<Packet4ui, Packet2l>(const Packet4ui& a) {
|
||||
return (Packet2l)__lsx_vsllwil_du_wu((__m128i)a, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8us pcast<Packet4ui, Packet8us>(const Packet4ui& a, const Packet4ui& b) {
|
||||
return __lsx_vssrlni_hu_w((__m128i)a, (__m128i)b, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8s pcast<Packet4ui, Packet8s>(const Packet4ui& a, const Packet4ui& b) {
|
||||
return (Packet8s)__lsx_vssrlni_hu_w((__m128i)a, (__m128i)b, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16uc pcast<Packet4ui, Packet16uc>(const Packet4ui& a, const Packet4ui& b, const Packet4ui& c,
|
||||
const Packet4ui& d) {
|
||||
Packet8us tmp1 = __lsx_vssrlni_hu_w((__m128i)a, (__m128i)b, 0);
|
||||
Packet8us tmp2 = __lsx_vssrlni_hu_w((__m128i)c, (__m128i)d, 0);
|
||||
return __lsx_vssrlni_bu_h((__m128i)tmp1, (__m128i)tmp2, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16c pcast<Packet4ui, Packet16c>(const Packet4ui& a, const Packet4ui& b, const Packet4ui& c,
|
||||
const Packet4ui& d) {
|
||||
Packet8us tmp1 = __lsx_vssrlni_hu_w((__m128i)a, (__m128i)b, 0);
|
||||
Packet8us tmp2 = __lsx_vssrlni_hu_w((__m128i)c, (__m128i)d, 0);
|
||||
return (Packet16c)__lsx_vssrlni_bu_h((__m128i)tmp1, (__m128i)tmp2, 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4f pcast<Packet2l, Packet4f>(const Packet2l& a, const Packet2l& b) {
|
||||
return __lsx_vffint_s_w(__lsx_vssrlni_w_d((__m128i)a, (__m128i)b, 0));
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4i pcast<Packet2l, Packet4i>(const Packet2l& a, const Packet2l& b) {
|
||||
return __lsx_vssrlni_w_d((__m128i)a, (__m128i)b, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4ui pcast<Packet2l, Packet4ui>(const Packet2l& a, const Packet2l& b) {
|
||||
return (Packet4ui)__lsx_vssrlni_w_d((__m128i)a, (__m128i)b, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8s pcast<Packet2l, Packet8s>(const Packet2l& a, const Packet2l& b, const Packet2l& c,
|
||||
const Packet2l& d) {
|
||||
Packet4i tmp1 = __lsx_vssrlni_w_d((__m128i)a, (__m128i)b, 0);
|
||||
Packet4i tmp2 = __lsx_vssrlni_w_d((__m128i)c, (__m128i)d, 0);
|
||||
return __lsx_vssrlni_h_w((__m128i)tmp1, (__m128i)tmp2, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8us pcast<Packet2l, Packet8us>(const Packet2l& a, const Packet2l& b, const Packet2l& c,
|
||||
const Packet2l& d) {
|
||||
Packet4i tmp1 = __lsx_vssrlni_w_d((__m128i)a, (__m128i)b, 0);
|
||||
Packet4i tmp2 = __lsx_vssrlni_w_d((__m128i)c, (__m128i)d, 0);
|
||||
return (Packet8us)__lsx_vssrlni_h_w((__m128i)tmp1, (__m128i)tmp2, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16c pcast<Packet2l, Packet16c>(const Packet2l& a, const Packet2l& b, const Packet2l& c,
|
||||
const Packet2l& d, const Packet2l& e, const Packet2l& f,
|
||||
const Packet2l& g, const Packet2l& h) {
|
||||
const Packet8s abcd = pcast<Packet2l, Packet8s>(a, b, c, d);
|
||||
const Packet8s efgh = pcast<Packet2l, Packet8s>(e, f, g, h);
|
||||
return __lsx_vssrlni_b_h((__m128i)abcd, (__m128i)efgh, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16uc pcast<Packet2l, Packet16uc>(const Packet2l& a, const Packet2l& b, const Packet2l& c,
|
||||
const Packet2l& d, const Packet2l& e, const Packet2l& f,
|
||||
const Packet2l& g, const Packet2l& h) {
|
||||
const Packet8us abcd = pcast<Packet2l, Packet8us>(a, b, c, d);
|
||||
const Packet8us efgh = pcast<Packet2l, Packet8us>(e, f, g, h);
|
||||
return __lsx_vssrlni_bu_h((__m128i)abcd, (__m128i)efgh, 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4f pcast<Packet2ul, Packet4f>(const Packet2ul& a, const Packet2ul& b) {
|
||||
return __lsx_vffint_s_wu(__lsx_vssrlni_w_d((__m128i)a, (__m128i)b, 0));
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4ui pcast<Packet2ul, Packet4ui>(const Packet2ul& a, const Packet2ul& b) {
|
||||
return __lsx_vssrlni_wu_d((__m128i)a, (__m128i)b, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4i pcast<Packet2ul, Packet4i>(const Packet2ul& a, const Packet2ul& b) {
|
||||
return (Packet4i)__lsx_vssrlni_wu_d((__m128i)a, (__m128i)b, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8us pcast<Packet2ul, Packet8us>(const Packet2ul& a, const Packet2ul& b, const Packet2ul& c,
|
||||
const Packet2ul& d) {
|
||||
Packet4ui tmp1 = __lsx_vssrlni_wu_d((__m128i)a, (__m128i)b, 0);
|
||||
Packet4ui tmp2 = __lsx_vssrlni_wu_d((__m128i)c, (__m128i)d, 0);
|
||||
return __lsx_vssrlni_hu_w((__m128i)tmp1, (__m128i)tmp2, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8s pcast<Packet2ul, Packet8s>(const Packet2ul& a, const Packet2ul& b, const Packet2ul& c,
|
||||
const Packet2ul& d) {
|
||||
Packet4ui tmp1 = __lsx_vssrlni_wu_d((__m128i)a, (__m128i)b, 0);
|
||||
Packet4ui tmp2 = __lsx_vssrlni_wu_d((__m128i)c, (__m128i)d, 0);
|
||||
return (Packet8s)__lsx_vssrlni_hu_w((__m128i)tmp1, (__m128i)tmp2, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16uc pcast<Packet2ul, Packet16uc>(const Packet2ul& a, const Packet2ul& b, const Packet2ul& c,
|
||||
const Packet2ul& d, const Packet2ul& e, const Packet2ul& f,
|
||||
const Packet2ul& g, const Packet2ul& h) {
|
||||
const Packet8s abcd = pcast<Packet2ul, Packet8s>(a, b, c, d);
|
||||
const Packet8s efgh = pcast<Packet2ul, Packet8s>(e, f, g, h);
|
||||
return __lsx_vssrlni_b_h((__m128i)abcd, (__m128i)efgh, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16c pcast<Packet2ul, Packet16c>(const Packet2ul& a, const Packet2ul& b, const Packet2ul& c,
|
||||
const Packet2ul& d, const Packet2ul& e, const Packet2ul& f,
|
||||
const Packet2ul& g, const Packet2ul& h) {
|
||||
const Packet8us abcd = pcast<Packet2ul, Packet8us>(a, b, c, d);
|
||||
const Packet8us efgh = pcast<Packet2ul, Packet8us>(e, f, g, h);
|
||||
return __lsx_vssrlni_bu_h((__m128i)abcd, (__m128i)efgh, 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4f pcast<Packet2d, Packet4f>(const Packet2d& a, const Packet2d& b) {
|
||||
return __lsx_vfcvt_s_d(b, a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2l pcast<Packet2d, Packet2l>(const Packet2d& a) {
|
||||
return __lsx_vftint_l_d(a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2ul pcast<Packet2d, Packet2ul>(const Packet2d& a) {
|
||||
return __lsx_vftint_lu_d(a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4i pcast<Packet2d, Packet4i>(const Packet2d& a, const Packet2d& b) {
|
||||
return __lsx_vssrlni_w_d(__lsx_vftint_l_d(a), __lsx_vftint_l_d(b), 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet4ui pcast<Packet2d, Packet4ui>(const Packet2d& a, const Packet2d& b) {
|
||||
return __lsx_vssrlni_wu_d(__lsx_vftint_lu_d(a), __lsx_vftint_lu_d(b), 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8s pcast<Packet2d, Packet8s>(const Packet2d& a, const Packet2d& b, const Packet2d& c,
|
||||
const Packet2d& d) {
|
||||
Packet4i tmp1 = __lsx_vssrlni_w_d(__lsx_vftint_l_d(a), __lsx_vftint_l_d(b), 0);
|
||||
Packet4i tmp2 = __lsx_vssrlni_w_d(__lsx_vftint_l_d(c), __lsx_vftint_l_d(d), 0);
|
||||
return __lsx_vssrlni_h_w((__m128i)tmp1, (__m128i)tmp2, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet8us pcast<Packet2d, Packet8us>(const Packet2d& a, const Packet2d& b, const Packet2d& c,
|
||||
const Packet2d& d) {
|
||||
Packet4ui tmp1 = __lsx_vssrlni_wu_d(__lsx_vftint_lu_d(a), __lsx_vftint_lu_d(b), 0);
|
||||
Packet4ui tmp2 = __lsx_vssrlni_wu_d(__lsx_vftint_lu_d(c), __lsx_vftint_lu_d(d), 0);
|
||||
return __lsx_vssrlni_hu_w((__m128i)tmp1, (__m128i)tmp2, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16c pcast<Packet2d, Packet16c>(const Packet2d& a, const Packet2d& b, const Packet2d& c,
|
||||
const Packet2d& d, const Packet2d& e, const Packet2d& f,
|
||||
const Packet2d& g, const Packet2d& h) {
|
||||
const Packet8s abcd = pcast<Packet2d, Packet8s>(a, b, c, d);
|
||||
const Packet8s efgh = pcast<Packet2d, Packet8s>(e, f, g, h);
|
||||
return __lsx_vssrlni_b_h((__m128i)abcd, (__m128i)efgh, 0);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet16uc pcast<Packet2d, Packet16uc>(const Packet2d& a, const Packet2d& b, const Packet2d& c,
|
||||
const Packet2d& d, const Packet2d& e, const Packet2d& f,
|
||||
const Packet2d& g, const Packet2d& h) {
|
||||
const Packet8us abcd = pcast<Packet2d, Packet8us>(a, b, c, d);
|
||||
const Packet8us efgh = pcast<Packet2d, Packet8us>(e, f, g, h);
|
||||
return __lsx_vssrlni_bu_h((__m128i)abcd, (__m128i)efgh, 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2d pcast<Packet4f, Packet2d>(const Packet4f& a) {
|
||||
return __lsx_vfcvtl_d_s(a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2d pcast<Packet16c, Packet2d>(const Packet16c& a) {
|
||||
Packet8s tmp1 = __lsx_vsllwil_h_b((__m128i)a, 0);
|
||||
Packet4i tmp2 = __lsx_vsllwil_w_h((__m128i)tmp1, 0);
|
||||
return __lsx_vffint_d_l(__lsx_vsllwil_d_w((__m128i)tmp2, 0));
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2d pcast<Packet16uc, Packet2d>(const Packet16uc& a) {
|
||||
Packet8us tmp1 = __lsx_vsllwil_hu_bu((__m128i)a, 0);
|
||||
Packet4ui tmp2 = __lsx_vsllwil_wu_hu((__m128i)tmp1, 0);
|
||||
return __lsx_vffint_d_lu(__lsx_vsllwil_du_wu((__m128i)tmp2, 0));
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2d pcast<Packet8s, Packet2d>(const Packet8s& a) {
|
||||
Packet4i tmp = __lsx_vsllwil_w_h((__m128i)a, 0);
|
||||
return __lsx_vffint_d_l(__lsx_vsllwil_d_w((__m128i)tmp, 0));
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2d pcast<Packet8us, Packet2d>(const Packet8us& a) {
|
||||
Packet4ui tmp = __lsx_vsllwil_wu_hu((__m128i)a, 0);
|
||||
return __lsx_vffint_d_lu(__lsx_vsllwil_du_wu((__m128i)tmp, 0));
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2d pcast<Packet4i, Packet2d>(const Packet4i& a) {
|
||||
return __lsx_vffint_d_l(__lsx_vsllwil_d_w((__m128i)a, 0));
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2d pcast<Packet4ui, Packet2d>(const Packet4ui& a) {
|
||||
return __lsx_vffint_d_lu(__lsx_vsllwil_du_wu((__m128i)a, 0));
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2d pcast<Packet2l, Packet2d>(const Packet2l& a) {
|
||||
return __lsx_vffint_d_l(a);
|
||||
}
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE Packet2d pcast<Packet2ul, Packet2d>(const Packet2ul& a) {
|
||||
return __lsx_vffint_d_lu(a);
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_TYPE_CASTING_LSX_H
|
||||
@@ -0,0 +1,57 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_NEON_UNARY_FUNCTORS_H
|
||||
#define EIGEN_NEON_UNARY_FUNCTORS_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "../../InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
#if EIGEN_HAS_ARM64_FP16_VECTOR_ARITHMETIC
|
||||
/** \internal
|
||||
* \brief Template specialization of the logistic function for Eigen::half.
|
||||
*/
|
||||
template <>
|
||||
struct scalar_logistic_op<Eigen::half> {
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Eigen::half operator()(const Eigen::half& x) const {
|
||||
// Convert to float and call scalar_logistic_op<float>.
|
||||
const scalar_logistic_op<float> float_op;
|
||||
return Eigen::half(float_op(float(x)));
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Eigen::half packetOp(const Eigen::half& x) const { return this->operator()(x); }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet4hf packetOp(const Packet4hf& x) const {
|
||||
const scalar_logistic_op<float> float_op;
|
||||
return vcvt_f16_f32(float_op.packetOp(vcvt_f32_f16(x)));
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Packet8hf packetOp(const Packet8hf& x) const {
|
||||
const scalar_logistic_op<float> float_op;
|
||||
return vcombine_f16(vcvt_f16_f32(float_op.packetOp(vcvt_f32_f16(vget_low_f16(x)))),
|
||||
vcvt_f16_f32(float_op.packetOp(vcvt_high_f32_f16(x))));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct functor_traits<scalar_logistic_op<Eigen::half>> {
|
||||
enum {
|
||||
Cost = functor_traits<scalar_logistic_op<float>>::Cost,
|
||||
PacketAccess = functor_traits<scalar_logistic_op<float>>::PacketAccess,
|
||||
};
|
||||
};
|
||||
#endif // EIGEN_HAS_ARM64_FP16_VECTOR_ARITHMETIC
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_NEON_UNARY_FUNCTORS_H
|
||||
@@ -0,0 +1,324 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2025 Charlie Schlosser <cs.schlosser@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_REDUCTIONS_SSE_H
|
||||
#define EIGEN_REDUCTIONS_SSE_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "../../InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename Packet>
|
||||
struct sse_add_wrapper {
|
||||
static EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) { return padd<Packet>(a, b); }
|
||||
};
|
||||
|
||||
template <typename Packet>
|
||||
struct sse_mul_wrapper {
|
||||
static EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) { return pmul<Packet>(a, b); }
|
||||
};
|
||||
|
||||
template <typename Packet>
|
||||
struct sse_min_wrapper {
|
||||
static EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) { return pmin<Packet>(a, b); }
|
||||
};
|
||||
|
||||
template <int NaNPropagation, typename Packet>
|
||||
struct sse_min_prop_wrapper {
|
||||
static EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) {
|
||||
return pmin<NaNPropagation, Packet>(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Packet>
|
||||
struct sse_max_wrapper {
|
||||
static EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) { return pmax<Packet>(a, b); }
|
||||
};
|
||||
|
||||
template <int NaNPropagation, typename Packet>
|
||||
struct sse_max_prop_wrapper {
|
||||
static EIGEN_STRONG_INLINE Packet packetOp(const Packet& a, const Packet& b) {
|
||||
return pmax<NaNPropagation, Packet>(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Packet, typename Op>
|
||||
struct sse_predux_common;
|
||||
|
||||
template <typename Packet>
|
||||
struct sse_predux_impl : sse_predux_common<Packet, sse_add_wrapper<Packet>> {};
|
||||
|
||||
template <typename Packet>
|
||||
struct sse_predux_mul_impl : sse_predux_common<Packet, sse_mul_wrapper<Packet>> {};
|
||||
|
||||
template <typename Packet>
|
||||
struct sse_predux_min_impl : sse_predux_common<Packet, sse_min_wrapper<Packet>> {};
|
||||
|
||||
template <int NaNPropagation, typename Packet>
|
||||
struct sse_predux_min_prop_impl : sse_predux_common<Packet, sse_min_prop_wrapper<NaNPropagation, Packet>> {};
|
||||
|
||||
template <typename Packet>
|
||||
struct sse_predux_max_impl : sse_predux_common<Packet, sse_max_wrapper<Packet>> {};
|
||||
|
||||
template <int NaNPropagation, typename Packet>
|
||||
struct sse_predux_max_prop_impl : sse_predux_common<Packet, sse_max_prop_wrapper<NaNPropagation, Packet>> {};
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet16b -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux(const Packet16b& a) {
|
||||
Packet4i tmp = _mm_or_si128(a, _mm_unpackhi_epi64(a, a));
|
||||
return (pfirst(tmp) != 0) || (pfirst<Packet4i>(_mm_shuffle_epi32(tmp, 1)) != 0);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_mul(const Packet16b& a) {
|
||||
Packet4i tmp = _mm_and_si128(a, _mm_unpackhi_epi64(a, a));
|
||||
return ((pfirst<Packet4i>(tmp) == 0x01010101) && (pfirst<Packet4i>(_mm_shuffle_epi32(tmp, 1)) == 0x01010101));
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_min(const Packet16b& a) {
|
||||
return predux_mul(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_max(const Packet16b& a) {
|
||||
return predux(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet16b& a) {
|
||||
return predux(a);
|
||||
}
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet4i -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <typename Op>
|
||||
struct sse_predux_common<Packet4i, Op> {
|
||||
static EIGEN_STRONG_INLINE int run(const Packet4i& a) {
|
||||
Packet4i tmp;
|
||||
tmp = Op::packetOp(a, _mm_shuffle_epi32(a, _MM_SHUFFLE(0, 1, 2, 3)));
|
||||
tmp = Op::packetOp(tmp, _mm_unpackhi_epi32(tmp, tmp));
|
||||
return _mm_cvtsi128_si32(tmp);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int predux(const Packet4i& a) {
|
||||
return sse_predux_impl<Packet4i>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int predux_mul(const Packet4i& a) {
|
||||
return sse_predux_mul_impl<Packet4i>::run(a);
|
||||
}
|
||||
|
||||
#ifdef EIGEN_VECTORIZE_SSE4_1
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int predux_min(const Packet4i& a) {
|
||||
return sse_predux_min_impl<Packet4i>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int predux_max(const Packet4i& a) {
|
||||
return sse_predux_max_impl<Packet4i>::run(a);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet4i& a) {
|
||||
return _mm_movemask_ps(_mm_castsi128_ps(a)) != 0x0;
|
||||
}
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet4ui -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <typename Op>
|
||||
struct sse_predux_common<Packet4ui, Op> {
|
||||
static EIGEN_STRONG_INLINE uint32_t run(const Packet4ui& a) {
|
||||
Packet4ui tmp;
|
||||
tmp = Op::packetOp(a, _mm_shuffle_epi32(a, _MM_SHUFFLE(0, 1, 2, 3)));
|
||||
tmp = Op::packetOp(tmp, _mm_unpackhi_epi32(tmp, tmp));
|
||||
return static_cast<uint32_t>(_mm_cvtsi128_si32(tmp));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE uint32_t predux(const Packet4ui& a) {
|
||||
return sse_predux_impl<Packet4ui>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE uint32_t predux_mul(const Packet4ui& a) {
|
||||
return sse_predux_mul_impl<Packet4ui>::run(a);
|
||||
}
|
||||
|
||||
#ifdef EIGEN_VECTORIZE_SSE4_1
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE uint32_t predux_min(const Packet4ui& a) {
|
||||
return sse_predux_min_impl<Packet4ui>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE uint32_t predux_max(const Packet4ui& a) {
|
||||
return sse_predux_max_impl<Packet4ui>::run(a);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet4ui& a) {
|
||||
return _mm_movemask_ps(_mm_castsi128_ps(a)) != 0x0;
|
||||
}
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet2l -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <typename Op>
|
||||
struct sse_predux_common<Packet2l, Op> {
|
||||
static EIGEN_STRONG_INLINE int64_t run(const Packet2l& a) {
|
||||
Packet2l tmp;
|
||||
tmp = Op::packetOp(a, _mm_unpackhi_epi64(a, a));
|
||||
return pfirst(tmp);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE int64_t predux(const Packet2l& a) {
|
||||
return sse_predux_impl<Packet2l>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet2l& a) {
|
||||
return _mm_movemask_pd(_mm_castsi128_pd(a)) != 0x0;
|
||||
}
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet4f -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <typename Op>
|
||||
struct sse_predux_common<Packet4f, Op> {
|
||||
static EIGEN_STRONG_INLINE float run(const Packet4f& a) {
|
||||
Packet4f tmp;
|
||||
tmp = Op::packetOp(a, _mm_movehl_ps(a, a));
|
||||
#ifdef EIGEN_VECTORIZE_SSE3
|
||||
tmp = Op::packetOp(tmp, _mm_movehdup_ps(tmp));
|
||||
#else
|
||||
tmp = Op::packetOp(tmp, _mm_shuffle_ps(tmp, tmp, 1));
|
||||
#endif
|
||||
return _mm_cvtss_f32(tmp);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux(const Packet4f& a) {
|
||||
return sse_predux_impl<Packet4f>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_mul(const Packet4f& a) {
|
||||
return sse_predux_mul_impl<Packet4f>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_min(const Packet4f& a) {
|
||||
return sse_predux_min_impl<Packet4f>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_min<PropagateNumbers>(const Packet4f& a) {
|
||||
return sse_predux_min_prop_impl<PropagateNumbers, Packet4f>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_min<PropagateNaN>(const Packet4f& a) {
|
||||
return sse_predux_min_prop_impl<PropagateNaN, Packet4f>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_max(const Packet4f& a) {
|
||||
return sse_predux_max_impl<Packet4f>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_max<PropagateNumbers>(const Packet4f& a) {
|
||||
return sse_predux_max_prop_impl<PropagateNumbers, Packet4f>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE float predux_max<PropagateNaN>(const Packet4f& a) {
|
||||
return sse_predux_max_prop_impl<PropagateNaN, Packet4f>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet4f& a) {
|
||||
return _mm_movemask_ps(a) != 0x0;
|
||||
}
|
||||
|
||||
/* -- -- -- -- -- -- -- -- -- -- -- -- Packet2d -- -- -- -- -- -- -- -- -- -- -- -- */
|
||||
|
||||
template <typename Op>
|
||||
struct sse_predux_common<Packet2d, Op> {
|
||||
static EIGEN_STRONG_INLINE double run(const Packet2d& a) {
|
||||
Packet2d tmp;
|
||||
tmp = Op::packetOp(a, _mm_unpackhi_pd(a, a));
|
||||
return _mm_cvtsd_f64(tmp);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux(const Packet2d& a) {
|
||||
return sse_predux_impl<Packet2d>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_mul(const Packet2d& a) {
|
||||
return sse_predux_mul_impl<Packet2d>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_min(const Packet2d& a) {
|
||||
return sse_predux_min_impl<Packet2d>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_min<PropagateNumbers>(const Packet2d& a) {
|
||||
return sse_predux_min_prop_impl<PropagateNumbers, Packet2d>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_min<PropagateNaN>(const Packet2d& a) {
|
||||
return sse_predux_min_prop_impl<PropagateNaN, Packet2d>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_max(const Packet2d& a) {
|
||||
return sse_predux_max_impl<Packet2d>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_max<PropagateNumbers>(const Packet2d& a) {
|
||||
return sse_predux_max_prop_impl<PropagateNumbers, Packet2d>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE double predux_max<PropagateNaN>(const Packet2d& a) {
|
||||
return sse_predux_max_prop_impl<PropagateNaN, Packet2d>::run(a);
|
||||
}
|
||||
|
||||
template <>
|
||||
EIGEN_STRONG_INLINE bool predux_any(const Packet2d& a) {
|
||||
return _mm_movemask_pd(a) != 0x0;
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_REDUCTIONS_SSE_H
|
||||
@@ -0,0 +1,158 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2022, The Eigen authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_CORE_UTIL_ASSERT_H
|
||||
#define EIGEN_CORE_UTIL_ASSERT_H
|
||||
|
||||
// Eigen custom assert function.
|
||||
//
|
||||
// The combination of Eigen's relative includes and cassert's `assert` function
|
||||
// (or any usage of the __FILE__ macro) can lead to ODR issues:
|
||||
// a header included using different relative paths in two different TUs will
|
||||
// have two different token-for-token definitions, since __FILE__ is expanded
|
||||
// as an in-line string with different values. Normally this would be
|
||||
// harmless - the linker would just choose one definition. However, it breaks
|
||||
// with C++20 modules when functions in different modules have different
|
||||
// definitions.
|
||||
//
|
||||
// To get around this, we need to use __builtin_FILE() when available, which is
|
||||
// considered a single token, and thus satisfies the ODR.
|
||||
|
||||
// Only define eigen_plain_assert if we are debugging, and either
|
||||
// - we are not compiling for GPU, or
|
||||
// - gpu debugging is enabled.
|
||||
#if !defined(EIGEN_NO_DEBUG) && (!defined(EIGEN_GPU_COMPILE_PHASE) || !defined(EIGEN_NO_DEBUG_GPU))
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#ifndef EIGEN_USE_CUSTOM_PLAIN_ASSERT
|
||||
// Disable new custom asserts by default for now.
|
||||
#define EIGEN_USE_CUSTOM_PLAIN_ASSERT 0
|
||||
#endif
|
||||
|
||||
#if EIGEN_USE_CUSTOM_PLAIN_ASSERT
|
||||
|
||||
#ifndef EIGEN_HAS_BUILTIN_FILE
|
||||
// Clang can check if __builtin_FILE() is supported.
|
||||
// GCC > 5, MSVC 2019 14.26 (1926) all have __builtin_FILE().
|
||||
//
|
||||
// For NVCC, it's more complicated. Through trial-and-error:
|
||||
// - nvcc+gcc supports __builtin_FILE() on host, and on device after CUDA 11.
|
||||
// - nvcc+msvc supports __builtin_FILE() only after CUDA 11.
|
||||
#if (EIGEN_HAS_BUILTIN(__builtin_FILE) && (EIGEN_COMP_CLANG || !defined(EIGEN_CUDA_ARCH))) || \
|
||||
(EIGEN_GNUC_STRICT_AT_LEAST(5, 0, 0) && (EIGEN_COMP_NVCC >= 110000 || !defined(EIGEN_CUDA_ARCH))) || \
|
||||
(EIGEN_COMP_MSVC >= 1926 && (!EIGEN_COMP_NVCC || EIGEN_COMP_NVCC >= 110000))
|
||||
#define EIGEN_HAS_BUILTIN_FILE 1
|
||||
#else
|
||||
#define EIGEN_HAS_BUILTIN_FILE 0
|
||||
#endif
|
||||
#endif // EIGEN_HAS_BUILTIN_FILE
|
||||
|
||||
#if EIGEN_HAS_BUILTIN_FILE
|
||||
#define EIGEN_BUILTIN_FILE __builtin_FILE()
|
||||
#define EIGEN_BUILTIN_LINE __builtin_LINE()
|
||||
#else
|
||||
// Default (potentially unsafe) values.
|
||||
#define EIGEN_BUILTIN_FILE __FILE__
|
||||
#define EIGEN_BUILTIN_LINE __LINE__
|
||||
#endif
|
||||
|
||||
// Use __PRETTY_FUNCTION__ when available, since it is more descriptive, as
|
||||
// __builtin_FUNCTION() only returns the undecorated function name.
|
||||
// This should still be okay ODR-wise since it is a compiler-specific fixed
|
||||
// value. Mixing compilers will likely lead to ODR violations anyways.
|
||||
#if EIGEN_COMP_MSVC
|
||||
#define EIGEN_BUILTIN_FUNCTION __FUNCSIG__
|
||||
#elif EIGEN_COMP_GNUC
|
||||
#define EIGEN_BUILTIN_FUNCTION __PRETTY_FUNCTION__
|
||||
#else
|
||||
#define EIGEN_BUILTIN_FUNCTION __func__
|
||||
#endif
|
||||
|
||||
namespace Eigen {
|
||||
namespace internal {
|
||||
|
||||
// Generic default assert handler.
|
||||
template <typename EnableIf = void, typename... EmptyArgs>
|
||||
struct assert_handler_impl {
|
||||
EIGEN_DEVICE_FUNC EIGEN_DONT_INLINE static inline void run(const char* expression, const char* file, unsigned line,
|
||||
const char* function) {
|
||||
#ifdef EIGEN_GPU_COMPILE_PHASE
|
||||
// GPU device code doesn't allow stderr or abort, so use printf and raise an
|
||||
// illegal instruction exception to trigger a kernel failure.
|
||||
#ifndef EIGEN_NO_IO
|
||||
printf("Assertion failed at %s:%u in %s: %s\n", file == nullptr ? "<file>" : file, line,
|
||||
function == nullptr ? "<function>" : function, expression);
|
||||
#endif
|
||||
__trap();
|
||||
|
||||
#else // EIGEN_GPU_COMPILE_PHASE
|
||||
|
||||
// Print to stderr and abort, as specified in <cassert>.
|
||||
#ifndef EIGEN_NO_IO
|
||||
fprintf(stderr, "Assertion failed at %s:%u in %s: %s\n", file == nullptr ? "<file>" : file, line,
|
||||
function == nullptr ? "<function>" : function, expression);
|
||||
#endif
|
||||
std::abort();
|
||||
|
||||
#endif // EIGEN_GPU_COMPILE_PHASE
|
||||
}
|
||||
};
|
||||
|
||||
// Use POSIX __assert_fail handler when available.
|
||||
//
|
||||
// This allows us to integrate with systems that have custom handlers.
|
||||
//
|
||||
// NOTE: this handler is not always available on all POSIX systems (otherwise
|
||||
// we could simply test for __unix__ or similar). The handler function name
|
||||
// seems to depend on the specific toolchain implementation, and differs between
|
||||
// compilers, platforms, OSes, etc. Hence, we detect support via SFINAE.
|
||||
template <typename... EmptyArgs>
|
||||
struct assert_handler_impl<void_t<decltype(__assert_fail((const char*)nullptr, // expression
|
||||
(const char*)nullptr, // file
|
||||
0, // line
|
||||
(const char*)nullptr, // function
|
||||
std::declval<EmptyArgs>()... // Empty substitution required
|
||||
// for SFINAE.
|
||||
))>,
|
||||
EmptyArgs...> {
|
||||
EIGEN_DEVICE_FUNC EIGEN_DONT_INLINE static inline void run(const char* expression, const char* file, unsigned line,
|
||||
const char* function) {
|
||||
// GCC requires this call to be dependent on the template parameters.
|
||||
__assert_fail(expression, file, line, function, std::declval<EmptyArgs>()...);
|
||||
}
|
||||
};
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_DONT_INLINE inline void __assert_handler(const char* expression, const char* file,
|
||||
unsigned line, const char* function) {
|
||||
assert_handler_impl<>::run(expression, file, line, function);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Eigen
|
||||
|
||||
#define eigen_plain_assert(expression) \
|
||||
(EIGEN_PREDICT_FALSE(!(expression)) ? Eigen::internal::__assert_handler(#expression, EIGEN_BUILTIN_FILE, \
|
||||
EIGEN_BUILTIN_LINE, EIGEN_BUILTIN_FUNCTION) \
|
||||
: (void)0)
|
||||
|
||||
#else // EIGEN_USE_CUSTOM_PLAIN_ASSERT
|
||||
|
||||
// Use regular assert.
|
||||
#define eigen_plain_assert(condition) assert(condition)
|
||||
|
||||
#endif // EIGEN_USE_CUSTOM_PLAIN_ASSERT
|
||||
|
||||
#else // EIGEN_NO_DEBUG
|
||||
|
||||
#define eigen_plain_assert(condition) ((void)0)
|
||||
|
||||
#endif // EIGEN_NO_DEBUG
|
||||
|
||||
#endif // EIGEN_CORE_UTIL_ASSERT_H
|
||||
@@ -0,0 +1,270 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_EMULATE_ARRAY_H
|
||||
#define EIGEN_EMULATE_ARRAY_H
|
||||
|
||||
// CUDA doesn't support the STL containers, so we use our own instead.
|
||||
#if defined(EIGEN_GPUCC) || defined(EIGEN_AVOID_STL_ARRAY)
|
||||
|
||||
namespace Eigen {
|
||||
template <typename T, size_t n>
|
||||
class array {
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef T* iterator;
|
||||
typedef const T* const_iterator;
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE iterator begin() { return values; }
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const_iterator begin() const { return values; }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE iterator end() { return values + n; }
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const_iterator end() const { return values + n; }
|
||||
|
||||
typedef std::reverse_iterator<iterator> reverse_iterator;
|
||||
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
|
||||
EIGEN_STRONG_INLINE reverse_iterator rbegin() { return reverse_iterator(end()); }
|
||||
EIGEN_STRONG_INLINE const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
|
||||
|
||||
EIGEN_STRONG_INLINE reverse_iterator rend() { return reverse_iterator(begin()); }
|
||||
EIGEN_STRONG_INLINE const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T& operator[](size_t index) {
|
||||
eigen_internal_assert(index < size());
|
||||
return values[index];
|
||||
}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const T& operator[](size_t index) const {
|
||||
eigen_internal_assert(index < size());
|
||||
return values[index];
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T& at(size_t index) {
|
||||
eigen_assert(index < size());
|
||||
return values[index];
|
||||
}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const T& at(size_t index) const {
|
||||
eigen_assert(index < size());
|
||||
return values[index];
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T& front() { return values[0]; }
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const T& front() const { return values[0]; }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T& back() { return values[n - 1]; }
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const T& back() const { return values[n - 1]; }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE static std::size_t size() { return n; }
|
||||
|
||||
T values[n];
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE array() {}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE array(const T& v) {
|
||||
EIGEN_STATIC_ASSERT(n == 1, YOU_MADE_A_PROGRAMMING_MISTAKE)
|
||||
values[0] = v;
|
||||
}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE array(const T& v1, const T& v2) {
|
||||
EIGEN_STATIC_ASSERT(n == 2, YOU_MADE_A_PROGRAMMING_MISTAKE)
|
||||
values[0] = v1;
|
||||
values[1] = v2;
|
||||
}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE array(const T& v1, const T& v2, const T& v3) {
|
||||
EIGEN_STATIC_ASSERT(n == 3, YOU_MADE_A_PROGRAMMING_MISTAKE)
|
||||
values[0] = v1;
|
||||
values[1] = v2;
|
||||
values[2] = v3;
|
||||
}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE array(const T& v1, const T& v2, const T& v3, const T& v4) {
|
||||
EIGEN_STATIC_ASSERT(n == 4, YOU_MADE_A_PROGRAMMING_MISTAKE)
|
||||
values[0] = v1;
|
||||
values[1] = v2;
|
||||
values[2] = v3;
|
||||
values[3] = v4;
|
||||
}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE array(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) {
|
||||
EIGEN_STATIC_ASSERT(n == 5, YOU_MADE_A_PROGRAMMING_MISTAKE)
|
||||
values[0] = v1;
|
||||
values[1] = v2;
|
||||
values[2] = v3;
|
||||
values[3] = v4;
|
||||
values[4] = v5;
|
||||
}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE array(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5,
|
||||
const T& v6) {
|
||||
EIGEN_STATIC_ASSERT(n == 6, YOU_MADE_A_PROGRAMMING_MISTAKE)
|
||||
values[0] = v1;
|
||||
values[1] = v2;
|
||||
values[2] = v3;
|
||||
values[3] = v4;
|
||||
values[4] = v5;
|
||||
values[5] = v6;
|
||||
}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE array(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5,
|
||||
const T& v6, const T& v7) {
|
||||
EIGEN_STATIC_ASSERT(n == 7, YOU_MADE_A_PROGRAMMING_MISTAKE)
|
||||
values[0] = v1;
|
||||
values[1] = v2;
|
||||
values[2] = v3;
|
||||
values[3] = v4;
|
||||
values[4] = v5;
|
||||
values[5] = v6;
|
||||
values[6] = v7;
|
||||
}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE array(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5,
|
||||
const T& v6, const T& v7, const T& v8) {
|
||||
EIGEN_STATIC_ASSERT(n == 8, YOU_MADE_A_PROGRAMMING_MISTAKE)
|
||||
values[0] = v1;
|
||||
values[1] = v2;
|
||||
values[2] = v3;
|
||||
values[3] = v4;
|
||||
values[4] = v5;
|
||||
values[5] = v6;
|
||||
values[6] = v7;
|
||||
values[7] = v8;
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE array(std::initializer_list<T> l) {
|
||||
eigen_assert(l.size() == n);
|
||||
internal::smart_copy(l.begin(), l.end(), values);
|
||||
}
|
||||
};
|
||||
|
||||
// Specialize array for zero size
|
||||
template <typename T>
|
||||
class array<T, 0> {
|
||||
public:
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T& operator[](size_t) {
|
||||
eigen_assert(false && "Can't index a zero size array");
|
||||
return dummy;
|
||||
}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const T& operator[](size_t) const {
|
||||
eigen_assert(false && "Can't index a zero size array");
|
||||
return dummy;
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T& front() {
|
||||
eigen_assert(false && "Can't index a zero size array");
|
||||
return dummy;
|
||||
}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const T& front() const {
|
||||
eigen_assert(false && "Can't index a zero size array");
|
||||
return dummy;
|
||||
}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T& back() {
|
||||
eigen_assert(false && "Can't index a zero size array");
|
||||
return dummy;
|
||||
}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const T& back() const {
|
||||
eigen_assert(false && "Can't index a zero size array");
|
||||
return dummy;
|
||||
}
|
||||
|
||||
static EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE std::size_t size() { return 0; }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE array() : dummy() {}
|
||||
|
||||
EIGEN_DEVICE_FUNC array(std::initializer_list<T> l) : dummy() {
|
||||
EIGEN_UNUSED_VARIABLE(l);
|
||||
eigen_assert(l.size() == 0);
|
||||
}
|
||||
|
||||
private:
|
||||
T dummy;
|
||||
};
|
||||
|
||||
// Comparison operator
|
||||
// Todo: implement !=, <, <=, >, and >=
|
||||
template <class T, std::size_t N>
|
||||
EIGEN_DEVICE_FUNC bool operator==(const array<T, N>& lhs, const array<T, N>& rhs) {
|
||||
for (std::size_t i = 0; i < N; ++i) {
|
||||
if (lhs[i] != rhs[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
template <std::size_t I_, class T, std::size_t N>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T& array_get(array<T, N>& a) {
|
||||
return a[I_];
|
||||
}
|
||||
template <std::size_t I_, class T, std::size_t N>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const T& array_get(const array<T, N>& a) {
|
||||
return a[I_];
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
struct array_size<array<T, N> > {
|
||||
static constexpr Index value = N;
|
||||
};
|
||||
template <class T, std::size_t N>
|
||||
struct array_size<array<T, N>&> {
|
||||
static constexpr Index value = N;
|
||||
};
|
||||
template <class T, std::size_t N>
|
||||
struct array_size<const array<T, N> > {
|
||||
static constexpr Index value = N;
|
||||
};
|
||||
template <class T, std::size_t N>
|
||||
struct array_size<const array<T, N>&> {
|
||||
static constexpr Index value = N;
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Eigen
|
||||
|
||||
#else
|
||||
|
||||
// The compiler supports c++11, and we're not targeting cuda: use std::array as Eigen::array
|
||||
#include <array>
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
using array = std::array<T, N>;
|
||||
|
||||
namespace internal {
|
||||
/* std::get is only constexpr in C++14, not yet in C++11
|
||||
* - libstdc++ from version 4.7 onwards has it nevertheless,
|
||||
* so use that
|
||||
* - libstdc++ older versions: use _M_instance directly
|
||||
* - libc++ all versions so far: use __elems_ directly
|
||||
* - all other libs: use std::get to be portable, but
|
||||
* this may not be constexpr
|
||||
*/
|
||||
#if defined(__GLIBCXX__) && __GLIBCXX__ < 20120322
|
||||
#define STD_GET_ARR_HACK a._M_instance[I_]
|
||||
#elif defined(_LIBCPP_VERSION)
|
||||
#define STD_GET_ARR_HACK a.__elems_[I_]
|
||||
#else
|
||||
#define STD_GET_ARR_HACK std::template get<I_, T, N>(a)
|
||||
#endif
|
||||
|
||||
template <std::size_t I_, class T, std::size_t N>
|
||||
constexpr T& array_get(std::array<T, N>& a) {
|
||||
return (T&)STD_GET_ARR_HACK;
|
||||
}
|
||||
template <std::size_t I_, class T, std::size_t N>
|
||||
constexpr T&& array_get(std::array<T, N>&& a) {
|
||||
return (T&&)STD_GET_ARR_HACK;
|
||||
}
|
||||
template <std::size_t I_, class T, std::size_t N>
|
||||
constexpr T const& array_get(std::array<T, N> const& a) {
|
||||
return (T const&)STD_GET_ARR_HACK;
|
||||
}
|
||||
|
||||
#undef STD_GET_ARR_HACK
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif
|
||||
|
||||
#endif // EIGEN_EMULATE_ARRAY_H
|
||||
@@ -0,0 +1,101 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
// Copyright (C) 2018 Deven Desai <deven.desai.amd@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#if defined(EIGEN_USE_GPU) && !defined(EIGEN_CORE_GPU_HIP_CUDA_DEFINES_H)
|
||||
#define EIGEN_CXX11_TENSOR_GPU_HIP_CUDA_DEFINES_H
|
||||
|
||||
// Note that we are using EIGEN_USE_HIP here instead of EIGEN_HIPCC...this is by design
|
||||
// There is code in the Tensorflow codebase that will define EIGEN_USE_GPU, but
|
||||
// for some reason gets sent to the gcc/host compiler instead of the gpu/nvcc/hipcc compiler
|
||||
// When compiling such files, gcc will end up trying to pick up the CUDA headers by
|
||||
// default (see the code within "unsupported/Eigen/CXX11/Tensor" that is guarded by EIGEN_USE_GPU)
|
||||
// This will obviously not work when trying to compile tensorflow on a system with no CUDA
|
||||
// To work around this issue for HIP systems (and leave the default behaviour intact), the
|
||||
// HIP tensorflow build defines EIGEN_USE_HIP when compiling all source files, and
|
||||
// "unsupported/Eigen/CXX11/Tensor" has been updated to use HIP header when EIGEN_USE_HIP is
|
||||
// defined. In continuation of that requirement, the guard here needs to be EIGEN_USE_HIP as well
|
||||
|
||||
#if defined(EIGEN_USE_HIP)
|
||||
|
||||
#define gpuStream_t hipStream_t
|
||||
#define gpuDeviceProp_t hipDeviceProp_t
|
||||
#define gpuError_t hipError_t
|
||||
#define gpuSuccess hipSuccess
|
||||
#define gpuErrorNotReady hipErrorNotReady
|
||||
#define gpuGetDeviceCount hipGetDeviceCount
|
||||
#define gpuGetLastError hipGetLastError
|
||||
#define gpuPeekAtLastError hipPeekAtLastError
|
||||
#define gpuGetErrorName hipGetErrorName
|
||||
#define gpuGetErrorString hipGetErrorString
|
||||
#define gpuGetDeviceProperties hipGetDeviceProperties
|
||||
#define gpuStreamDefault hipStreamDefault
|
||||
#define gpuGetDevice hipGetDevice
|
||||
#define gpuSetDevice hipSetDevice
|
||||
#define gpuMalloc hipMalloc
|
||||
#define gpuFree hipFree
|
||||
#define gpuMemsetAsync hipMemsetAsync
|
||||
#define gpuMemset2DAsync hipMemset2DAsync
|
||||
#define gpuMemcpyAsync hipMemcpyAsync
|
||||
#define gpuMemcpyDeviceToDevice hipMemcpyDeviceToDevice
|
||||
#define gpuMemcpyDeviceToHost hipMemcpyDeviceToHost
|
||||
#define gpuMemcpyHostToDevice hipMemcpyHostToDevice
|
||||
#define gpuStreamQuery hipStreamQuery
|
||||
#define gpuSharedMemConfig hipSharedMemConfig
|
||||
#define gpuDeviceSetSharedMemConfig hipDeviceSetSharedMemConfig
|
||||
#define gpuStreamSynchronize hipStreamSynchronize
|
||||
#define gpuDeviceSynchronize hipDeviceSynchronize
|
||||
#define gpuMemcpy hipMemcpy
|
||||
|
||||
#else
|
||||
|
||||
#define gpuStream_t cudaStream_t
|
||||
#define gpuDeviceProp_t cudaDeviceProp
|
||||
#define gpuError_t cudaError_t
|
||||
#define gpuSuccess cudaSuccess
|
||||
#define gpuErrorNotReady cudaErrorNotReady
|
||||
#define gpuGetDeviceCount cudaGetDeviceCount
|
||||
#define gpuGetLastError cudaGetLastError
|
||||
#define gpuPeekAtLastError cudaPeekAtLastError
|
||||
#define gpuGetErrorName cudaGetErrorName
|
||||
#define gpuGetErrorString cudaGetErrorString
|
||||
#define gpuGetDeviceProperties cudaGetDeviceProperties
|
||||
#define gpuStreamDefault cudaStreamDefault
|
||||
#define gpuGetDevice cudaGetDevice
|
||||
#define gpuSetDevice cudaSetDevice
|
||||
#define gpuMalloc cudaMalloc
|
||||
#define gpuFree cudaFree
|
||||
#define gpuMemsetAsync cudaMemsetAsync
|
||||
#define gpuMemset2DAsync cudaMemset2DAsync
|
||||
#define gpuMemcpyAsync cudaMemcpyAsync
|
||||
#define gpuMemcpyDeviceToDevice cudaMemcpyDeviceToDevice
|
||||
#define gpuMemcpyDeviceToHost cudaMemcpyDeviceToHost
|
||||
#define gpuMemcpyHostToDevice cudaMemcpyHostToDevice
|
||||
#define gpuStreamQuery cudaStreamQuery
|
||||
#define gpuSharedMemConfig cudaSharedMemConfig
|
||||
#define gpuDeviceSetSharedMemConfig cudaDeviceSetSharedMemConfig
|
||||
#define gpuStreamSynchronize cudaStreamSynchronize
|
||||
#define gpuDeviceSynchronize cudaDeviceSynchronize
|
||||
#define gpuMemcpy cudaMemcpy
|
||||
|
||||
#endif
|
||||
|
||||
// gpu_assert can be overridden
|
||||
#ifndef gpu_assert
|
||||
|
||||
#if defined(EIGEN_HIP_DEVICE_COMPILE)
|
||||
// HIPCC do not support the use of assert on the GPU side.
|
||||
#define gpu_assert(COND)
|
||||
#else
|
||||
#define gpu_assert(COND) eigen_assert(COND)
|
||||
#endif
|
||||
|
||||
#endif // gpu_assert
|
||||
|
||||
#endif // EIGEN_CORE_GPU_HIP_CUDA_DEFINES_H
|
||||
@@ -0,0 +1,45 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
// Copyright (C) 2018 Deven Desai <deven.desai.amd@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#if defined(EIGEN_CORE_GPU_HIP_CUDA_DEFINES_H)
|
||||
|
||||
#ifndef EIGEN_PERMANENTLY_ENABLE_GPU_HIP_CUDA_DEFINES
|
||||
|
||||
#undef gpuStream_t
|
||||
#undef gpuDeviceProp_t
|
||||
#undef gpuError_t
|
||||
#undef gpuSuccess
|
||||
#undef gpuErrorNotReady
|
||||
#undef gpuGetDeviceCount
|
||||
#undef gpuGetErrorString
|
||||
#undef gpuGetDeviceProperties
|
||||
#undef gpuStreamDefault
|
||||
#undef gpuGetDevice
|
||||
#undef gpuSetDevice
|
||||
#undef gpuMalloc
|
||||
#undef gpuFree
|
||||
#undef gpuMemsetAsync
|
||||
#undef gpuMemset2DAsync
|
||||
#undef gpuMemcpyAsync
|
||||
#undef gpuMemcpyDeviceToDevice
|
||||
#undef gpuMemcpyDeviceToHost
|
||||
#undef gpuMemcpyHostToDevice
|
||||
#undef gpuStreamQuery
|
||||
#undef gpuSharedMemConfig
|
||||
#undef gpuDeviceSetSharedMemConfig
|
||||
#undef gpuStreamSynchronize
|
||||
#undef gpuDeviceSynchronize
|
||||
#undef gpuMemcpy
|
||||
|
||||
#endif // EIGEN_PERMANENTLY_ENABLE_GPU_HIP_CUDA_DEFINES
|
||||
|
||||
#undef EIGEN_CORE_GPU_HIP_CUDA_DEFINES_H
|
||||
|
||||
#endif // EIGEN_CORE_GPU_HIP_CUDA_DEFINES_H
|
||||
@@ -0,0 +1,139 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_FIXEDSIZEVECTOR_H
|
||||
#define EIGEN_FIXEDSIZEVECTOR_H
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
/** \class MaxSizeVector
|
||||
* \ingroup Core_Module
|
||||
*
|
||||
* \brief The MaxSizeVector class.
|
||||
*
|
||||
* The %MaxSizeVector provides a subset of std::vector functionality.
|
||||
*
|
||||
* The goal is to provide basic std::vector operations when using
|
||||
* std::vector is not an option (e.g. on GPU or when compiling using
|
||||
* FMA/AVX, as this can cause either compilation failures or illegal
|
||||
* instruction failures).
|
||||
*
|
||||
* Beware: The constructors are not API compatible with these of
|
||||
* std::vector.
|
||||
*/
|
||||
template <typename T>
|
||||
class MaxSizeVector {
|
||||
static const size_t alignment = internal::plain_enum_max(EIGEN_ALIGNOF(T), sizeof(void*));
|
||||
|
||||
public:
|
||||
// Construct a new MaxSizeVector, reserve n elements.
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit MaxSizeVector(size_t n)
|
||||
: reserve_(n), size_(0), data_(static_cast<T*>(internal::handmade_aligned_malloc(n * sizeof(T), alignment))) {}
|
||||
|
||||
// Construct a new MaxSizeVector, reserve and resize to n.
|
||||
// Copy the init value to all elements.
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE MaxSizeVector(size_t n, const T& init)
|
||||
: reserve_(n), size_(n), data_(static_cast<T*>(internal::handmade_aligned_malloc(n * sizeof(T), alignment))) {
|
||||
size_t i = 0;
|
||||
EIGEN_TRY {
|
||||
for (; i < size_; ++i) {
|
||||
new (&data_[i]) T(init);
|
||||
}
|
||||
}
|
||||
EIGEN_CATCH(...) {
|
||||
// Construction failed, destruct in reverse order:
|
||||
for (; (i + 1) > 0; --i) {
|
||||
data_[i - 1].~T();
|
||||
}
|
||||
internal::handmade_aligned_free(data_);
|
||||
EIGEN_THROW;
|
||||
}
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ~MaxSizeVector() {
|
||||
for (size_t i = size_; i > 0; --i) {
|
||||
data_[i - 1].~T();
|
||||
}
|
||||
internal::handmade_aligned_free(data_);
|
||||
}
|
||||
|
||||
void resize(size_t n) {
|
||||
eigen_assert(n <= reserve_);
|
||||
for (; size_ < n; ++size_) {
|
||||
new (&data_[size_]) T;
|
||||
}
|
||||
for (; size_ > n; --size_) {
|
||||
data_[size_ - 1].~T();
|
||||
}
|
||||
eigen_assert(size_ == n);
|
||||
}
|
||||
|
||||
// Append new elements (up to reserved size).
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void push_back(const T& t) {
|
||||
eigen_assert(size_ < reserve_);
|
||||
new (&data_[size_++]) T(t);
|
||||
}
|
||||
|
||||
// For C++03 compatibility this only takes one argument
|
||||
template <class X>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void emplace_back(const X& x) {
|
||||
eigen_assert(size_ < reserve_);
|
||||
new (&data_[size_++]) T(x);
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const T& operator[](size_t i) const {
|
||||
eigen_assert(i < size_);
|
||||
return data_[i];
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T& operator[](size_t i) {
|
||||
eigen_assert(i < size_);
|
||||
return data_[i];
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T& back() {
|
||||
eigen_assert(size_ > 0);
|
||||
return data_[size_ - 1];
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const T& back() const {
|
||||
eigen_assert(size_ > 0);
|
||||
return data_[size_ - 1];
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void pop_back() {
|
||||
eigen_assert(size_ > 0);
|
||||
data_[--size_].~T();
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t size() const { return size_; }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool empty() const { return size_ == 0; }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr T* data() { return data_; }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr const T* data() const { return data_; }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr T* begin() { return data_; }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr T* end() { return data_ + size_; }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr const T* begin() const { return data_; }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr const T* end() const { return data_ + size_; }
|
||||
|
||||
private:
|
||||
size_t reserve_;
|
||||
size_t size_;
|
||||
T* data_;
|
||||
};
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_FIXEDSIZEVECTOR_H
|
||||
@@ -0,0 +1,638 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008-2015 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_MOREMETA_H
|
||||
#define EIGEN_MOREMETA_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "../InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename... tt>
|
||||
struct type_list {
|
||||
constexpr static int count = sizeof...(tt);
|
||||
};
|
||||
|
||||
template <typename t, typename... tt>
|
||||
struct type_list<t, tt...> {
|
||||
constexpr static int count = sizeof...(tt) + 1;
|
||||
typedef t first_type;
|
||||
};
|
||||
|
||||
template <typename T, T... nn>
|
||||
struct numeric_list {
|
||||
constexpr static std::size_t count = sizeof...(nn);
|
||||
};
|
||||
|
||||
template <typename T, T n, T... nn>
|
||||
struct numeric_list<T, n, nn...> {
|
||||
static constexpr std::size_t count = sizeof...(nn) + 1;
|
||||
static constexpr T first_value = n;
|
||||
};
|
||||
|
||||
// Ddoxygen doesn't like the recursive definition of gen_numeric_list.
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
/* numeric list constructors
|
||||
*
|
||||
* equivalencies:
|
||||
* constructor result
|
||||
* typename gen_numeric_list<int, 5>::type numeric_list<int, 0,1,2,3,4>
|
||||
* typename gen_numeric_list_reversed<int, 5>::type numeric_list<int, 4,3,2,1,0>
|
||||
* typename gen_numeric_list_swapped_pair<int, 5,1,2>::type numeric_list<int, 0,2,1,3,4>
|
||||
* typename gen_numeric_list_repeated<int, 0, 5>::type numeric_list<int, 0,0,0,0,0>
|
||||
*/
|
||||
|
||||
template <typename T, std::size_t n, T start = 0, T... ii>
|
||||
struct gen_numeric_list : gen_numeric_list<T, n - 1, start, start + n - 1, ii...> {};
|
||||
|
||||
template <typename T, T start, T... ii>
|
||||
struct gen_numeric_list<T, 0, start, ii...> {
|
||||
typedef numeric_list<T, ii...> type;
|
||||
};
|
||||
|
||||
template <typename T, std::size_t n, T start = 0, T... ii>
|
||||
struct gen_numeric_list_reversed : gen_numeric_list_reversed<T, n - 1, start, ii..., start + n - 1> {};
|
||||
template <typename T, T start, T... ii>
|
||||
struct gen_numeric_list_reversed<T, 0, start, ii...> {
|
||||
typedef numeric_list<T, ii...> type;
|
||||
};
|
||||
|
||||
template <typename T, std::size_t n, T a, T b, T start = 0, T... ii>
|
||||
struct gen_numeric_list_swapped_pair
|
||||
: gen_numeric_list_swapped_pair<T, n - 1, a, b, start,
|
||||
(start + n - 1) == a ? b : ((start + n - 1) == b ? a : (start + n - 1)), ii...> {};
|
||||
template <typename T, T a, T b, T start, T... ii>
|
||||
struct gen_numeric_list_swapped_pair<T, 0, a, b, start, ii...> {
|
||||
typedef numeric_list<T, ii...> type;
|
||||
};
|
||||
|
||||
template <typename T, std::size_t n, T V, T... nn>
|
||||
struct gen_numeric_list_repeated : gen_numeric_list_repeated<T, n - 1, V, V, nn...> {};
|
||||
template <typename T, T V, T... nn>
|
||||
struct gen_numeric_list_repeated<T, 0, V, nn...> {
|
||||
typedef numeric_list<T, nn...> type;
|
||||
};
|
||||
#else
|
||||
template <typename T, std::size_t n, T start = 0, T... ii>
|
||||
struct gen_numeric_list;
|
||||
#endif // not EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
/* list manipulation: concatenate */
|
||||
|
||||
template <class a, class b>
|
||||
struct concat;
|
||||
|
||||
template <typename... as, typename... bs>
|
||||
struct concat<type_list<as...>, type_list<bs...>> {
|
||||
typedef type_list<as..., bs...> type;
|
||||
};
|
||||
template <typename T, T... as, T... bs>
|
||||
struct concat<numeric_list<T, as...>, numeric_list<T, bs...>> {
|
||||
typedef numeric_list<T, as..., bs...> type;
|
||||
};
|
||||
|
||||
template <typename... p>
|
||||
struct mconcat;
|
||||
template <typename a>
|
||||
struct mconcat<a> {
|
||||
typedef a type;
|
||||
};
|
||||
template <typename a, typename b>
|
||||
struct mconcat<a, b> : concat<a, b> {};
|
||||
template <typename a, typename b, typename... cs>
|
||||
struct mconcat<a, b, cs...> : concat<a, typename mconcat<b, cs...>::type> {};
|
||||
|
||||
/* list manipulation: extract slices */
|
||||
|
||||
template <int n, typename x>
|
||||
struct take;
|
||||
|
||||
template <int n, typename a, typename... as>
|
||||
struct take<n, type_list<a, as...>> : concat<type_list<a>, typename take<n - 1, type_list<as...>>::type> {};
|
||||
|
||||
template <int n>
|
||||
struct take<n, type_list<>> {
|
||||
typedef type_list<> type;
|
||||
};
|
||||
|
||||
template <typename a, typename... as>
|
||||
struct take<0, type_list<a, as...>> {
|
||||
typedef type_list<> type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct take<0, type_list<>> {
|
||||
typedef type_list<> type;
|
||||
};
|
||||
|
||||
template <typename T, int n, T a, T... as>
|
||||
struct take<n, numeric_list<T, a, as...>>
|
||||
: concat<numeric_list<T, a>, typename take<n - 1, numeric_list<T, as...>>::type> {};
|
||||
|
||||
template <typename T, T a, T... as>
|
||||
struct take<0, numeric_list<T, a, as...>> {
|
||||
typedef numeric_list<T> type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct take<0, numeric_list<T>> {
|
||||
typedef numeric_list<T> type;
|
||||
};
|
||||
|
||||
template <typename T, int n, T... ii>
|
||||
struct h_skip_helper_numeric;
|
||||
template <typename T, int n, T i, T... ii>
|
||||
struct h_skip_helper_numeric<T, n, i, ii...> : h_skip_helper_numeric<T, n - 1, ii...> {};
|
||||
template <typename T, T i, T... ii>
|
||||
struct h_skip_helper_numeric<T, 0, i, ii...> {
|
||||
typedef numeric_list<T, i, ii...> type;
|
||||
};
|
||||
template <typename T, int n>
|
||||
struct h_skip_helper_numeric<T, n> {
|
||||
typedef numeric_list<T> type;
|
||||
};
|
||||
template <typename T>
|
||||
struct h_skip_helper_numeric<T, 0> {
|
||||
typedef numeric_list<T> type;
|
||||
};
|
||||
|
||||
template <int n, typename... tt>
|
||||
struct h_skip_helper_type;
|
||||
template <int n, typename t, typename... tt>
|
||||
struct h_skip_helper_type<n, t, tt...> : h_skip_helper_type<n - 1, tt...> {};
|
||||
template <typename t, typename... tt>
|
||||
struct h_skip_helper_type<0, t, tt...> {
|
||||
typedef type_list<t, tt...> type;
|
||||
};
|
||||
template <int n>
|
||||
struct h_skip_helper_type<n> {
|
||||
typedef type_list<> type;
|
||||
};
|
||||
template <>
|
||||
struct h_skip_helper_type<0> {
|
||||
typedef type_list<> type;
|
||||
};
|
||||
|
||||
template <int n>
|
||||
struct h_skip {
|
||||
template <typename T, T... ii>
|
||||
constexpr static EIGEN_STRONG_INLINE typename h_skip_helper_numeric<T, n, ii...>::type helper(
|
||||
numeric_list<T, ii...>) {
|
||||
return typename h_skip_helper_numeric<T, n, ii...>::type();
|
||||
}
|
||||
template <typename... tt>
|
||||
constexpr static EIGEN_STRONG_INLINE typename h_skip_helper_type<n, tt...>::type helper(type_list<tt...>) {
|
||||
return typename h_skip_helper_type<n, tt...>::type();
|
||||
}
|
||||
};
|
||||
|
||||
template <int n, typename a>
|
||||
struct skip {
|
||||
typedef decltype(h_skip<n>::helper(a())) type;
|
||||
};
|
||||
|
||||
template <int start, int count, typename a>
|
||||
struct slice : take<count, typename skip<start, a>::type> {};
|
||||
|
||||
/* list manipulation: retrieve single element from list */
|
||||
|
||||
template <int n, typename x>
|
||||
struct get;
|
||||
|
||||
template <int n, typename a, typename... as>
|
||||
struct get<n, type_list<a, as...>> : get<n - 1, type_list<as...>> {};
|
||||
template <typename a, typename... as>
|
||||
struct get<0, type_list<a, as...>> {
|
||||
typedef a type;
|
||||
};
|
||||
|
||||
template <typename T, int n, T a, T... as>
|
||||
struct get<n, numeric_list<T, a, as...>> : get<n - 1, numeric_list<T, as...>> {};
|
||||
template <typename T, T a, T... as>
|
||||
struct get<0, numeric_list<T, a, as...>> {
|
||||
constexpr static T value = a;
|
||||
};
|
||||
|
||||
template <std::size_t n, typename T, T a, T... as>
|
||||
constexpr T array_get(const numeric_list<T, a, as...>&) {
|
||||
return get<(int)n, numeric_list<T, a, as...>>::value;
|
||||
}
|
||||
|
||||
/* always get type, regardless of dummy; good for parameter pack expansion */
|
||||
|
||||
template <typename T, T dummy, typename t>
|
||||
struct id_numeric {
|
||||
typedef t type;
|
||||
};
|
||||
template <typename dummy, typename t>
|
||||
struct id_type {
|
||||
typedef t type;
|
||||
};
|
||||
|
||||
/* equality checking, flagged version */
|
||||
|
||||
template <typename a, typename b>
|
||||
struct is_same_gf : is_same<a, b> {
|
||||
constexpr static int global_flags = 0;
|
||||
};
|
||||
|
||||
/* apply_op to list */
|
||||
|
||||
template <bool from_left, // false
|
||||
template <typename, typename> class op, typename additional_param, typename... values>
|
||||
struct h_apply_op_helper {
|
||||
typedef type_list<typename op<values, additional_param>::type...> type;
|
||||
};
|
||||
template <template <typename, typename> class op, typename additional_param, typename... values>
|
||||
struct h_apply_op_helper<true, op, additional_param, values...> {
|
||||
typedef type_list<typename op<additional_param, values>::type...> type;
|
||||
};
|
||||
|
||||
template <bool from_left, template <typename, typename> class op, typename additional_param>
|
||||
struct h_apply_op {
|
||||
template <typename... values>
|
||||
constexpr static typename h_apply_op_helper<from_left, op, additional_param, values...>::type helper(
|
||||
type_list<values...>) {
|
||||
return typename h_apply_op_helper<from_left, op, additional_param, values...>::type();
|
||||
}
|
||||
};
|
||||
|
||||
template <template <typename, typename> class op, typename additional_param, typename a>
|
||||
struct apply_op_from_left {
|
||||
typedef decltype(h_apply_op<true, op, additional_param>::helper(a())) type;
|
||||
};
|
||||
|
||||
template <template <typename, typename> class op, typename additional_param, typename a>
|
||||
struct apply_op_from_right {
|
||||
typedef decltype(h_apply_op<false, op, additional_param>::helper(a())) type;
|
||||
};
|
||||
|
||||
/* see if an element is in a list */
|
||||
|
||||
template <template <typename, typename> class test, typename check_against, typename h_list,
|
||||
bool last_check_positive = false>
|
||||
struct contained_in_list;
|
||||
|
||||
template <template <typename, typename> class test, typename check_against, typename h_list>
|
||||
struct contained_in_list<test, check_against, h_list, true> {
|
||||
constexpr static bool value = true;
|
||||
};
|
||||
|
||||
template <template <typename, typename> class test, typename check_against, typename a, typename... as>
|
||||
struct contained_in_list<test, check_against, type_list<a, as...>, false>
|
||||
: contained_in_list<test, check_against, type_list<as...>, test<check_against, a>::value> {};
|
||||
|
||||
template <template <typename, typename> class test, typename check_against, typename... empty>
|
||||
struct contained_in_list<test, check_against, type_list<empty...>, false> {
|
||||
constexpr static bool value = false;
|
||||
};
|
||||
|
||||
/* see if an element is in a list and check for global flags */
|
||||
|
||||
template <template <typename, typename> class test, typename check_against, typename h_list, int default_flags = 0,
|
||||
bool last_check_positive = false, int last_check_flags = default_flags>
|
||||
struct contained_in_list_gf;
|
||||
|
||||
template <template <typename, typename> class test, typename check_against, typename h_list, int default_flags,
|
||||
int last_check_flags>
|
||||
struct contained_in_list_gf<test, check_against, h_list, default_flags, true, last_check_flags> {
|
||||
constexpr static bool value = true;
|
||||
constexpr static int global_flags = last_check_flags;
|
||||
};
|
||||
|
||||
template <template <typename, typename> class test, typename check_against, typename a, typename... as,
|
||||
int default_flags, int last_check_flags>
|
||||
struct contained_in_list_gf<test, check_against, type_list<a, as...>, default_flags, false, last_check_flags>
|
||||
: contained_in_list_gf<test, check_against, type_list<as...>, default_flags, test<check_against, a>::value,
|
||||
test<check_against, a>::global_flags> {};
|
||||
|
||||
template <template <typename, typename> class test, typename check_against, typename... empty, int default_flags,
|
||||
int last_check_flags>
|
||||
struct contained_in_list_gf<test, check_against, type_list<empty...>, default_flags, false, last_check_flags> {
|
||||
constexpr static bool value = false;
|
||||
constexpr static int global_flags = default_flags;
|
||||
};
|
||||
|
||||
/* generic reductions */
|
||||
|
||||
template <typename Reducer, typename... Ts>
|
||||
struct reduce;
|
||||
|
||||
template <typename Reducer>
|
||||
struct reduce<Reducer> {
|
||||
EIGEN_DEVICE_FUNC constexpr static EIGEN_STRONG_INLINE int run() { return Reducer::Identity; }
|
||||
};
|
||||
|
||||
template <typename Reducer, typename A>
|
||||
struct reduce<Reducer, A> {
|
||||
EIGEN_DEVICE_FUNC constexpr static EIGEN_STRONG_INLINE A run(A a) { return a; }
|
||||
};
|
||||
|
||||
template <typename Reducer, typename A, typename... Ts>
|
||||
struct reduce<Reducer, A, Ts...> {
|
||||
EIGEN_DEVICE_FUNC constexpr static EIGEN_STRONG_INLINE auto run(A a, Ts... ts)
|
||||
-> decltype(Reducer::run(a, reduce<Reducer, Ts...>::run(ts...))) {
|
||||
return Reducer::run(a, reduce<Reducer, Ts...>::run(ts...));
|
||||
}
|
||||
};
|
||||
|
||||
/* generic binary operations */
|
||||
|
||||
struct sum_op {
|
||||
template <typename A, typename B>
|
||||
EIGEN_DEVICE_FUNC constexpr static EIGEN_STRONG_INLINE auto run(A a, B b) -> decltype(a + b) {
|
||||
return a + b;
|
||||
}
|
||||
static constexpr int Identity = 0;
|
||||
};
|
||||
struct product_op {
|
||||
template <typename A, typename B>
|
||||
EIGEN_DEVICE_FUNC constexpr static EIGEN_STRONG_INLINE auto run(A a, B b) -> decltype(a * b) {
|
||||
return a * b;
|
||||
}
|
||||
static constexpr int Identity = 1;
|
||||
};
|
||||
|
||||
struct logical_and_op {
|
||||
template <typename A, typename B>
|
||||
constexpr static EIGEN_STRONG_INLINE auto run(A a, B b) -> decltype(a && b) {
|
||||
return a && b;
|
||||
}
|
||||
};
|
||||
struct logical_or_op {
|
||||
template <typename A, typename B>
|
||||
constexpr static EIGEN_STRONG_INLINE auto run(A a, B b) -> decltype(a || b) {
|
||||
return a || b;
|
||||
}
|
||||
};
|
||||
|
||||
struct equal_op {
|
||||
template <typename A, typename B>
|
||||
constexpr static EIGEN_STRONG_INLINE auto run(A a, B b) -> decltype(a == b) {
|
||||
return a == b;
|
||||
}
|
||||
};
|
||||
struct not_equal_op {
|
||||
template <typename A, typename B>
|
||||
constexpr static EIGEN_STRONG_INLINE auto run(A a, B b) -> decltype(a != b) {
|
||||
return a != b;
|
||||
}
|
||||
};
|
||||
struct lesser_op {
|
||||
template <typename A, typename B>
|
||||
constexpr static EIGEN_STRONG_INLINE auto run(A a, B b) -> decltype(a < b) {
|
||||
return a < b;
|
||||
}
|
||||
};
|
||||
struct lesser_equal_op {
|
||||
template <typename A, typename B>
|
||||
constexpr static EIGEN_STRONG_INLINE auto run(A a, B b) -> decltype(a <= b) {
|
||||
return a <= b;
|
||||
}
|
||||
};
|
||||
struct greater_op {
|
||||
template <typename A, typename B>
|
||||
constexpr static EIGEN_STRONG_INLINE auto run(A a, B b) -> decltype(a > b) {
|
||||
return a > b;
|
||||
}
|
||||
};
|
||||
struct greater_equal_op {
|
||||
template <typename A, typename B>
|
||||
constexpr static EIGEN_STRONG_INLINE auto run(A a, B b) -> decltype(a >= b) {
|
||||
return a >= b;
|
||||
}
|
||||
};
|
||||
|
||||
/* generic unary operations */
|
||||
|
||||
struct not_op {
|
||||
template <typename A>
|
||||
constexpr static EIGEN_STRONG_INLINE auto run(A a) -> decltype(!a) {
|
||||
return !a;
|
||||
}
|
||||
};
|
||||
struct negation_op {
|
||||
template <typename A>
|
||||
constexpr static EIGEN_STRONG_INLINE auto run(A a) -> decltype(-a) {
|
||||
return -a;
|
||||
}
|
||||
};
|
||||
struct greater_equal_zero_op {
|
||||
template <typename A>
|
||||
constexpr static EIGEN_STRONG_INLINE auto run(A a) -> decltype(a >= 0) {
|
||||
return a >= 0;
|
||||
}
|
||||
};
|
||||
|
||||
/* reductions for lists */
|
||||
|
||||
// using auto -> return value spec makes ICC 13.0 and 13.1 crash here, so we have to hack it
|
||||
// together in front... (13.0 doesn't work with array_prod/array_reduce/... anyway, but 13.1
|
||||
// does...
|
||||
template <typename... Ts>
|
||||
EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE decltype(reduce<product_op, Ts...>::run((*((Ts*)0))...)) arg_prod(
|
||||
Ts... ts) {
|
||||
return reduce<product_op, Ts...>::run(ts...);
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
constexpr EIGEN_STRONG_INLINE decltype(reduce<sum_op, Ts...>::run((*((Ts*)0))...)) arg_sum(Ts... ts) {
|
||||
return reduce<sum_op, Ts...>::run(ts...);
|
||||
}
|
||||
|
||||
/* reverse arrays */
|
||||
|
||||
template <typename Array, int... n>
|
||||
constexpr EIGEN_STRONG_INLINE Array h_array_reverse(Array arr, numeric_list<int, n...>) {
|
||||
return {{array_get<sizeof...(n) - n - 1>(arr)...}};
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
constexpr EIGEN_STRONG_INLINE array<T, N> array_reverse(array<T, N> arr) {
|
||||
return h_array_reverse(arr, typename gen_numeric_list<int, N>::type());
|
||||
}
|
||||
|
||||
/* generic array reductions */
|
||||
|
||||
// can't reuse standard reduce() interface above because Intel's Compiler
|
||||
// *really* doesn't like it, so we just reimplement the stuff
|
||||
// (start from N - 1 and work down to 0 because specialization for
|
||||
// n == N - 1 also doesn't work in Intel's compiler, so it goes into
|
||||
// an infinite loop)
|
||||
template <typename Reducer, typename T, std::size_t N, std::size_t n = N - 1>
|
||||
struct h_array_reduce {
|
||||
EIGEN_DEVICE_FUNC constexpr static EIGEN_STRONG_INLINE auto run(array<T, N> arr, T identity)
|
||||
-> decltype(Reducer::run(h_array_reduce<Reducer, T, N, n - 1>::run(arr, identity), array_get<n>(arr))) {
|
||||
return Reducer::run(h_array_reduce<Reducer, T, N, n - 1>::run(arr, identity), array_get<n>(arr));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Reducer, typename T, std::size_t N>
|
||||
struct h_array_reduce<Reducer, T, N, 0> {
|
||||
EIGEN_DEVICE_FUNC constexpr static EIGEN_STRONG_INLINE T run(const array<T, N>& arr, T) { return array_get<0>(arr); }
|
||||
};
|
||||
|
||||
template <typename Reducer, typename T>
|
||||
struct h_array_reduce<Reducer, T, 0> {
|
||||
EIGEN_DEVICE_FUNC constexpr static EIGEN_STRONG_INLINE T run(const array<T, 0>&, T identity) { return identity; }
|
||||
};
|
||||
|
||||
template <typename Reducer, typename T, std::size_t N>
|
||||
EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE auto array_reduce(const array<T, N>& arr, T identity)
|
||||
-> decltype(h_array_reduce<Reducer, T, N>::run(arr, identity)) {
|
||||
return h_array_reduce<Reducer, T, N>::run(arr, identity);
|
||||
}
|
||||
|
||||
/* standard array reductions */
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE auto array_sum(const array<T, N>& arr)
|
||||
-> decltype(array_reduce<sum_op, T, N>(arr, static_cast<T>(0))) {
|
||||
return array_reduce<sum_op, T, N>(arr, static_cast<T>(0));
|
||||
}
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE auto array_prod(const array<T, N>& arr)
|
||||
-> decltype(array_reduce<product_op, T, N>(arr, static_cast<T>(1))) {
|
||||
return array_reduce<product_op, T, N>(arr, static_cast<T>(1));
|
||||
}
|
||||
|
||||
template <typename t>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE t array_prod(const std::vector<t>& a) {
|
||||
eigen_assert(a.size() > 0);
|
||||
t prod = 1;
|
||||
for (size_t i = 0; i < a.size(); ++i) {
|
||||
prod *= a[i];
|
||||
}
|
||||
return prod;
|
||||
}
|
||||
|
||||
/* zip an array */
|
||||
|
||||
template <typename Op, typename A, typename B, std::size_t N, int... n>
|
||||
constexpr EIGEN_STRONG_INLINE array<decltype(Op::run(A(), B())), N> h_array_zip(array<A, N> a, array<B, N> b,
|
||||
numeric_list<int, n...>) {
|
||||
return array<decltype(Op::run(A(), B())), N>{{Op::run(array_get<n>(a), array_get<n>(b))...}};
|
||||
}
|
||||
|
||||
template <typename Op, typename A, typename B, std::size_t N>
|
||||
constexpr EIGEN_STRONG_INLINE array<decltype(Op::run(A(), B())), N> array_zip(array<A, N> a, array<B, N> b) {
|
||||
return h_array_zip<Op>(a, b, typename gen_numeric_list<int, N>::type());
|
||||
}
|
||||
|
||||
/* zip an array and reduce the result */
|
||||
|
||||
template <typename Reducer, typename Op, typename A, typename B, std::size_t N, int... n>
|
||||
constexpr EIGEN_STRONG_INLINE auto h_array_zip_and_reduce(array<A, N> a, array<B, N> b, numeric_list<int, n...>)
|
||||
-> decltype(reduce<Reducer, typename id_numeric<int, n, decltype(Op::run(A(), B()))>::type...>::run(
|
||||
Op::run(array_get<n>(a), array_get<n>(b))...)) {
|
||||
return reduce<Reducer, typename id_numeric<int, n, decltype(Op::run(A(), B()))>::type...>::run(
|
||||
Op::run(array_get<n>(a), array_get<n>(b))...);
|
||||
}
|
||||
|
||||
template <typename Reducer, typename Op, typename A, typename B, std::size_t N>
|
||||
constexpr EIGEN_STRONG_INLINE auto array_zip_and_reduce(array<A, N> a, array<B, N> b)
|
||||
-> decltype(h_array_zip_and_reduce<Reducer, Op, A, B, N>(a, b, typename gen_numeric_list<int, N>::type())) {
|
||||
return h_array_zip_and_reduce<Reducer, Op, A, B, N>(a, b, typename gen_numeric_list<int, N>::type());
|
||||
}
|
||||
|
||||
/* apply stuff to an array */
|
||||
|
||||
template <typename Op, typename A, std::size_t N, int... n>
|
||||
constexpr EIGEN_STRONG_INLINE array<decltype(Op::run(A())), N> h_array_apply(array<A, N> a, numeric_list<int, n...>) {
|
||||
return array<decltype(Op::run(A())), N>{{Op::run(array_get<n>(a))...}};
|
||||
}
|
||||
|
||||
template <typename Op, typename A, std::size_t N>
|
||||
constexpr EIGEN_STRONG_INLINE array<decltype(Op::run(A())), N> array_apply(array<A, N> a) {
|
||||
return h_array_apply<Op>(a, typename gen_numeric_list<int, N>::type());
|
||||
}
|
||||
|
||||
/* apply stuff to an array and reduce */
|
||||
|
||||
template <typename Reducer, typename Op, typename A, std::size_t N, int... n>
|
||||
constexpr EIGEN_STRONG_INLINE auto h_array_apply_and_reduce(array<A, N> arr, numeric_list<int, n...>)
|
||||
-> decltype(reduce<Reducer, typename id_numeric<int, n, decltype(Op::run(A()))>::type...>::run(
|
||||
Op::run(array_get<n>(arr))...)) {
|
||||
return reduce<Reducer, typename id_numeric<int, n, decltype(Op::run(A()))>::type...>::run(
|
||||
Op::run(array_get<n>(arr))...);
|
||||
}
|
||||
|
||||
template <typename Reducer, typename Op, typename A, std::size_t N>
|
||||
constexpr EIGEN_STRONG_INLINE auto array_apply_and_reduce(array<A, N> a)
|
||||
-> decltype(h_array_apply_and_reduce<Reducer, Op, A, N>(a, typename gen_numeric_list<int, N>::type())) {
|
||||
return h_array_apply_and_reduce<Reducer, Op, A, N>(a, typename gen_numeric_list<int, N>::type());
|
||||
}
|
||||
|
||||
/* repeat a value n times (and make an array out of it
|
||||
* usage:
|
||||
* array<int, 16> = repeat<16>(42);
|
||||
*/
|
||||
|
||||
template <int n>
|
||||
struct h_repeat {
|
||||
template <typename t, int... ii>
|
||||
constexpr static EIGEN_STRONG_INLINE array<t, n> run(t v, numeric_list<int, ii...>) {
|
||||
return {{typename id_numeric<int, ii, t>::type(v)...}};
|
||||
}
|
||||
};
|
||||
|
||||
template <int n, typename t>
|
||||
constexpr array<t, n> repeat(t v) {
|
||||
return h_repeat<n>::run(v, typename gen_numeric_list<int, n>::type());
|
||||
}
|
||||
|
||||
/* instantiate a class by a C-style array */
|
||||
template <class InstType, typename ArrType, std::size_t N, bool Reverse, typename... Ps>
|
||||
struct h_instantiate_by_c_array;
|
||||
|
||||
template <class InstType, typename ArrType, std::size_t N, typename... Ps>
|
||||
struct h_instantiate_by_c_array<InstType, ArrType, N, false, Ps...> {
|
||||
static InstType run(ArrType* arr, Ps... args) {
|
||||
return h_instantiate_by_c_array<InstType, ArrType, N - 1, false, Ps..., ArrType>::run(arr + 1, args..., arr[0]);
|
||||
}
|
||||
};
|
||||
|
||||
template <class InstType, typename ArrType, std::size_t N, typename... Ps>
|
||||
struct h_instantiate_by_c_array<InstType, ArrType, N, true, Ps...> {
|
||||
static InstType run(ArrType* arr, Ps... args) {
|
||||
return h_instantiate_by_c_array<InstType, ArrType, N - 1, false, ArrType, Ps...>::run(arr + 1, arr[0], args...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class InstType, typename ArrType, typename... Ps>
|
||||
struct h_instantiate_by_c_array<InstType, ArrType, 0, false, Ps...> {
|
||||
static InstType run(ArrType* arr, Ps... args) {
|
||||
(void)arr;
|
||||
return InstType(args...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class InstType, typename ArrType, typename... Ps>
|
||||
struct h_instantiate_by_c_array<InstType, ArrType, 0, true, Ps...> {
|
||||
static InstType run(ArrType* arr, Ps... args) {
|
||||
(void)arr;
|
||||
return InstType(args...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class InstType, typename ArrType, std::size_t N, bool Reverse = false>
|
||||
InstType instantiate_by_c_array(ArrType* arr) {
|
||||
return h_instantiate_by_c_array<InstType, ArrType, N, Reverse>::run(arr);
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_MOREMETA_H
|
||||
@@ -0,0 +1,209 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2021 The Eigen Team
|
||||
//
|
||||
// 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_SERIALIZER_H
|
||||
#define EIGEN_SERIALIZER_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
// The Serializer class encodes data into a memory buffer so it can be later
|
||||
// reconstructed. This is mainly used to send objects back-and-forth between
|
||||
// the CPU and GPU.
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
/**
|
||||
* Serializes an object to a memory buffer.
|
||||
*
|
||||
* Useful for transferring data (e.g. back-and-forth to a device).
|
||||
*/
|
||||
template <typename T, typename EnableIf = void>
|
||||
class Serializer;
|
||||
|
||||
// Specialization for POD types.
|
||||
template <typename T>
|
||||
class Serializer<T,
|
||||
typename std::enable_if_t<std::is_trivially_copyable<T>::value && std::is_standard_layout<T>::value>> {
|
||||
public:
|
||||
/**
|
||||
* Determines the required size of the serialization buffer for a value.
|
||||
*
|
||||
* \param value the value to serialize.
|
||||
* \return the required size.
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC size_t size(const T& value) const { return sizeof(value); }
|
||||
|
||||
/**
|
||||
* Serializes a value to a byte buffer.
|
||||
* \param dest the destination buffer; if this is nullptr, does nothing.
|
||||
* \param end the end of the destination buffer.
|
||||
* \param value the value to serialize.
|
||||
* \return the next memory address past the end of the serialized data.
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC uint8_t* serialize(uint8_t* dest, uint8_t* end, const T& value) {
|
||||
if (EIGEN_PREDICT_FALSE(dest == nullptr)) return nullptr;
|
||||
if (EIGEN_PREDICT_FALSE(dest + sizeof(value) > end)) return nullptr;
|
||||
EIGEN_USING_STD(memcpy)
|
||||
memcpy(dest, &value, sizeof(value));
|
||||
return dest + sizeof(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a value from a byte buffer.
|
||||
* \param src the source buffer; if this is nullptr, does nothing.
|
||||
* \param end the end of the source buffer.
|
||||
* \param value the value to populate.
|
||||
* \return the next unprocessed memory address; nullptr if parsing errors are detected.
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC const uint8_t* deserialize(const uint8_t* src, const uint8_t* end, T& value) const {
|
||||
if (EIGEN_PREDICT_FALSE(src == nullptr)) return nullptr;
|
||||
if (EIGEN_PREDICT_FALSE(src + sizeof(value) > end)) return nullptr;
|
||||
EIGEN_USING_STD(memcpy)
|
||||
memcpy(&value, src, sizeof(value));
|
||||
return src + sizeof(value);
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for DenseBase.
|
||||
// Serializes [rows, cols, data...].
|
||||
template <typename Derived>
|
||||
class Serializer<DenseBase<Derived>, void> {
|
||||
public:
|
||||
typedef typename Derived::Scalar Scalar;
|
||||
|
||||
struct Header {
|
||||
typename Derived::Index rows;
|
||||
typename Derived::Index cols;
|
||||
};
|
||||
|
||||
EIGEN_DEVICE_FUNC size_t size(const Derived& value) const { return sizeof(Header) + sizeof(Scalar) * value.size(); }
|
||||
|
||||
EIGEN_DEVICE_FUNC uint8_t* serialize(uint8_t* dest, uint8_t* end, const Derived& value) {
|
||||
if (EIGEN_PREDICT_FALSE(dest == nullptr)) return nullptr;
|
||||
if (EIGEN_PREDICT_FALSE(dest + size(value) > end)) return nullptr;
|
||||
const size_t header_bytes = sizeof(Header);
|
||||
const size_t data_bytes = sizeof(Scalar) * value.size();
|
||||
Header header = {value.rows(), value.cols()};
|
||||
EIGEN_USING_STD(memcpy)
|
||||
memcpy(dest, &header, header_bytes);
|
||||
dest += header_bytes;
|
||||
memcpy(dest, value.data(), data_bytes);
|
||||
return dest + data_bytes;
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC const uint8_t* deserialize(const uint8_t* src, const uint8_t* end, Derived& value) const {
|
||||
if (EIGEN_PREDICT_FALSE(src == nullptr)) return nullptr;
|
||||
if (EIGEN_PREDICT_FALSE(src + sizeof(Header) > end)) return nullptr;
|
||||
const size_t header_bytes = sizeof(Header);
|
||||
Header header;
|
||||
EIGEN_USING_STD(memcpy)
|
||||
memcpy(&header, src, header_bytes);
|
||||
src += header_bytes;
|
||||
const size_t data_bytes = sizeof(Scalar) * header.rows * header.cols;
|
||||
if (EIGEN_PREDICT_FALSE(src + data_bytes > end)) return nullptr;
|
||||
value.resize(header.rows, header.cols);
|
||||
memcpy(value.data(), src, data_bytes);
|
||||
return src + data_bytes;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
|
||||
class Serializer<Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>>
|
||||
: public Serializer<DenseBase<Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>>> {};
|
||||
|
||||
template <typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
|
||||
class Serializer<Array<Scalar, Rows, Cols, Options, MaxRows, MaxCols>>
|
||||
: public Serializer<DenseBase<Array<Scalar, Rows, Cols, Options, MaxRows, MaxCols>>> {};
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Recursive serialization implementation helper.
|
||||
template <size_t N, typename... Types>
|
||||
struct serialize_impl;
|
||||
|
||||
template <size_t N, typename T1, typename... Ts>
|
||||
struct serialize_impl<N, T1, Ts...> {
|
||||
using Serializer = Eigen::Serializer<typename std::decay<T1>::type>;
|
||||
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t serialize_size(const T1& value, const Ts&... args) {
|
||||
Serializer serializer;
|
||||
size_t size = serializer.size(value);
|
||||
return size + serialize_impl<N - 1, Ts...>::serialize_size(args...);
|
||||
}
|
||||
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE uint8_t* serialize(uint8_t* dest, uint8_t* end, const T1& value,
|
||||
const Ts&... args) {
|
||||
Serializer serializer;
|
||||
dest = serializer.serialize(dest, end, value);
|
||||
return serialize_impl<N - 1, Ts...>::serialize(dest, end, args...);
|
||||
}
|
||||
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const uint8_t* deserialize(const uint8_t* src, const uint8_t* end,
|
||||
T1& value, Ts&... args) {
|
||||
Serializer serializer;
|
||||
src = serializer.deserialize(src, end, value);
|
||||
return serialize_impl<N - 1, Ts...>::deserialize(src, end, args...);
|
||||
}
|
||||
};
|
||||
|
||||
// Base case.
|
||||
template <>
|
||||
struct serialize_impl<0> {
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t serialize_size() { return 0; }
|
||||
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE uint8_t* serialize(uint8_t* dest, uint8_t* /*end*/) { return dest; }
|
||||
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const uint8_t* deserialize(const uint8_t* src, const uint8_t* /*end*/) {
|
||||
return src;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Determine the buffer size required to serialize a set of values.
|
||||
*
|
||||
* \param args ... arguments to serialize in sequence.
|
||||
* \return the total size of the required buffer.
|
||||
*/
|
||||
template <typename... Args>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE size_t serialize_size(const Args&... args) {
|
||||
return internal::serialize_impl<sizeof...(args), Args...>::serialize_size(args...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize a set of values to the byte buffer.
|
||||
*
|
||||
* \param dest output byte buffer; if this is nullptr, does nothing.
|
||||
* \param end the end of the output byte buffer.
|
||||
* \param args ... arguments to serialize in sequence.
|
||||
* \return the next address after all serialized values.
|
||||
*/
|
||||
template <typename... Args>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE uint8_t* serialize(uint8_t* dest, uint8_t* end, const Args&... args) {
|
||||
return internal::serialize_impl<sizeof...(args), Args...>::serialize(dest, end, args...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize a set of values from the byte buffer.
|
||||
*
|
||||
* \param src input byte buffer; if this is nullptr, does nothing.
|
||||
* \param end the end of input byte buffer.
|
||||
* \param args ... arguments to deserialize in sequence.
|
||||
* \return the next address after all parsed values; nullptr if parsing errors are detected.
|
||||
*/
|
||||
template <typename... Args>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const uint8_t* deserialize(const uint8_t* src, const uint8_t* end,
|
||||
Args&... args) {
|
||||
return internal::serialize_impl<sizeof...(args), Args...>::deserialize(src, end, args...);
|
||||
}
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_SERIALIZER_H
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_EIGENVALUES_MODULE_H
|
||||
#error "Please include Eigen/Eigenvalues instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_GEOMETRY_MODULE_H
|
||||
#error "Please include Eigen/Geometry instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_HOUSEHOLDER_MODULE_H
|
||||
#error "Please include Eigen/Householder instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_ITERATIVELINEARSOLVERS_MODULE_H
|
||||
#error "Please include Eigen/IterativeLinearSolvers instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_JACOBI_MODULE_H
|
||||
#error "Please include Eigen/Jacobi instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_KLUSUPPORT_MODULE_H
|
||||
#error "Please include Eigen/KLUSupport instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_LU_MODULE_H
|
||||
#error "Please include Eigen/LU instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_METISSUPPORT_MODULE_H
|
||||
#error "Please include Eigen/MetisSupport instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_ORDERINGMETHODS_MODULE_H
|
||||
#error "Please include Eigen/OrderingMethods instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_PASTIXSUPPORT_MODULE_H
|
||||
#error "Please include Eigen/PaStiXSupport instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_PARDISOSUPPORT_MODULE_H
|
||||
#error "Please include Eigen/PardisoSupport instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_QR_MODULE_H
|
||||
#error "Please include Eigen/QR instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_SPQRSUPPORT_MODULE_H
|
||||
#error "Please include Eigen/SPQRSupport instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,174 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2022 Melven Roehrig-Zoellner <Melven.Roehrig-Zoellner@DLR.de>
|
||||
// Copyright (c) 2011, Intel Corporation. All rights reserved.
|
||||
//
|
||||
// This file is based on the JacobiSVD_LAPACKE.h originally from Intel -
|
||||
// see license notice below:
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of Intel Corporation nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
********************************************************************************
|
||||
* Content : Eigen bindings to LAPACKe
|
||||
* Singular Value Decomposition - SVD (divide and conquer variant)
|
||||
********************************************************************************
|
||||
*/
|
||||
#ifndef EIGEN_BDCSVD_LAPACKE_H
|
||||
#define EIGEN_BDCSVD_LAPACKE_H
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
namespace lapacke_helpers {
|
||||
|
||||
/** \internal Specialization for the data types supported by LAPACKe */
|
||||
|
||||
// defining a derived class to allow access to protected members
|
||||
template <typename MatrixType_, int Options>
|
||||
class BDCSVD_LAPACKE : public BDCSVD<MatrixType_, Options> {
|
||||
typedef BDCSVD<MatrixType_, Options> SVD;
|
||||
typedef typename SVD::MatrixType MatrixType;
|
||||
typedef typename SVD::Scalar Scalar;
|
||||
typedef typename SVD::RealScalar RealScalar;
|
||||
|
||||
public:
|
||||
// construct this by moving from a parent object
|
||||
BDCSVD_LAPACKE(SVD&& svd) : SVD(std::move(svd)) {}
|
||||
|
||||
template <typename Derived>
|
||||
void compute_impl_lapacke(const MatrixBase<Derived>& matrix, unsigned int computationOptions) {
|
||||
SVD::allocate(matrix.rows(), matrix.cols(), computationOptions);
|
||||
|
||||
SVD::m_nonzeroSingularValues = SVD::m_diagSize;
|
||||
|
||||
// prepare arguments to ?gesdd
|
||||
const lapack_int matrix_order = lapack_storage_of(matrix);
|
||||
const char jobz = (SVD::m_computeFullU || SVD::m_computeFullV) ? 'A'
|
||||
: (SVD::m_computeThinU || SVD::m_computeThinV) ? 'S'
|
||||
: 'N';
|
||||
const lapack_int u_cols = (jobz == 'A') ? to_lapack(SVD::rows()) : (jobz == 'S') ? to_lapack(SVD::diagSize()) : 1;
|
||||
const lapack_int vt_rows = (jobz == 'A') ? to_lapack(SVD::cols()) : (jobz == 'S') ? to_lapack(SVD::diagSize()) : 1;
|
||||
lapack_int ldu, ldvt;
|
||||
Scalar *u, *vt, dummy;
|
||||
MatrixType localU;
|
||||
if (SVD::computeU() && !(SVD::m_computeThinU && SVD::m_computeFullV)) {
|
||||
ldu = to_lapack(SVD::m_matrixU.outerStride());
|
||||
u = SVD::m_matrixU.data();
|
||||
} else if (SVD::computeV()) {
|
||||
localU.resize(SVD::rows(), u_cols);
|
||||
ldu = to_lapack(localU.outerStride());
|
||||
u = localU.data();
|
||||
} else {
|
||||
ldu = 1;
|
||||
u = &dummy;
|
||||
}
|
||||
MatrixType localV;
|
||||
if (SVD::computeU() || SVD::computeV()) {
|
||||
localV.resize(vt_rows, SVD::cols());
|
||||
ldvt = to_lapack(localV.outerStride());
|
||||
vt = localV.data();
|
||||
} else {
|
||||
ldvt = 1;
|
||||
vt = &dummy;
|
||||
}
|
||||
MatrixType temp;
|
||||
temp = matrix;
|
||||
|
||||
// actual call to ?gesdd
|
||||
lapack_int info = gesdd(matrix_order, jobz, to_lapack(SVD::rows()), to_lapack(SVD::cols()), to_lapack(temp.data()),
|
||||
to_lapack(temp.outerStride()), (RealScalar*)SVD::m_singularValues.data(), to_lapack(u), ldu,
|
||||
to_lapack(vt), ldvt);
|
||||
|
||||
// Check the result of the LAPACK call
|
||||
if (info < 0 || !SVD::m_singularValues.allFinite()) {
|
||||
// this includes info == -4 => NaN entry in A
|
||||
SVD::m_info = InvalidInput;
|
||||
} else if (info > 0) {
|
||||
SVD::m_info = NoConvergence;
|
||||
} else {
|
||||
SVD::m_info = Success;
|
||||
if (SVD::m_computeThinU && SVD::m_computeFullV) {
|
||||
SVD::m_matrixU = localU.leftCols(SVD::m_matrixU.cols());
|
||||
}
|
||||
if (SVD::computeV()) {
|
||||
SVD::m_matrixV = localV.adjoint().leftCols(SVD::m_matrixV.cols());
|
||||
}
|
||||
}
|
||||
SVD::m_isInitialized = true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename MatrixType_, int Options, typename Derived>
|
||||
BDCSVD<MatrixType_, Options>& BDCSVD_wrapper(BDCSVD<MatrixType_, Options>& svd, const MatrixBase<Derived>& matrix,
|
||||
int computationOptions) {
|
||||
// we need to move to the wrapper type and back
|
||||
BDCSVD_LAPACKE<MatrixType_, Options> tmpSvd(std::move(svd));
|
||||
tmpSvd.compute_impl_lapacke(matrix, computationOptions);
|
||||
svd = std::move(tmpSvd);
|
||||
return svd;
|
||||
}
|
||||
|
||||
} // end namespace lapacke_helpers
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
#define EIGEN_LAPACKE_SDD(EIGTYPE, EIGCOLROW, OPTIONS) \
|
||||
template <> \
|
||||
template <typename Derived> \
|
||||
inline BDCSVD<Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW, Dynamic, Dynamic>, OPTIONS>& \
|
||||
BDCSVD<Matrix<EIGTYPE, Dynamic, Dynamic, EIGCOLROW, Dynamic, Dynamic>, OPTIONS>::compute_impl( \
|
||||
const MatrixBase<Derived>& matrix, unsigned int computationOptions) { \
|
||||
return internal::lapacke_helpers::BDCSVD_wrapper(*this, matrix, computationOptions); \
|
||||
}
|
||||
|
||||
#define EIGEN_LAPACK_SDD_OPTIONS(OPTIONS) \
|
||||
EIGEN_LAPACKE_SDD(double, ColMajor, OPTIONS) \
|
||||
EIGEN_LAPACKE_SDD(float, ColMajor, OPTIONS) \
|
||||
EIGEN_LAPACKE_SDD(dcomplex, ColMajor, OPTIONS) \
|
||||
EIGEN_LAPACKE_SDD(scomplex, ColMajor, OPTIONS) \
|
||||
\
|
||||
EIGEN_LAPACKE_SDD(double, RowMajor, OPTIONS) \
|
||||
EIGEN_LAPACKE_SDD(float, RowMajor, OPTIONS) \
|
||||
EIGEN_LAPACKE_SDD(dcomplex, RowMajor, OPTIONS) \
|
||||
EIGEN_LAPACKE_SDD(scomplex, RowMajor, OPTIONS)
|
||||
|
||||
EIGEN_LAPACK_SDD_OPTIONS(0)
|
||||
EIGEN_LAPACK_SDD_OPTIONS(ComputeThinU)
|
||||
EIGEN_LAPACK_SDD_OPTIONS(ComputeThinV)
|
||||
EIGEN_LAPACK_SDD_OPTIONS(ComputeFullU)
|
||||
EIGEN_LAPACK_SDD_OPTIONS(ComputeFullV)
|
||||
EIGEN_LAPACK_SDD_OPTIONS(ComputeThinU | ComputeThinV)
|
||||
EIGEN_LAPACK_SDD_OPTIONS(ComputeFullU | ComputeFullV)
|
||||
EIGEN_LAPACK_SDD_OPTIONS(ComputeThinU | ComputeFullV)
|
||||
EIGEN_LAPACK_SDD_OPTIONS(ComputeFullU | ComputeThinV)
|
||||
|
||||
#undef EIGEN_LAPACK_SDD_OPTIONS
|
||||
|
||||
#undef EIGEN_LAPACKE_SDD
|
||||
|
||||
} // end namespace Eigen
|
||||
|
||||
#endif // EIGEN_BDCSVD_LAPACKE_H
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_SVD_MODULE_H
|
||||
#error "Please include Eigen/SVD instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_SPARSECHOLESKY_MODULE_H
|
||||
#error "Please include Eigen/SparseCholesky instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_SPARSECORE_MODULE_H
|
||||
#error "Please include Eigen/SparseCore instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_SPARSELU_MODULE_H
|
||||
#error "Please include Eigen/SparseLU instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_SPARSEQR_MODULE_H
|
||||
#error "Please include Eigen/SparseQR instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_SUPERLUSUPPORT_MODULE_H
|
||||
#error "Please include Eigen/SuperLUSupport instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2018 Rasmus Munk Larsen <rmlarsen@google.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
// Barrier is an object that allows one or more threads to wait until
|
||||
// Notify has been called a specified number of times.
|
||||
|
||||
#ifndef EIGEN_CXX11_THREADPOOL_BARRIER_H
|
||||
#define EIGEN_CXX11_THREADPOOL_BARRIER_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
class Barrier {
|
||||
public:
|
||||
Barrier(unsigned int count) : state_(count << 1), notified_(false) {
|
||||
eigen_plain_assert(((count << 1) >> 1) == count);
|
||||
}
|
||||
~Barrier() { eigen_plain_assert((state_ >> 1) == 0); }
|
||||
|
||||
void Notify() {
|
||||
unsigned int v = state_.fetch_sub(2, std::memory_order_acq_rel) - 2;
|
||||
if (v != 1) {
|
||||
// Clear the lowest bit (waiter flag) and check that the original state
|
||||
// value was not zero. If it was zero, it means that notify was called
|
||||
// more times than the original count.
|
||||
eigen_plain_assert(((v + 2) & ~1) != 0);
|
||||
return; // either count has not dropped to 0, or waiter is not waiting
|
||||
}
|
||||
EIGEN_MUTEX_LOCK l(mu_);
|
||||
eigen_plain_assert(!notified_);
|
||||
notified_ = true;
|
||||
cv_.notify_all();
|
||||
}
|
||||
|
||||
void Wait() {
|
||||
unsigned int v = state_.fetch_or(1, std::memory_order_acq_rel);
|
||||
if ((v >> 1) == 0) return;
|
||||
EIGEN_MUTEX_LOCK l(mu_);
|
||||
while (!notified_) {
|
||||
cv_.wait(l);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
EIGEN_MUTEX mu_;
|
||||
EIGEN_CONDVAR cv_;
|
||||
std::atomic<unsigned int> state_; // low bit is waiter flag
|
||||
bool notified_;
|
||||
};
|
||||
|
||||
// Notification is an object that allows a user to to wait for another
|
||||
// thread to signal a notification that an event has occurred.
|
||||
//
|
||||
// Multiple threads can wait on the same Notification object,
|
||||
// but only one caller must call Notify() on the object.
|
||||
struct Notification : Barrier {
|
||||
Notification() : Barrier(1){};
|
||||
};
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_CXX11_THREADPOOL_BARRIER_H
|
||||
@@ -0,0 +1,336 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2023 Charlie Schlosser <cs.schlosser@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_CORE_THREAD_POOL_DEVICE_H
|
||||
#define EIGEN_CORE_THREAD_POOL_DEVICE_H
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
// CoreThreadPoolDevice provides an easy-to-understand Device for parallelizing Eigen Core expressions with
|
||||
// Threadpool. Expressions are recursively split evenly until the evaluation cost is less than the threshold for
|
||||
// delegating the task to a thread.
|
||||
/*
|
||||
a
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
/ \
|
||||
a e
|
||||
/ \ / \
|
||||
/ \ / \
|
||||
/ \ / \
|
||||
a c e g
|
||||
/ \ / \ / \ / \
|
||||
/ \ / \ / \ / \
|
||||
a b c d e f g h
|
||||
*/
|
||||
// Each task descends the binary tree to the left, delegates the right task to a new thread, and continues to the
|
||||
// left. This ensures that work is evenly distributed to the thread pool as quickly as possible and minimizes the number
|
||||
// of tasks created during the evaluation. Consider an expression that is divided into 8 chunks. The
|
||||
// primary task 'a' creates tasks 'e' 'c' and 'b', and executes its portion of the expression at the bottom of the
|
||||
// tree. Likewise, task 'e' creates tasks 'g' and 'f', and executes its portion of the expression.
|
||||
|
||||
struct CoreThreadPoolDevice {
|
||||
using Task = std::function<void()>;
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoreThreadPoolDevice(ThreadPool& pool, float threadCostThreshold = 3e-5f)
|
||||
: m_pool(pool) {
|
||||
eigen_assert(threadCostThreshold >= 0.0f && "threadCostThreshold must be non-negative");
|
||||
m_costFactor = threadCostThreshold;
|
||||
}
|
||||
|
||||
template <int PacketSize>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE int calculateLevels(Index size, float cost) const {
|
||||
eigen_assert(cost >= 0.0f && "cost must be non-negative");
|
||||
Index numOps = size / PacketSize;
|
||||
int actualThreads = numOps < m_pool.NumThreads() ? static_cast<int>(numOps) : m_pool.NumThreads();
|
||||
float totalCost = static_cast<float>(numOps) * cost;
|
||||
float idealThreads = totalCost * m_costFactor;
|
||||
if (idealThreads < static_cast<float>(actualThreads)) {
|
||||
idealThreads = numext::maxi(idealThreads, 1.0f);
|
||||
actualThreads = numext::mini(actualThreads, static_cast<int>(idealThreads));
|
||||
}
|
||||
int maxLevel = internal::log2_ceil(actualThreads);
|
||||
return maxLevel;
|
||||
}
|
||||
|
||||
// MSVC does not like inlining parallelForImpl
|
||||
#if EIGEN_COMP_MSVC && !EIGEN_COMP_CLANG
|
||||
#define EIGEN_PARALLEL_FOR_INLINE
|
||||
#else
|
||||
#define EIGEN_PARALLEL_FOR_INLINE EIGEN_STRONG_INLINE
|
||||
#endif
|
||||
|
||||
template <typename UnaryFunctor, int PacketSize>
|
||||
EIGEN_DEVICE_FUNC EIGEN_PARALLEL_FOR_INLINE void parallelForImpl(Index begin, Index end, UnaryFunctor& f,
|
||||
Barrier& barrier, int level) {
|
||||
while (level > 0) {
|
||||
level--;
|
||||
Index size = end - begin;
|
||||
eigen_assert(size % PacketSize == 0 && "this function assumes size is a multiple of PacketSize");
|
||||
Index mid = begin + numext::round_down(size >> 1, PacketSize);
|
||||
Task right = [this, mid, end, &f, &barrier, level]() {
|
||||
parallelForImpl<UnaryFunctor, PacketSize>(mid, end, f, barrier, level);
|
||||
};
|
||||
m_pool.Schedule(std::move(right));
|
||||
end = mid;
|
||||
}
|
||||
for (Index i = begin; i < end; i += PacketSize) f(i);
|
||||
barrier.Notify();
|
||||
}
|
||||
|
||||
template <typename BinaryFunctor, int PacketSize>
|
||||
EIGEN_DEVICE_FUNC EIGEN_PARALLEL_FOR_INLINE void parallelForImpl(Index outerBegin, Index outerEnd, Index innerBegin,
|
||||
Index innerEnd, BinaryFunctor& f, Barrier& barrier,
|
||||
int level) {
|
||||
while (level > 0) {
|
||||
level--;
|
||||
Index outerSize = outerEnd - outerBegin;
|
||||
if (outerSize > 1) {
|
||||
Index outerMid = outerBegin + (outerSize >> 1);
|
||||
Task right = [this, &f, &barrier, outerMid, outerEnd, innerBegin, innerEnd, level]() {
|
||||
parallelForImpl<BinaryFunctor, PacketSize>(outerMid, outerEnd, innerBegin, innerEnd, f, barrier, level);
|
||||
};
|
||||
m_pool.Schedule(std::move(right));
|
||||
outerEnd = outerMid;
|
||||
} else {
|
||||
Index innerSize = innerEnd - innerBegin;
|
||||
eigen_assert(innerSize % PacketSize == 0 && "this function assumes innerSize is a multiple of PacketSize");
|
||||
Index innerMid = innerBegin + numext::round_down(innerSize >> 1, PacketSize);
|
||||
Task right = [this, &f, &barrier, outerBegin, outerEnd, innerMid, innerEnd, level]() {
|
||||
parallelForImpl<BinaryFunctor, PacketSize>(outerBegin, outerEnd, innerMid, innerEnd, f, barrier, level);
|
||||
};
|
||||
m_pool.Schedule(std::move(right));
|
||||
innerEnd = innerMid;
|
||||
}
|
||||
}
|
||||
for (Index outer = outerBegin; outer < outerEnd; outer++)
|
||||
for (Index inner = innerBegin; inner < innerEnd; inner += PacketSize) f(outer, inner);
|
||||
barrier.Notify();
|
||||
}
|
||||
|
||||
#undef EIGEN_PARALLEL_FOR_INLINE
|
||||
|
||||
template <typename UnaryFunctor, int PacketSize>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void parallelFor(Index begin, Index end, UnaryFunctor& f, float cost) {
|
||||
Index size = end - begin;
|
||||
int maxLevel = calculateLevels<PacketSize>(size, cost);
|
||||
Barrier barrier(1 << maxLevel);
|
||||
parallelForImpl<UnaryFunctor, PacketSize>(begin, end, f, barrier, maxLevel);
|
||||
barrier.Wait();
|
||||
}
|
||||
|
||||
template <typename BinaryFunctor, int PacketSize>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void parallelFor(Index outerBegin, Index outerEnd, Index innerBegin,
|
||||
Index innerEnd, BinaryFunctor& f, float cost) {
|
||||
Index outerSize = outerEnd - outerBegin;
|
||||
Index innerSize = innerEnd - innerBegin;
|
||||
Index size = outerSize * innerSize;
|
||||
int maxLevel = calculateLevels<PacketSize>(size, cost);
|
||||
Barrier barrier(1 << maxLevel);
|
||||
parallelForImpl<BinaryFunctor, PacketSize>(outerBegin, outerEnd, innerBegin, innerEnd, f, barrier, maxLevel);
|
||||
barrier.Wait();
|
||||
}
|
||||
|
||||
ThreadPool& m_pool;
|
||||
// costFactor is the cost of delegating a task to a thread
|
||||
// the inverse is used to avoid a floating point division
|
||||
float m_costFactor;
|
||||
};
|
||||
|
||||
// specialization of coefficient-wise assignment loops for CoreThreadPoolDevice
|
||||
|
||||
namespace internal {
|
||||
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
struct Kernel;
|
||||
#endif
|
||||
|
||||
template <typename Kernel>
|
||||
struct cost_helper {
|
||||
using SrcEvaluatorType = typename Kernel::SrcEvaluatorType;
|
||||
using DstEvaluatorType = typename Kernel::DstEvaluatorType;
|
||||
using SrcXprType = typename SrcEvaluatorType::XprType;
|
||||
using DstXprType = typename DstEvaluatorType::XprType;
|
||||
static constexpr Index Cost = functor_cost<SrcXprType>::Cost + functor_cost<DstXprType>::Cost;
|
||||
};
|
||||
|
||||
template <typename Kernel>
|
||||
struct dense_assignment_loop_with_device<Kernel, CoreThreadPoolDevice, DefaultTraversal, NoUnrolling> {
|
||||
static constexpr Index XprEvaluationCost = cost_helper<Kernel>::Cost;
|
||||
struct AssignmentFunctor : public Kernel {
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE AssignmentFunctor(Kernel& kernel) : Kernel(kernel) {}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void operator()(Index outer, Index inner) {
|
||||
this->assignCoeffByOuterInner(outer, inner);
|
||||
}
|
||||
};
|
||||
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Kernel& kernel, CoreThreadPoolDevice& device) {
|
||||
const Index innerSize = kernel.innerSize();
|
||||
const Index outerSize = kernel.outerSize();
|
||||
constexpr float cost = static_cast<float>(XprEvaluationCost);
|
||||
AssignmentFunctor functor(kernel);
|
||||
device.template parallelFor<AssignmentFunctor, 1>(0, outerSize, 0, innerSize, functor, cost);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Kernel>
|
||||
struct dense_assignment_loop_with_device<Kernel, CoreThreadPoolDevice, DefaultTraversal, InnerUnrolling> {
|
||||
using DstXprType = typename Kernel::DstEvaluatorType::XprType;
|
||||
static constexpr Index XprEvaluationCost = cost_helper<Kernel>::Cost, InnerSize = DstXprType::InnerSizeAtCompileTime;
|
||||
struct AssignmentFunctor : public Kernel {
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE AssignmentFunctor(Kernel& kernel) : Kernel(kernel) {}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void operator()(Index outer) {
|
||||
copy_using_evaluator_DefaultTraversal_InnerUnrolling<Kernel, 0, InnerSize>::run(*this, outer);
|
||||
}
|
||||
};
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Kernel& kernel, CoreThreadPoolDevice& device) {
|
||||
const Index outerSize = kernel.outerSize();
|
||||
AssignmentFunctor functor(kernel);
|
||||
constexpr float cost = static_cast<float>(XprEvaluationCost) * static_cast<float>(InnerSize);
|
||||
device.template parallelFor<AssignmentFunctor, 1>(0, outerSize, functor, cost);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Kernel>
|
||||
struct dense_assignment_loop_with_device<Kernel, CoreThreadPoolDevice, InnerVectorizedTraversal, NoUnrolling> {
|
||||
using PacketType = typename Kernel::PacketType;
|
||||
static constexpr Index XprEvaluationCost = cost_helper<Kernel>::Cost, PacketSize = unpacket_traits<PacketType>::size,
|
||||
SrcAlignment = Kernel::AssignmentTraits::SrcAlignment,
|
||||
DstAlignment = Kernel::AssignmentTraits::DstAlignment;
|
||||
struct AssignmentFunctor : public Kernel {
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE AssignmentFunctor(Kernel& kernel) : Kernel(kernel) {}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void operator()(Index outer, Index inner) {
|
||||
this->template assignPacketByOuterInner<Unaligned, Unaligned, PacketType>(outer, inner);
|
||||
}
|
||||
};
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Kernel& kernel, CoreThreadPoolDevice& device) {
|
||||
const Index innerSize = kernel.innerSize();
|
||||
const Index outerSize = kernel.outerSize();
|
||||
const float cost = static_cast<float>(XprEvaluationCost) * static_cast<float>(innerSize);
|
||||
AssignmentFunctor functor(kernel);
|
||||
device.template parallelFor<AssignmentFunctor, PacketSize>(0, outerSize, 0, innerSize, functor, cost);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Kernel>
|
||||
struct dense_assignment_loop_with_device<Kernel, CoreThreadPoolDevice, InnerVectorizedTraversal, InnerUnrolling> {
|
||||
using PacketType = typename Kernel::PacketType;
|
||||
using DstXprType = typename Kernel::DstEvaluatorType::XprType;
|
||||
static constexpr Index XprEvaluationCost = cost_helper<Kernel>::Cost, PacketSize = unpacket_traits<PacketType>::size,
|
||||
SrcAlignment = Kernel::AssignmentTraits::SrcAlignment,
|
||||
DstAlignment = Kernel::AssignmentTraits::DstAlignment,
|
||||
InnerSize = DstXprType::InnerSizeAtCompileTime;
|
||||
struct AssignmentFunctor : public Kernel {
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE AssignmentFunctor(Kernel& kernel) : Kernel(kernel) {}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void operator()(Index outer) {
|
||||
copy_using_evaluator_innervec_InnerUnrolling<Kernel, 0, InnerSize, SrcAlignment, DstAlignment>::run(*this, outer);
|
||||
}
|
||||
};
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Kernel& kernel, CoreThreadPoolDevice& device) {
|
||||
const Index outerSize = kernel.outerSize();
|
||||
constexpr float cost = static_cast<float>(XprEvaluationCost) * static_cast<float>(InnerSize);
|
||||
AssignmentFunctor functor(kernel);
|
||||
device.template parallelFor<AssignmentFunctor, PacketSize>(0, outerSize, functor, cost);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Kernel>
|
||||
struct dense_assignment_loop_with_device<Kernel, CoreThreadPoolDevice, SliceVectorizedTraversal, NoUnrolling> {
|
||||
using Scalar = typename Kernel::Scalar;
|
||||
using PacketType = typename Kernel::PacketType;
|
||||
static constexpr Index XprEvaluationCost = cost_helper<Kernel>::Cost, PacketSize = unpacket_traits<PacketType>::size;
|
||||
struct PacketAssignmentFunctor : public Kernel {
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketAssignmentFunctor(Kernel& kernel) : Kernel(kernel) {}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void operator()(Index outer, Index inner) {
|
||||
this->template assignPacketByOuterInner<Unaligned, Unaligned, PacketType>(outer, inner);
|
||||
}
|
||||
};
|
||||
struct ScalarAssignmentFunctor : public Kernel {
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE ScalarAssignmentFunctor(Kernel& kernel) : Kernel(kernel) {}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void operator()(Index outer) {
|
||||
const Index innerSize = this->innerSize();
|
||||
const Index packetAccessSize = numext::round_down(innerSize, PacketSize);
|
||||
for (Index inner = packetAccessSize; inner < innerSize; inner++) this->assignCoeffByOuterInner(outer, inner);
|
||||
}
|
||||
};
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Kernel& kernel, CoreThreadPoolDevice& device) {
|
||||
const Index outerSize = kernel.outerSize();
|
||||
const Index innerSize = kernel.innerSize();
|
||||
const Index packetAccessSize = numext::round_down(innerSize, PacketSize);
|
||||
constexpr float packetCost = static_cast<float>(XprEvaluationCost);
|
||||
const float scalarCost = static_cast<float>(XprEvaluationCost) * static_cast<float>(innerSize - packetAccessSize);
|
||||
PacketAssignmentFunctor packetFunctor(kernel);
|
||||
ScalarAssignmentFunctor scalarFunctor(kernel);
|
||||
device.template parallelFor<PacketAssignmentFunctor, PacketSize>(0, outerSize, 0, packetAccessSize, packetFunctor,
|
||||
packetCost);
|
||||
device.template parallelFor<ScalarAssignmentFunctor, 1>(0, outerSize, scalarFunctor, scalarCost);
|
||||
};
|
||||
};
|
||||
|
||||
template <typename Kernel>
|
||||
struct dense_assignment_loop_with_device<Kernel, CoreThreadPoolDevice, LinearTraversal, NoUnrolling> {
|
||||
static constexpr Index XprEvaluationCost = cost_helper<Kernel>::Cost;
|
||||
struct AssignmentFunctor : public Kernel {
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE AssignmentFunctor(Kernel& kernel) : Kernel(kernel) {}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void operator()(Index index) { this->assignCoeff(index); }
|
||||
};
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Kernel& kernel, CoreThreadPoolDevice& device) {
|
||||
const Index size = kernel.size();
|
||||
constexpr float cost = static_cast<float>(XprEvaluationCost);
|
||||
AssignmentFunctor functor(kernel);
|
||||
device.template parallelFor<AssignmentFunctor, 1>(0, size, functor, cost);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Kernel>
|
||||
struct dense_assignment_loop_with_device<Kernel, CoreThreadPoolDevice, LinearVectorizedTraversal, NoUnrolling> {
|
||||
using Scalar = typename Kernel::Scalar;
|
||||
using PacketType = typename Kernel::PacketType;
|
||||
static constexpr Index XprEvaluationCost = cost_helper<Kernel>::Cost,
|
||||
RequestedAlignment = Kernel::AssignmentTraits::LinearRequiredAlignment,
|
||||
PacketSize = unpacket_traits<PacketType>::size,
|
||||
DstIsAligned = Kernel::AssignmentTraits::DstAlignment >= RequestedAlignment,
|
||||
DstAlignment = packet_traits<Scalar>::AlignedOnScalar ? RequestedAlignment
|
||||
: Kernel::AssignmentTraits::DstAlignment,
|
||||
SrcAlignment = Kernel::AssignmentTraits::JointAlignment;
|
||||
struct AssignmentFunctor : public Kernel {
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE AssignmentFunctor(Kernel& kernel) : Kernel(kernel) {}
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void operator()(Index index) {
|
||||
this->template assignPacket<DstAlignment, SrcAlignment, PacketType>(index);
|
||||
}
|
||||
};
|
||||
static constexpr bool UsePacketSegment = Kernel::AssignmentTraits::UsePacketSegment;
|
||||
using head_loop =
|
||||
unaligned_dense_assignment_loop<PacketType, DstAlignment, SrcAlignment, UsePacketSegment, DstIsAligned>;
|
||||
using tail_loop = unaligned_dense_assignment_loop<PacketType, DstAlignment, SrcAlignment, UsePacketSegment, false>;
|
||||
|
||||
static EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void run(Kernel& kernel, CoreThreadPoolDevice& device) {
|
||||
const Index size = kernel.size();
|
||||
const Index alignedStart =
|
||||
DstIsAligned ? 0 : internal::first_aligned<RequestedAlignment>(kernel.dstDataPtr(), size);
|
||||
const Index alignedEnd = alignedStart + numext::round_down(size - alignedStart, PacketSize);
|
||||
|
||||
head_loop::run(kernel, 0, alignedStart);
|
||||
|
||||
constexpr float cost = static_cast<float>(XprEvaluationCost);
|
||||
AssignmentFunctor functor(kernel);
|
||||
device.template parallelFor<AssignmentFunctor, PacketSize>(alignedStart, alignedEnd, functor, cost);
|
||||
|
||||
tail_loop::run(kernel, alignedEnd, size);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_CORE_THREAD_POOL_DEVICE_H
|
||||
@@ -0,0 +1,241 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2016 Dmitry Vyukov <dvyukov@google.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_CXX11_THREADPOOL_EVENTCOUNT_H
|
||||
#define EIGEN_CXX11_THREADPOOL_EVENTCOUNT_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
// EventCount allows to wait for arbitrary predicates in non-blocking
|
||||
// algorithms. Think of condition variable, but wait predicate does not need to
|
||||
// be protected by a mutex. Usage:
|
||||
// Waiting thread does:
|
||||
//
|
||||
// if (predicate)
|
||||
// return act();
|
||||
// EventCount::Waiter& w = waiters[my_index];
|
||||
// ec.Prewait(&w);
|
||||
// if (predicate) {
|
||||
// ec.CancelWait(&w);
|
||||
// return act();
|
||||
// }
|
||||
// ec.CommitWait(&w);
|
||||
//
|
||||
// Notifying thread does:
|
||||
//
|
||||
// predicate = true;
|
||||
// ec.Notify(true);
|
||||
//
|
||||
// Notify is cheap if there are no waiting threads. Prewait/CommitWait are not
|
||||
// cheap, but they are executed only if the preceding predicate check has
|
||||
// failed.
|
||||
//
|
||||
// Algorithm outline:
|
||||
// There are two main variables: predicate (managed by user) and state_.
|
||||
// Operation closely resembles Dekker mutual algorithm:
|
||||
// https://en.wikipedia.org/wiki/Dekker%27s_algorithm
|
||||
// Waiting thread sets state_ then checks predicate, Notifying thread sets
|
||||
// predicate then checks state_. Due to seq_cst fences in between these
|
||||
// operations it is guaranteed than either waiter will see predicate change
|
||||
// and won't block, or notifying thread will see state_ change and will unblock
|
||||
// the waiter, or both. But it can't happen that both threads don't see each
|
||||
// other changes, which would lead to deadlock.
|
||||
class EventCount {
|
||||
public:
|
||||
class Waiter;
|
||||
|
||||
EventCount(MaxSizeVector<Waiter>& waiters) : state_(kStackMask), waiters_(waiters) {
|
||||
eigen_plain_assert(waiters.size() < (1 << kWaiterBits) - 1);
|
||||
}
|
||||
|
||||
EventCount(const EventCount&) = delete;
|
||||
void operator=(const EventCount&) = delete;
|
||||
|
||||
~EventCount() {
|
||||
// Ensure there are no waiters.
|
||||
eigen_plain_assert(state_.load() == kStackMask);
|
||||
}
|
||||
|
||||
// Prewait prepares for waiting.
|
||||
// After calling Prewait, the thread must re-check the wait predicate
|
||||
// and then call either CancelWait or CommitWait.
|
||||
void Prewait() {
|
||||
uint64_t state = state_.load(std::memory_order_relaxed);
|
||||
for (;;) {
|
||||
CheckState(state);
|
||||
uint64_t newstate = state + kWaiterInc;
|
||||
CheckState(newstate);
|
||||
if (state_.compare_exchange_weak(state, newstate, std::memory_order_seq_cst)) return;
|
||||
}
|
||||
}
|
||||
|
||||
// CommitWait commits waiting after Prewait.
|
||||
void CommitWait(Waiter* w) {
|
||||
eigen_plain_assert((w->epoch & ~kEpochMask) == 0);
|
||||
w->state = Waiter::kNotSignaled;
|
||||
const uint64_t me = (w - &waiters_[0]) | w->epoch;
|
||||
uint64_t state = state_.load(std::memory_order_seq_cst);
|
||||
for (;;) {
|
||||
CheckState(state, true);
|
||||
uint64_t newstate;
|
||||
if ((state & kSignalMask) != 0) {
|
||||
// Consume the signal and return immediately.
|
||||
newstate = state - kWaiterInc - kSignalInc;
|
||||
} else {
|
||||
// Remove this thread from pre-wait counter and add to the waiter stack.
|
||||
newstate = ((state & kWaiterMask) - kWaiterInc) | me;
|
||||
w->next.store(state & (kStackMask | kEpochMask), std::memory_order_relaxed);
|
||||
}
|
||||
CheckState(newstate);
|
||||
if (state_.compare_exchange_weak(state, newstate, std::memory_order_acq_rel)) {
|
||||
if ((state & kSignalMask) == 0) {
|
||||
w->epoch += kEpochInc;
|
||||
Park(w);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CancelWait cancels effects of the previous Prewait call.
|
||||
void CancelWait() {
|
||||
uint64_t state = state_.load(std::memory_order_relaxed);
|
||||
for (;;) {
|
||||
CheckState(state, true);
|
||||
uint64_t newstate = state - kWaiterInc;
|
||||
// We don't know if the thread was also notified or not,
|
||||
// so we should not consume a signal unconditionally.
|
||||
// Only if number of waiters is equal to number of signals,
|
||||
// we know that the thread was notified and we must take away the signal.
|
||||
if (((state & kWaiterMask) >> kWaiterShift) == ((state & kSignalMask) >> kSignalShift)) newstate -= kSignalInc;
|
||||
CheckState(newstate);
|
||||
if (state_.compare_exchange_weak(state, newstate, std::memory_order_acq_rel)) return;
|
||||
}
|
||||
}
|
||||
|
||||
// Notify wakes one or all waiting threads.
|
||||
// Must be called after changing the associated wait predicate.
|
||||
void Notify(bool notifyAll) {
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
uint64_t state = state_.load(std::memory_order_acquire);
|
||||
for (;;) {
|
||||
CheckState(state);
|
||||
const uint64_t waiters = (state & kWaiterMask) >> kWaiterShift;
|
||||
const uint64_t signals = (state & kSignalMask) >> kSignalShift;
|
||||
// Easy case: no waiters.
|
||||
if ((state & kStackMask) == kStackMask && waiters == signals) return;
|
||||
uint64_t newstate;
|
||||
if (notifyAll) {
|
||||
// Empty wait stack and set signal to number of pre-wait threads.
|
||||
newstate = (state & kWaiterMask) | (waiters << kSignalShift) | kStackMask;
|
||||
} else if (signals < waiters) {
|
||||
// There is a thread in pre-wait state, unblock it.
|
||||
newstate = state + kSignalInc;
|
||||
} else {
|
||||
// Pop a waiter from list and unpark it.
|
||||
Waiter* w = &waiters_[state & kStackMask];
|
||||
uint64_t next = w->next.load(std::memory_order_relaxed);
|
||||
newstate = (state & (kWaiterMask | kSignalMask)) | next;
|
||||
}
|
||||
CheckState(newstate);
|
||||
if (state_.compare_exchange_weak(state, newstate, std::memory_order_acq_rel)) {
|
||||
if (!notifyAll && (signals < waiters)) return; // unblocked pre-wait thread
|
||||
if ((state & kStackMask) == kStackMask) return;
|
||||
Waiter* w = &waiters_[state & kStackMask];
|
||||
if (!notifyAll) w->next.store(kStackMask, std::memory_order_relaxed);
|
||||
Unpark(w);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// State_ layout:
|
||||
// - low kWaiterBits is a stack of waiters committed wait
|
||||
// (indexes in waiters_ array are used as stack elements,
|
||||
// kStackMask means empty stack).
|
||||
// - next kWaiterBits is count of waiters in prewait state.
|
||||
// - next kWaiterBits is count of pending signals.
|
||||
// - remaining bits are ABA counter for the stack.
|
||||
// (stored in Waiter node and incremented on push).
|
||||
static const uint64_t kWaiterBits = 14;
|
||||
static const uint64_t kStackMask = (1ull << kWaiterBits) - 1;
|
||||
static const uint64_t kWaiterShift = kWaiterBits;
|
||||
static const uint64_t kWaiterMask = ((1ull << kWaiterBits) - 1) << kWaiterShift;
|
||||
static const uint64_t kWaiterInc = 1ull << kWaiterShift;
|
||||
static const uint64_t kSignalShift = 2 * kWaiterBits;
|
||||
static const uint64_t kSignalMask = ((1ull << kWaiterBits) - 1) << kSignalShift;
|
||||
static const uint64_t kSignalInc = 1ull << kSignalShift;
|
||||
static const uint64_t kEpochShift = 3 * kWaiterBits;
|
||||
static const uint64_t kEpochBits = 64 - kEpochShift;
|
||||
static const uint64_t kEpochMask = ((1ull << kEpochBits) - 1) << kEpochShift;
|
||||
static const uint64_t kEpochInc = 1ull << kEpochShift;
|
||||
|
||||
public:
|
||||
class Waiter {
|
||||
friend class EventCount;
|
||||
|
||||
enum State {
|
||||
kNotSignaled,
|
||||
kWaiting,
|
||||
kSignaled,
|
||||
};
|
||||
|
||||
EIGEN_ALIGN_TO_AVOID_FALSE_SHARING std::atomic<uint64_t> next{kStackMask};
|
||||
EIGEN_MUTEX mu;
|
||||
EIGEN_CONDVAR cv;
|
||||
uint64_t epoch{0};
|
||||
unsigned state{kNotSignaled};
|
||||
};
|
||||
|
||||
private:
|
||||
static void CheckState(uint64_t state, bool waiter = false) {
|
||||
static_assert(kEpochBits >= 20, "not enough bits to prevent ABA problem");
|
||||
const uint64_t waiters = (state & kWaiterMask) >> kWaiterShift;
|
||||
const uint64_t signals = (state & kSignalMask) >> kSignalShift;
|
||||
eigen_plain_assert(waiters >= signals);
|
||||
eigen_plain_assert(waiters < (1 << kWaiterBits) - 1);
|
||||
eigen_plain_assert(!waiter || waiters > 0);
|
||||
(void)waiters;
|
||||
(void)signals;
|
||||
}
|
||||
|
||||
void Park(Waiter* w) {
|
||||
EIGEN_MUTEX_LOCK lock(w->mu);
|
||||
while (w->state != Waiter::kSignaled) {
|
||||
w->state = Waiter::kWaiting;
|
||||
w->cv.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
void Unpark(Waiter* w) {
|
||||
for (Waiter* next; w; w = next) {
|
||||
uint64_t wnext = w->next.load(std::memory_order_relaxed) & kStackMask;
|
||||
next = wnext == kStackMask ? nullptr : &waiters_[internal::convert_index<size_t>(wnext)];
|
||||
unsigned state;
|
||||
{
|
||||
EIGEN_MUTEX_LOCK lock(w->mu);
|
||||
state = w->state;
|
||||
w->state = Waiter::kSignaled;
|
||||
}
|
||||
// Avoid notifying if it wasn't waiting.
|
||||
if (state == Waiter::kWaiting) w->cv.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
std::atomic<uint64_t> state_;
|
||||
MaxSizeVector<Waiter>& waiters_;
|
||||
};
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_CXX11_THREADPOOL_EVENTCOUNT_H
|
||||
@@ -0,0 +1,140 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2025 Weiwei Kong <weiweikong@google.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_THREADPOOL_FORKJOIN_H
|
||||
#define EIGEN_THREADPOOL_FORKJOIN_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
// ForkJoinScheduler provides implementations of various non-blocking ParallelFor algorithms for unary
|
||||
// and binary parallel tasks. More specifically, the implementations follow the binary tree-based
|
||||
// algorithm from the following paper:
|
||||
//
|
||||
// Lea, D. (2000, June). A java fork/join framework. *In Proceedings of the
|
||||
// ACM 2000 conference on Java Grande* (pp. 36-43).
|
||||
//
|
||||
// For a given binary task function `f(i,j)` and integers `num_threads`, `granularity`, `start`, and `end`,
|
||||
// the implemented parallel for algorithm schedules and executes at most `num_threads` of the functions
|
||||
// from the following set in parallel (either synchronously or asynchronously):
|
||||
//
|
||||
// f(start,start+s_1), f(start+s_1,start+s_2), ..., f(start+s_n,end)
|
||||
//
|
||||
// where `s_{j+1} - s_{j}` and `end - s_n` are roughly within a factor of two of `granularity`. For a unary
|
||||
// task function `g(k)`, the same operation is applied with
|
||||
//
|
||||
// f(i,j) = [&](){ for(Index k = i; k < j; ++k) g(k); };
|
||||
//
|
||||
// Note that the parameter `granularity` should be tuned by the user based on the trade-off of running the
|
||||
// given task function sequentially vs. scheduling individual tasks in parallel. An example of a partially
|
||||
// tuned `granularity` is in `Eigen::CoreThreadPoolDevice::parallelFor(...)` where the template
|
||||
// parameter `PacketSize` and float input `cost` are used to indirectly compute a granularity level for a
|
||||
// given task function.
|
||||
//
|
||||
// Example usage #1 (synchronous):
|
||||
// ```
|
||||
// ThreadPool thread_pool(num_threads);
|
||||
// ForkJoinScheduler::ParallelFor(0, num_tasks, granularity, std::move(parallel_task), &thread_pool);
|
||||
// ```
|
||||
//
|
||||
// Example usage #2 (executing multiple tasks asynchronously, each one parallelized with ParallelFor):
|
||||
// ```
|
||||
// ThreadPool thread_pool(num_threads);
|
||||
// Barrier barrier(num_async_calls);
|
||||
// auto done = [&](){ barrier.Notify(); };
|
||||
// for (Index k=0; k<num_async_calls; ++k) {
|
||||
// ForkJoinScheduler::ParallelForAsync(task_start[k], task_end[k], granularity[k], parallel_task[k], done,
|
||||
// &thread_pool);
|
||||
// }
|
||||
// barrier.Wait();
|
||||
// ```
|
||||
class ForkJoinScheduler {
|
||||
public:
|
||||
// Runs `do_func` asynchronously for the range [start, end) with a specified
|
||||
// granularity. `do_func` should be of type `std::function<void(Index,
|
||||
// Index)`. `done()` is called exactly once after all tasks have been executed.
|
||||
template <typename DoFnType, typename DoneFnType, typename ThreadPoolEnv>
|
||||
static void ParallelForAsync(Index start, Index end, Index granularity, DoFnType&& do_func, DoneFnType&& done,
|
||||
ThreadPoolTempl<ThreadPoolEnv>* thread_pool) {
|
||||
if (start >= end) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
thread_pool->Schedule([start, end, granularity, thread_pool, do_func = std::forward<DoFnType>(do_func),
|
||||
done = std::forward<DoneFnType>(done)]() {
|
||||
RunParallelFor(start, end, granularity, do_func, thread_pool);
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
// Synchronous variant of ParallelForAsync.
|
||||
// WARNING: Making nested calls to `ParallelFor`, e.g., calling `ParallelFor` inside a task passed into another
|
||||
// `ParallelFor` call, may lead to deadlocks due to how task stealing is implemented.
|
||||
template <typename DoFnType, typename ThreadPoolEnv>
|
||||
static void ParallelFor(Index start, Index end, Index granularity, DoFnType&& do_func,
|
||||
ThreadPoolTempl<ThreadPoolEnv>* thread_pool) {
|
||||
if (start >= end) return;
|
||||
Barrier barrier(1);
|
||||
auto done = [&barrier]() { barrier.Notify(); };
|
||||
ParallelForAsync(start, end, granularity, do_func, done, thread_pool);
|
||||
barrier.Wait();
|
||||
}
|
||||
|
||||
private:
|
||||
// Schedules `right_thunk`, runs `left_thunk`, and runs other tasks until `right_thunk` has finished.
|
||||
template <typename LeftType, typename RightType, typename ThreadPoolEnv>
|
||||
static void ForkJoin(LeftType&& left_thunk, RightType&& right_thunk, ThreadPoolTempl<ThreadPoolEnv>* thread_pool) {
|
||||
typedef typename ThreadPoolTempl<ThreadPoolEnv>::Task Task;
|
||||
std::atomic<bool> right_done(false);
|
||||
auto execute_right = [&right_thunk, &right_done]() {
|
||||
std::forward<RightType>(right_thunk)();
|
||||
right_done.store(true, std::memory_order_release);
|
||||
};
|
||||
thread_pool->Schedule(execute_right);
|
||||
std::forward<LeftType>(left_thunk)();
|
||||
Task task;
|
||||
while (!right_done.load(std::memory_order_acquire)) {
|
||||
thread_pool->MaybeGetTask(&task);
|
||||
if (task.f) task.f();
|
||||
}
|
||||
}
|
||||
|
||||
static Index ComputeMidpoint(Index start, Index end, Index granularity) {
|
||||
// Typical workloads choose initial values of `{start, end, granularity}` such that `start - end` and
|
||||
// `granularity` are powers of two. Since modern processors usually implement (2^x)-way
|
||||
// set-associative caches, we minimize the number of cache misses by choosing midpoints that are not
|
||||
// powers of two (to avoid having two addresses in the main memory pointing to the same point in the
|
||||
// cache). More specifically, we choose the midpoint at (roughly) the 9/16 mark.
|
||||
const Index size = end - start;
|
||||
const Index offset = numext::round_down(9 * (size + 1) / 16, granularity);
|
||||
return start + offset;
|
||||
}
|
||||
|
||||
template <typename DoFnType, typename ThreadPoolEnv>
|
||||
static void RunParallelFor(Index start, Index end, Index granularity, DoFnType&& do_func,
|
||||
ThreadPoolTempl<ThreadPoolEnv>* thread_pool) {
|
||||
Index mid = ComputeMidpoint(start, end, granularity);
|
||||
if ((end - start) < granularity || mid == start || mid == end) {
|
||||
do_func(start, end);
|
||||
return;
|
||||
}
|
||||
ForkJoin([start, mid, granularity, &do_func,
|
||||
thread_pool]() { RunParallelFor(start, mid, granularity, do_func, thread_pool); },
|
||||
[mid, end, granularity, &do_func, thread_pool]() {
|
||||
RunParallelFor(mid, end, granularity, do_func, thread_pool);
|
||||
},
|
||||
thread_pool);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_THREADPOOL_FORKJOIN_H
|
||||
@@ -0,0 +1,4 @@
|
||||
#ifndef EIGEN_THREADPOOL_MODULE_H
|
||||
#error \
|
||||
"Please include unsupported/Eigen/CXX11/ThreadPool instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,587 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2016 Dmitry Vyukov <dvyukov@google.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_CXX11_THREADPOOL_NONBLOCKING_THREAD_POOL_H
|
||||
#define EIGEN_CXX11_THREADPOOL_NONBLOCKING_THREAD_POOL_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
template <typename Environment>
|
||||
class ThreadPoolTempl : public Eigen::ThreadPoolInterface {
|
||||
public:
|
||||
typedef typename Environment::EnvThread Thread;
|
||||
typedef typename Environment::Task Task;
|
||||
typedef RunQueue<Task, 1024> Queue;
|
||||
|
||||
struct PerThread {
|
||||
constexpr PerThread() : pool(NULL), rand(0), thread_id(-1) {}
|
||||
ThreadPoolTempl* pool; // Parent pool, or null for normal threads.
|
||||
uint64_t rand; // Random generator state.
|
||||
int thread_id; // Worker thread index in pool.
|
||||
};
|
||||
|
||||
struct ThreadData {
|
||||
constexpr ThreadData() : thread(), steal_partition(0), queue() {}
|
||||
std::unique_ptr<Thread> thread;
|
||||
std::atomic<unsigned> steal_partition;
|
||||
Queue queue;
|
||||
};
|
||||
|
||||
ThreadPoolTempl(int num_threads, Environment env = Environment()) : ThreadPoolTempl(num_threads, true, env) {}
|
||||
|
||||
ThreadPoolTempl(int num_threads, bool allow_spinning, Environment env = Environment())
|
||||
: env_(env),
|
||||
num_threads_(num_threads),
|
||||
allow_spinning_(allow_spinning),
|
||||
spin_count_(
|
||||
// TODO(dvyukov,rmlarsen): The time spent in NonEmptyQueueIndex() is proportional to num_threads_ and
|
||||
// we assume that new work is scheduled at a constant rate, so we divide `kSpintCount` by number of
|
||||
// threads and number of spinning threads. The constant was picked based on a fair dice roll, tune it.
|
||||
allow_spinning && num_threads > 0 ? kSpinCount / kMaxSpinningThreads / num_threads : 0),
|
||||
thread_data_(num_threads),
|
||||
all_coprimes_(num_threads),
|
||||
waiters_(num_threads),
|
||||
global_steal_partition_(EncodePartition(0, num_threads_)),
|
||||
spinning_state_(0),
|
||||
blocked_(0),
|
||||
done_(false),
|
||||
cancelled_(false),
|
||||
ec_(waiters_) {
|
||||
waiters_.resize(num_threads_);
|
||||
// Calculate coprimes of all numbers [1, num_threads].
|
||||
// Coprimes are used for random walks over all threads in Steal
|
||||
// and NonEmptyQueueIndex. Iteration is based on the fact that if we take
|
||||
// a random starting thread index t and calculate num_threads - 1 subsequent
|
||||
// indices as (t + coprime) % num_threads, we will cover all threads without
|
||||
// repetitions (effectively getting a presudo-random permutation of thread
|
||||
// indices).
|
||||
eigen_plain_assert(num_threads_ < kMaxThreads);
|
||||
for (int i = 1; i <= num_threads_; ++i) {
|
||||
all_coprimes_.emplace_back(i);
|
||||
ComputeCoprimes(i, &all_coprimes_.back());
|
||||
}
|
||||
#ifndef EIGEN_THREAD_LOCAL
|
||||
init_barrier_.reset(new Barrier(num_threads_));
|
||||
#endif
|
||||
thread_data_.resize(num_threads_);
|
||||
for (int i = 0; i < num_threads_; i++) {
|
||||
SetStealPartition(i, EncodePartition(0, num_threads_));
|
||||
thread_data_[i].thread.reset(env_.CreateThread([this, i]() { WorkerLoop(i); }));
|
||||
}
|
||||
#ifndef EIGEN_THREAD_LOCAL
|
||||
// Wait for workers to initialize per_thread_map_. Otherwise we might race
|
||||
// with them in Schedule or CurrentThreadId.
|
||||
init_barrier_->Wait();
|
||||
#endif
|
||||
}
|
||||
|
||||
~ThreadPoolTempl() {
|
||||
done_ = true;
|
||||
|
||||
// Now if all threads block without work, they will start exiting.
|
||||
// But note that threads can continue to work arbitrary long,
|
||||
// block, submit new work, unblock and otherwise live full life.
|
||||
if (!cancelled_) {
|
||||
ec_.Notify(true);
|
||||
} else {
|
||||
// Since we were cancelled, there might be entries in the queues.
|
||||
// Empty them to prevent their destructor from asserting.
|
||||
for (size_t i = 0; i < thread_data_.size(); i++) {
|
||||
thread_data_[i].queue.Flush();
|
||||
}
|
||||
}
|
||||
// Join threads explicitly (by destroying) to avoid destruction order within
|
||||
// this class.
|
||||
for (size_t i = 0; i < thread_data_.size(); ++i) thread_data_[i].thread.reset();
|
||||
}
|
||||
|
||||
void SetStealPartitions(const std::vector<std::pair<unsigned, unsigned>>& partitions) {
|
||||
eigen_plain_assert(partitions.size() == static_cast<std::size_t>(num_threads_));
|
||||
|
||||
// Pass this information to each thread queue.
|
||||
for (int i = 0; i < num_threads_; i++) {
|
||||
const auto& pair = partitions[i];
|
||||
unsigned start = pair.first, end = pair.second;
|
||||
AssertBounds(start, end);
|
||||
unsigned val = EncodePartition(start, end);
|
||||
SetStealPartition(i, val);
|
||||
}
|
||||
}
|
||||
|
||||
void Schedule(std::function<void()> fn) EIGEN_OVERRIDE { ScheduleWithHint(std::move(fn), 0, num_threads_); }
|
||||
|
||||
void ScheduleWithHint(std::function<void()> fn, int start, int limit) override {
|
||||
Task t = env_.CreateTask(std::move(fn));
|
||||
PerThread* pt = GetPerThread();
|
||||
if (pt->pool == this) {
|
||||
// Worker thread of this pool, push onto the thread's queue.
|
||||
Queue& q = thread_data_[pt->thread_id].queue;
|
||||
t = q.PushFront(std::move(t));
|
||||
} else {
|
||||
// A free-standing thread (or worker of another pool), push onto a random
|
||||
// queue.
|
||||
eigen_plain_assert(start < limit);
|
||||
eigen_plain_assert(limit <= num_threads_);
|
||||
int num_queues = limit - start;
|
||||
int rnd = Rand(&pt->rand) % num_queues;
|
||||
eigen_plain_assert(start + rnd < limit);
|
||||
Queue& q = thread_data_[start + rnd].queue;
|
||||
t = q.PushBack(std::move(t));
|
||||
}
|
||||
// Note: below we touch this after making w available to worker threads.
|
||||
// Strictly speaking, this can lead to a racy-use-after-free. Consider that
|
||||
// Schedule is called from a thread that is neither main thread nor a worker
|
||||
// thread of this pool. Then, execution of w directly or indirectly
|
||||
// completes overall computations, which in turn leads to destruction of
|
||||
// this. We expect that such scenario is prevented by program, that is,
|
||||
// this is kept alive while any threads can potentially be in Schedule.
|
||||
if (!t.f) {
|
||||
if (IsNotifyParkedThreadRequired()) {
|
||||
ec_.Notify(false);
|
||||
}
|
||||
} else {
|
||||
env_.ExecuteTask(t); // Push failed, execute directly.
|
||||
}
|
||||
}
|
||||
|
||||
// Tries to assign work to the current task.
|
||||
void MaybeGetTask(Task* t) {
|
||||
PerThread* pt = GetPerThread();
|
||||
const int thread_id = pt->thread_id;
|
||||
// If we are not a worker thread of this pool, we can't get any work.
|
||||
if (thread_id < 0) return;
|
||||
Queue& q = thread_data_[thread_id].queue;
|
||||
*t = q.PopFront();
|
||||
if (t->f) return;
|
||||
if (num_threads_ == 1) {
|
||||
// For num_threads_ == 1 there is no point in going through the expensive
|
||||
// steal loop. Moreover, since NonEmptyQueueIndex() calls PopBack() on the
|
||||
// victim queues it might reverse the order in which ops are executed
|
||||
// compared to the order in which they are scheduled, which tends to be
|
||||
// counter-productive for the types of I/O workloads single thread pools
|
||||
// tend to be used for.
|
||||
for (int i = 0; i < spin_count_ && !t->f; ++i) *t = q.PopFront();
|
||||
} else {
|
||||
if (EIGEN_PREDICT_FALSE(!t->f)) *t = LocalSteal();
|
||||
if (EIGEN_PREDICT_FALSE(!t->f)) *t = GlobalSteal();
|
||||
if (EIGEN_PREDICT_FALSE(!t->f)) {
|
||||
if (allow_spinning_ && StartSpinning()) {
|
||||
for (int i = 0; i < spin_count_ && !t->f; ++i) *t = GlobalSteal();
|
||||
// Notify `spinning_state_` that we are no longer spinning.
|
||||
bool has_no_notify_task = StopSpinning();
|
||||
// If a task was submitted to the queue without a call to
|
||||
// `ec_.Notify()` (if `IsNotifyParkedThreadRequired()` returned
|
||||
// false), and we didn't steal anything above, we must try to
|
||||
// steal one more time, to make sure that this task will be
|
||||
// executed. We will not necessarily find it, because it might
|
||||
// have been already stolen by some other thread.
|
||||
if (has_no_notify_task && !t->f) *t = GlobalSteal();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cancel() EIGEN_OVERRIDE {
|
||||
cancelled_ = true;
|
||||
done_ = true;
|
||||
|
||||
// Let each thread know it's been cancelled.
|
||||
#ifdef EIGEN_THREAD_ENV_SUPPORTS_CANCELLATION
|
||||
for (size_t i = 0; i < thread_data_.size(); i++) {
|
||||
thread_data_[i].thread->OnCancel();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Wake up the threads without work to let them exit on their own.
|
||||
ec_.Notify(true);
|
||||
}
|
||||
|
||||
int NumThreads() const EIGEN_FINAL { return num_threads_; }
|
||||
|
||||
int CurrentThreadId() const EIGEN_FINAL {
|
||||
const PerThread* pt = const_cast<ThreadPoolTempl*>(this)->GetPerThread();
|
||||
if (pt->pool == this) {
|
||||
return pt->thread_id;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Create a single atomic<int> that encodes start and limit information for
|
||||
// each thread.
|
||||
// We expect num_threads_ < 65536, so we can store them in a single
|
||||
// std::atomic<unsigned>.
|
||||
// Exposed publicly as static functions so that external callers can reuse
|
||||
// this encode/decode logic for maintaining their own thread-safe copies of
|
||||
// scheduling and steal domain(s).
|
||||
static constexpr int kMaxPartitionBits = 16;
|
||||
static constexpr int kMaxThreads = 1 << kMaxPartitionBits;
|
||||
|
||||
inline unsigned EncodePartition(unsigned start, unsigned limit) { return (start << kMaxPartitionBits) | limit; }
|
||||
|
||||
inline void DecodePartition(unsigned val, unsigned* start, unsigned* limit) {
|
||||
*limit = val & (kMaxThreads - 1);
|
||||
val >>= kMaxPartitionBits;
|
||||
*start = val;
|
||||
}
|
||||
|
||||
void AssertBounds(int start, int end) {
|
||||
eigen_plain_assert(start >= 0);
|
||||
eigen_plain_assert(start < end); // non-zero sized partition
|
||||
eigen_plain_assert(end <= num_threads_);
|
||||
}
|
||||
|
||||
inline void SetStealPartition(size_t i, unsigned val) {
|
||||
thread_data_[i].steal_partition.store(val, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline unsigned GetStealPartition(int i) { return thread_data_[i].steal_partition.load(std::memory_order_relaxed); }
|
||||
|
||||
void ComputeCoprimes(int N, MaxSizeVector<unsigned>* coprimes) {
|
||||
for (int i = 1; i <= N; i++) {
|
||||
unsigned a = i;
|
||||
unsigned b = N;
|
||||
// If GCD(a, b) == 1, then a and b are coprimes.
|
||||
while (b != 0) {
|
||||
unsigned tmp = a;
|
||||
a = b;
|
||||
b = tmp % b;
|
||||
}
|
||||
if (a == 1) {
|
||||
coprimes->push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Maximum number of threads that can spin in steal loop.
|
||||
static constexpr int kMaxSpinningThreads = 1;
|
||||
|
||||
// The number of steal loop spin iterations before parking (this number is
|
||||
// divided by the number of threads, to get spin count for each thread).
|
||||
static constexpr int kSpinCount = 5000;
|
||||
|
||||
// If there are enough active threads with empty pending-task queues, a thread
|
||||
// that runs out of work can just be parked without spinning, because these
|
||||
// active threads will go into a steal loop after finishing their current
|
||||
// tasks.
|
||||
//
|
||||
// In the worst case when all active threads are executing long/expensive
|
||||
// tasks, the next Schedule() will have to wait until one of the parked
|
||||
// threads will be unparked, however this should be very rare in practice.
|
||||
static constexpr int kMinActiveThreadsToStartSpinning = 4;
|
||||
|
||||
struct SpinningState {
|
||||
// Spinning state layout:
|
||||
//
|
||||
// - Low 32 bits encode the number of threads that are spinning in steal
|
||||
// loop.
|
||||
//
|
||||
// - High 32 bits encode the number of tasks that were submitted to the pool
|
||||
// without a call to `ec_.Notify()`. This number can't be larger than
|
||||
// the number of spinning threads. Each spinning thread, when it exits the
|
||||
// spin loop must check if this number is greater than zero, and maybe
|
||||
// make another attempt to steal a task and decrement it by one.
|
||||
static constexpr uint64_t kNumSpinningMask = 0x00000000FFFFFFFF;
|
||||
static constexpr uint64_t kNumNoNotifyMask = 0xFFFFFFFF00000000;
|
||||
static constexpr uint64_t kNumNoNotifyShift = 32;
|
||||
|
||||
uint64_t num_spinning; // number of spinning threads
|
||||
uint64_t num_no_notification; // number of tasks submitted without
|
||||
// notifying waiting threads
|
||||
|
||||
// Decodes `spinning_state_` value.
|
||||
static SpinningState Decode(uint64_t state) {
|
||||
uint64_t num_spinning = (state & kNumSpinningMask);
|
||||
uint64_t num_no_notification = (state & kNumNoNotifyMask) >> kNumNoNotifyShift;
|
||||
|
||||
eigen_plain_assert(num_no_notification <= num_spinning);
|
||||
return {num_spinning, num_no_notification};
|
||||
}
|
||||
|
||||
// Encodes as `spinning_state_` value.
|
||||
uint64_t Encode() const {
|
||||
eigen_plain_assert(num_no_notification <= num_spinning);
|
||||
return (num_no_notification << kNumNoNotifyShift) | num_spinning;
|
||||
}
|
||||
};
|
||||
|
||||
Environment env_;
|
||||
const int num_threads_;
|
||||
const bool allow_spinning_;
|
||||
const int spin_count_;
|
||||
MaxSizeVector<ThreadData> thread_data_;
|
||||
MaxSizeVector<MaxSizeVector<unsigned>> all_coprimes_;
|
||||
MaxSizeVector<EventCount::Waiter> waiters_;
|
||||
unsigned global_steal_partition_;
|
||||
std::atomic<uint64_t> spinning_state_;
|
||||
std::atomic<unsigned> blocked_;
|
||||
std::atomic<bool> done_;
|
||||
std::atomic<bool> cancelled_;
|
||||
EventCount ec_;
|
||||
#ifndef EIGEN_THREAD_LOCAL
|
||||
std::unique_ptr<Barrier> init_barrier_;
|
||||
EIGEN_MUTEX per_thread_map_mutex_; // Protects per_thread_map_.
|
||||
std::unordered_map<uint64_t, std::unique_ptr<PerThread>> per_thread_map_;
|
||||
#endif
|
||||
|
||||
unsigned NumBlockedThreads() const { return blocked_.load(); }
|
||||
unsigned NumActiveThreads() const { return num_threads_ - blocked_.load(); }
|
||||
|
||||
// Main worker thread loop.
|
||||
void WorkerLoop(int thread_id) {
|
||||
#ifndef EIGEN_THREAD_LOCAL
|
||||
std::unique_ptr<PerThread> new_pt(new PerThread());
|
||||
per_thread_map_mutex_.lock();
|
||||
bool insertOK = per_thread_map_.emplace(GlobalThreadIdHash(), std::move(new_pt)).second;
|
||||
eigen_plain_assert(insertOK);
|
||||
EIGEN_UNUSED_VARIABLE(insertOK);
|
||||
per_thread_map_mutex_.unlock();
|
||||
init_barrier_->Notify();
|
||||
init_barrier_->Wait();
|
||||
#endif
|
||||
PerThread* pt = GetPerThread();
|
||||
pt->pool = this;
|
||||
pt->rand = GlobalThreadIdHash();
|
||||
pt->thread_id = thread_id;
|
||||
Task t;
|
||||
while (!cancelled_.load(std::memory_order_relaxed)) {
|
||||
MaybeGetTask(&t);
|
||||
// If we still don't have a task, wait for one. Return if thread pool is
|
||||
// in cancelled state.
|
||||
if (EIGEN_PREDICT_FALSE(!t.f)) {
|
||||
EventCount::Waiter* waiter = &waiters_[pt->thread_id];
|
||||
if (!WaitForWork(waiter, &t)) return;
|
||||
}
|
||||
if (EIGEN_PREDICT_TRUE(t.f)) env_.ExecuteTask(t);
|
||||
}
|
||||
}
|
||||
|
||||
// Steal tries to steal work from other worker threads in the range [start,
|
||||
// limit) in best-effort manner.
|
||||
Task Steal(unsigned start, unsigned limit) {
|
||||
PerThread* pt = GetPerThread();
|
||||
const size_t size = limit - start;
|
||||
unsigned r = Rand(&pt->rand);
|
||||
// Reduce r into [0, size) range, this utilizes trick from
|
||||
// https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
|
||||
eigen_plain_assert(all_coprimes_[size - 1].size() < (1 << 30));
|
||||
unsigned victim = ((uint64_t)r * (uint64_t)size) >> 32;
|
||||
unsigned index = ((uint64_t)all_coprimes_[size - 1].size() * (uint64_t)r) >> 32;
|
||||
unsigned inc = all_coprimes_[size - 1][index];
|
||||
|
||||
for (unsigned i = 0; i < size; i++) {
|
||||
eigen_plain_assert(start + victim < limit);
|
||||
Task t = thread_data_[start + victim].queue.PopBack();
|
||||
if (t.f) {
|
||||
return t;
|
||||
}
|
||||
victim += inc;
|
||||
if (victim >= size) {
|
||||
victim -= static_cast<unsigned int>(size);
|
||||
}
|
||||
}
|
||||
return Task();
|
||||
}
|
||||
|
||||
// Steals work within threads belonging to the partition.
|
||||
Task LocalSteal() {
|
||||
PerThread* pt = GetPerThread();
|
||||
unsigned partition = GetStealPartition(pt->thread_id);
|
||||
// If thread steal partition is the same as global partition, there is no
|
||||
// need to go through the steal loop twice.
|
||||
if (global_steal_partition_ == partition) return Task();
|
||||
unsigned start, limit;
|
||||
DecodePartition(partition, &start, &limit);
|
||||
AssertBounds(start, limit);
|
||||
|
||||
return Steal(start, limit);
|
||||
}
|
||||
|
||||
// Steals work from any other thread in the pool.
|
||||
Task GlobalSteal() { return Steal(0, num_threads_); }
|
||||
|
||||
// WaitForWork blocks until new work is available (returns true), or if it is
|
||||
// time to exit (returns false). Can optionally return a task to execute in t
|
||||
// (in such case t.f != nullptr on return).
|
||||
bool WaitForWork(EventCount::Waiter* waiter, Task* t) {
|
||||
eigen_plain_assert(!t->f);
|
||||
// We already did best-effort emptiness check in Steal, so prepare for
|
||||
// blocking.
|
||||
ec_.Prewait();
|
||||
// Now do a reliable emptiness check.
|
||||
int victim = NonEmptyQueueIndex();
|
||||
if (victim != -1) {
|
||||
ec_.CancelWait();
|
||||
if (cancelled_) {
|
||||
return false;
|
||||
} else {
|
||||
*t = thread_data_[victim].queue.PopBack();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Number of blocked threads is used as termination condition.
|
||||
// If we are shutting down and all worker threads blocked without work,
|
||||
// that's we are done.
|
||||
blocked_++;
|
||||
// TODO is blocked_ required to be unsigned?
|
||||
if (done_ && blocked_ == static_cast<unsigned>(num_threads_)) {
|
||||
ec_.CancelWait();
|
||||
// Almost done, but need to re-check queues.
|
||||
// Consider that all queues are empty and all worker threads are preempted
|
||||
// right after incrementing blocked_ above. Now a free-standing thread
|
||||
// submits work and calls destructor (which sets done_). If we don't
|
||||
// re-check queues, we will exit leaving the work unexecuted.
|
||||
if (NonEmptyQueueIndex() != -1) {
|
||||
// Note: we must not pop from queues before we decrement blocked_,
|
||||
// otherwise the following scenario is possible. Consider that instead
|
||||
// of checking for emptiness we popped the only element from queues.
|
||||
// Now other worker threads can start exiting, which is bad if the
|
||||
// work item submits other work. So we just check emptiness here,
|
||||
// which ensures that all worker threads exit at the same time.
|
||||
blocked_--;
|
||||
return true;
|
||||
}
|
||||
// Reached stable termination state.
|
||||
ec_.Notify(true);
|
||||
return false;
|
||||
}
|
||||
ec_.CommitWait(waiter);
|
||||
blocked_--;
|
||||
return true;
|
||||
}
|
||||
|
||||
int NonEmptyQueueIndex() {
|
||||
PerThread* pt = GetPerThread();
|
||||
// We intentionally design NonEmptyQueueIndex to steal work from
|
||||
// anywhere in the queue so threads don't block in WaitForWork() forever
|
||||
// when all threads in their partition go to sleep. Steal is still local.
|
||||
const size_t size = thread_data_.size();
|
||||
unsigned r = Rand(&pt->rand);
|
||||
unsigned inc = all_coprimes_[size - 1][r % all_coprimes_[size - 1].size()];
|
||||
unsigned victim = r % size;
|
||||
for (unsigned i = 0; i < size; i++) {
|
||||
if (!thread_data_[victim].queue.Empty()) {
|
||||
return victim;
|
||||
}
|
||||
victim += inc;
|
||||
if (victim >= size) {
|
||||
victim -= static_cast<unsigned int>(size);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// StartSpinning() checks if the number of threads in the spin loop is less
|
||||
// than the allowed maximum. If so, increments the number of spinning threads
|
||||
// by one and returns true (caller must enter the spin loop). Otherwise
|
||||
// returns false, and the caller must not enter the spin loop.
|
||||
bool StartSpinning() {
|
||||
if (NumActiveThreads() > kMinActiveThreadsToStartSpinning) return false;
|
||||
|
||||
uint64_t spinning = spinning_state_.load(std::memory_order_relaxed);
|
||||
for (;;) {
|
||||
SpinningState state = SpinningState::Decode(spinning);
|
||||
|
||||
if ((state.num_spinning - state.num_no_notification) >= kMaxSpinningThreads) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Increment the number of spinning threads.
|
||||
++state.num_spinning;
|
||||
|
||||
if (spinning_state_.compare_exchange_weak(spinning, state.Encode(), std::memory_order_relaxed)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// StopSpinning() decrements the number of spinning threads by one. It also
|
||||
// checks if there were any tasks submitted into the pool without notifying
|
||||
// parked threads, and decrements the count by one. Returns true if the number
|
||||
// of tasks submitted without notification was decremented. In this case,
|
||||
// caller thread might have to call Steal() one more time.
|
||||
bool StopSpinning() {
|
||||
uint64_t spinning = spinning_state_.load(std::memory_order_relaxed);
|
||||
for (;;) {
|
||||
SpinningState state = SpinningState::Decode(spinning);
|
||||
|
||||
// Decrement the number of spinning threads.
|
||||
--state.num_spinning;
|
||||
|
||||
// Maybe decrement the number of tasks submitted without notification.
|
||||
bool has_no_notify_task = state.num_no_notification > 0;
|
||||
if (has_no_notify_task) --state.num_no_notification;
|
||||
|
||||
if (spinning_state_.compare_exchange_weak(spinning, state.Encode(), std::memory_order_relaxed)) {
|
||||
return has_no_notify_task;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IsNotifyParkedThreadRequired() returns true if parked thread must be
|
||||
// notified about new added task. If there are threads spinning in the steal
|
||||
// loop, there is no need to unpark any of the waiting threads, the task will
|
||||
// be picked up by one of the spinning threads.
|
||||
bool IsNotifyParkedThreadRequired() {
|
||||
uint64_t spinning = spinning_state_.load(std::memory_order_relaxed);
|
||||
for (;;) {
|
||||
SpinningState state = SpinningState::Decode(spinning);
|
||||
|
||||
// If the number of tasks submitted without notifying parked threads is
|
||||
// equal to the number of spinning threads, we must wake up one of the
|
||||
// parked threads.
|
||||
if (state.num_no_notification == state.num_spinning) return true;
|
||||
|
||||
// Increment the number of tasks submitted without notification.
|
||||
++state.num_no_notification;
|
||||
|
||||
if (spinning_state_.compare_exchange_weak(spinning, state.Encode(), std::memory_order_relaxed)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static EIGEN_STRONG_INLINE uint64_t GlobalThreadIdHash() {
|
||||
return std::hash<std::thread::id>()(std::this_thread::get_id());
|
||||
}
|
||||
|
||||
EIGEN_STRONG_INLINE PerThread* GetPerThread() {
|
||||
#ifndef EIGEN_THREAD_LOCAL
|
||||
static PerThread dummy;
|
||||
auto it = per_thread_map_.find(GlobalThreadIdHash());
|
||||
if (it == per_thread_map_.end()) {
|
||||
return &dummy;
|
||||
} else {
|
||||
return it->second.get();
|
||||
}
|
||||
#else
|
||||
EIGEN_THREAD_LOCAL PerThread per_thread_;
|
||||
PerThread* pt = &per_thread_;
|
||||
return pt;
|
||||
#endif
|
||||
}
|
||||
|
||||
static EIGEN_STRONG_INLINE unsigned Rand(uint64_t* state) {
|
||||
uint64_t current = *state;
|
||||
// Update the internal state
|
||||
*state = current * 6364136223846793005ULL + 0xda3e39cb94b95bdbULL;
|
||||
// Generate the random output (using the PCG-XSH-RS scheme)
|
||||
return static_cast<unsigned>((current ^ (current >> 22)) >> (22 + (current >> 61)));
|
||||
}
|
||||
};
|
||||
|
||||
typedef ThreadPoolTempl<StlThreadEnvironment> ThreadPool;
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_CXX11_THREADPOOL_NONBLOCKING_THREAD_POOL_H
|
||||
@@ -0,0 +1,230 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2016 Dmitry Vyukov <dvyukov@google.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_CXX11_THREADPOOL_RUNQUEUE_H
|
||||
#define EIGEN_CXX11_THREADPOOL_RUNQUEUE_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
// RunQueue is a fixed-size, partially non-blocking deque or Work items.
|
||||
// Operations on front of the queue must be done by a single thread (owner),
|
||||
// operations on back of the queue can be done by multiple threads concurrently.
|
||||
//
|
||||
// Algorithm outline:
|
||||
// All remote threads operating on the queue back are serialized by a mutex.
|
||||
// This ensures that at most two threads access state: owner and one remote
|
||||
// thread (Size aside). The algorithm ensures that the occupied region of the
|
||||
// underlying array is logically continuous (can wraparound, but no stray
|
||||
// occupied elements). Owner operates on one end of this region, remote thread
|
||||
// operates on the other end. Synchronization between these threads
|
||||
// (potential consumption of the last element and take up of the last empty
|
||||
// element) happens by means of state variable in each element. States are:
|
||||
// empty, busy (in process of insertion of removal) and ready. Threads claim
|
||||
// elements (empty->busy and ready->busy transitions) by means of a CAS
|
||||
// operation. The finishing transition (busy->empty and busy->ready) are done
|
||||
// with plain store as the element is exclusively owned by the current thread.
|
||||
//
|
||||
// Note: we could permit only pointers as elements, then we would not need
|
||||
// separate state variable as null/non-null pointer value would serve as state,
|
||||
// but that would require malloc/free per operation for large, complex values
|
||||
// (and this is designed to store std::function<()>).
|
||||
template <typename Work, unsigned kSize>
|
||||
class RunQueue {
|
||||
public:
|
||||
RunQueue() : front_(0), back_(0) {
|
||||
// require power-of-two for fast masking
|
||||
eigen_plain_assert((kSize & (kSize - 1)) == 0);
|
||||
eigen_plain_assert(kSize > 2); // why would you do this?
|
||||
eigen_plain_assert(kSize <= (64 << 10)); // leave enough space for counter
|
||||
for (unsigned i = 0; i < kSize; i++) array_[i].state.store(kEmpty, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
~RunQueue() { eigen_plain_assert(Size() == 0); }
|
||||
|
||||
// PushFront inserts w at the beginning of the queue.
|
||||
// If queue is full returns w, otherwise returns default-constructed Work.
|
||||
Work PushFront(Work w) {
|
||||
unsigned front = front_.load(std::memory_order_relaxed);
|
||||
Elem* e = &array_[front & kMask];
|
||||
uint8_t s = e->state.load(std::memory_order_relaxed);
|
||||
if (s != kEmpty || !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire)) return w;
|
||||
front_.store(front + 1 + (kSize << 1), std::memory_order_relaxed);
|
||||
e->w = std::move(w);
|
||||
e->state.store(kReady, std::memory_order_release);
|
||||
return Work();
|
||||
}
|
||||
|
||||
// PopFront removes and returns the first element in the queue.
|
||||
// If the queue was empty returns default-constructed Work.
|
||||
Work PopFront() {
|
||||
unsigned front = front_.load(std::memory_order_relaxed);
|
||||
Elem* e = &array_[(front - 1) & kMask];
|
||||
uint8_t s = e->state.load(std::memory_order_relaxed);
|
||||
if (s != kReady || !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire)) return Work();
|
||||
Work w = std::move(e->w);
|
||||
e->state.store(kEmpty, std::memory_order_release);
|
||||
front = ((front - 1) & kMask2) | (front & ~kMask2);
|
||||
front_.store(front, std::memory_order_relaxed);
|
||||
return w;
|
||||
}
|
||||
|
||||
// PushBack adds w at the end of the queue.
|
||||
// If queue is full returns w, otherwise returns default-constructed Work.
|
||||
Work PushBack(Work w) {
|
||||
EIGEN_MUTEX_LOCK lock(mutex_);
|
||||
unsigned back = back_.load(std::memory_order_relaxed);
|
||||
Elem* e = &array_[(back - 1) & kMask];
|
||||
uint8_t s = e->state.load(std::memory_order_relaxed);
|
||||
if (s != kEmpty || !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire)) return w;
|
||||
back = ((back - 1) & kMask2) | (back & ~kMask2);
|
||||
back_.store(back, std::memory_order_relaxed);
|
||||
e->w = std::move(w);
|
||||
e->state.store(kReady, std::memory_order_release);
|
||||
return Work();
|
||||
}
|
||||
|
||||
// PopBack removes and returns the last elements in the queue.
|
||||
Work PopBack() {
|
||||
if (Empty()) return Work();
|
||||
EIGEN_MUTEX_LOCK lock(mutex_);
|
||||
unsigned back = back_.load(std::memory_order_relaxed);
|
||||
Elem* e = &array_[back & kMask];
|
||||
uint8_t s = e->state.load(std::memory_order_relaxed);
|
||||
if (s != kReady || !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire)) return Work();
|
||||
Work w = std::move(e->w);
|
||||
e->state.store(kEmpty, std::memory_order_release);
|
||||
back_.store(back + 1 + (kSize << 1), std::memory_order_relaxed);
|
||||
return w;
|
||||
}
|
||||
|
||||
// PopBackHalf removes and returns half last elements in the queue.
|
||||
// Returns number of elements removed.
|
||||
unsigned PopBackHalf(std::vector<Work>* result) {
|
||||
if (Empty()) return 0;
|
||||
EIGEN_MUTEX_LOCK lock(mutex_);
|
||||
unsigned back = back_.load(std::memory_order_relaxed);
|
||||
unsigned size = Size();
|
||||
unsigned mid = back;
|
||||
if (size > 1) mid = back + (size - 1) / 2;
|
||||
unsigned n = 0;
|
||||
unsigned start = 0;
|
||||
for (; static_cast<int>(mid - back) >= 0; mid--) {
|
||||
Elem* e = &array_[mid & kMask];
|
||||
uint8_t s = e->state.load(std::memory_order_relaxed);
|
||||
if (n == 0) {
|
||||
if (s != kReady || !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire)) continue;
|
||||
start = mid;
|
||||
} else {
|
||||
// Note: no need to store temporal kBusy, we exclusively own these
|
||||
// elements.
|
||||
eigen_plain_assert(s == kReady);
|
||||
}
|
||||
result->push_back(std::move(e->w));
|
||||
e->state.store(kEmpty, std::memory_order_release);
|
||||
n++;
|
||||
}
|
||||
if (n != 0) back_.store(start + 1 + (kSize << 1), std::memory_order_relaxed);
|
||||
return n;
|
||||
}
|
||||
|
||||
// Size returns current queue size.
|
||||
// Can be called by any thread at any time.
|
||||
unsigned Size() const { return SizeOrNotEmpty<true>(); }
|
||||
|
||||
// Empty tests whether container is empty.
|
||||
// Can be called by any thread at any time.
|
||||
bool Empty() const { return SizeOrNotEmpty<false>() == 0; }
|
||||
|
||||
// Delete all the elements from the queue.
|
||||
void Flush() {
|
||||
while (!Empty()) {
|
||||
PopFront();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static const unsigned kMask = kSize - 1;
|
||||
static const unsigned kMask2 = (kSize << 1) - 1;
|
||||
|
||||
enum State {
|
||||
kEmpty,
|
||||
kBusy,
|
||||
kReady,
|
||||
};
|
||||
|
||||
struct Elem {
|
||||
std::atomic<uint8_t> state;
|
||||
Work w;
|
||||
};
|
||||
|
||||
// Low log(kSize) + 1 bits in front_ and back_ contain rolling index of
|
||||
// front/back, respectively. The remaining bits contain modification counters
|
||||
// that are incremented on Push operations. This allows us to (1) distinguish
|
||||
// between empty and full conditions (if we would use log(kSize) bits for
|
||||
// position, these conditions would be indistinguishable); (2) obtain
|
||||
// consistent snapshot of front_/back_ for Size operation using the
|
||||
// modification counters.
|
||||
EIGEN_ALIGN_TO_AVOID_FALSE_SHARING std::atomic<unsigned> front_;
|
||||
EIGEN_ALIGN_TO_AVOID_FALSE_SHARING std::atomic<unsigned> back_;
|
||||
EIGEN_MUTEX mutex_; // guards `PushBack` and `PopBack` (accesses `back_`)
|
||||
|
||||
EIGEN_ALIGN_TO_AVOID_FALSE_SHARING Elem array_[kSize];
|
||||
|
||||
// SizeOrNotEmpty returns current queue size; if NeedSizeEstimate is false,
|
||||
// only whether the size is 0 is guaranteed to be correct.
|
||||
// Can be called by any thread at any time.
|
||||
template <bool NeedSizeEstimate>
|
||||
unsigned SizeOrNotEmpty() const {
|
||||
// Emptiness plays critical role in thread pool blocking. So we go to great
|
||||
// effort to not produce false positives (claim non-empty queue as empty).
|
||||
unsigned front = front_.load(std::memory_order_acquire);
|
||||
for (;;) {
|
||||
// Capture a consistent snapshot of front/tail.
|
||||
unsigned back = back_.load(std::memory_order_acquire);
|
||||
unsigned front1 = front_.load(std::memory_order_relaxed);
|
||||
if (front != front1) {
|
||||
front = front1;
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
continue;
|
||||
}
|
||||
if (NeedSizeEstimate) {
|
||||
return CalculateSize(front, back);
|
||||
} else {
|
||||
// This value will be 0 if the queue is empty, and undefined otherwise.
|
||||
unsigned maybe_zero = ((front ^ back) & kMask2);
|
||||
// Queue size estimate must agree with maybe zero check on the queue
|
||||
// empty/non-empty state.
|
||||
eigen_assert((CalculateSize(front, back) == 0) == (maybe_zero == 0));
|
||||
return maybe_zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EIGEN_ALWAYS_INLINE unsigned CalculateSize(unsigned front, unsigned back) const {
|
||||
int size = (front & kMask2) - (back & kMask2);
|
||||
// Fix overflow.
|
||||
if (EIGEN_PREDICT_FALSE(size < 0)) size += 2 * kSize;
|
||||
// Order of modification in push/pop is crafted to make the queue look
|
||||
// larger than it is during concurrent modifications. E.g. push can
|
||||
// increment size before the corresponding pop has decremented it.
|
||||
// So the computed size can be up to kSize + 1, fix it.
|
||||
if (EIGEN_PREDICT_FALSE(size > static_cast<int>(kSize))) size = kSize;
|
||||
return static_cast<unsigned>(size);
|
||||
}
|
||||
|
||||
RunQueue(const RunQueue&) = delete;
|
||||
void operator=(const RunQueue&) = delete;
|
||||
};
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_CXX11_THREADPOOL_RUNQUEUE_H
|
||||
@@ -0,0 +1,21 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2016 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_CXX11_THREADPOOL_THREAD_CANCEL_H
|
||||
#define EIGEN_CXX11_THREADPOOL_THREAD_CANCEL_H
|
||||
|
||||
// Try to come up with a portable way to cancel a thread
|
||||
#if EIGEN_OS_GNULINUX
|
||||
#define EIGEN_THREAD_CANCEL(t) pthread_cancel(t.native_handle());
|
||||
#define EIGEN_SUPPORTS_THREAD_CANCELLATION 1
|
||||
#else
|
||||
#define EIGEN_THREAD_CANCEL(t)
|
||||
#endif
|
||||
|
||||
#endif // EIGEN_CXX11_THREADPOOL_THREAD_CANCEL_H
|
||||
@@ -0,0 +1,43 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_CXX11_THREADPOOL_THREAD_ENVIRONMENT_H
|
||||
#define EIGEN_CXX11_THREADPOOL_THREAD_ENVIRONMENT_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
struct StlThreadEnvironment {
|
||||
struct Task {
|
||||
std::function<void()> f;
|
||||
};
|
||||
|
||||
// EnvThread constructor must start the thread,
|
||||
// destructor must join the thread.
|
||||
class EnvThread {
|
||||
public:
|
||||
EnvThread(std::function<void()> f) : thr_(std::move(f)) {}
|
||||
~EnvThread() { thr_.join(); }
|
||||
// This function is called when the threadpool is cancelled.
|
||||
void OnCancel() {}
|
||||
|
||||
private:
|
||||
std::thread thr_;
|
||||
};
|
||||
|
||||
EnvThread* CreateThread(std::function<void()> f) { return new EnvThread(std::move(f)); }
|
||||
Task CreateTask(std::function<void()> f) { return Task{std::move(f)}; }
|
||||
void ExecuteTask(const Task& t) { t.f(); }
|
||||
};
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_CXX11_THREADPOOL_THREAD_ENVIRONMENT_H
|
||||
@@ -0,0 +1,289 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2016 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_CXX11_THREADPOOL_THREAD_LOCAL_H
|
||||
#define EIGEN_CXX11_THREADPOOL_THREAD_LOCAL_H
|
||||
|
||||
#ifdef EIGEN_AVOID_THREAD_LOCAL
|
||||
|
||||
#ifdef EIGEN_THREAD_LOCAL
|
||||
#undef EIGEN_THREAD_LOCAL
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#if ((EIGEN_COMP_GNUC) || __has_feature(cxx_thread_local) || EIGEN_COMP_MSVC)
|
||||
#define EIGEN_THREAD_LOCAL static thread_local
|
||||
#endif
|
||||
|
||||
// Disable TLS for Apple and Android builds with older toolchains.
|
||||
#if defined(__APPLE__)
|
||||
// Included for TARGET_OS_IPHONE, __IPHONE_OS_VERSION_MIN_REQUIRED,
|
||||
// __IPHONE_8_0.
|
||||
#include <Availability.h>
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
// Checks whether C++11's `thread_local` storage duration specifier is
|
||||
// supported.
|
||||
#if EIGEN_COMP_CLANGAPPLE && \
|
||||
((EIGEN_COMP_CLANGAPPLE < 8000042) || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0))
|
||||
// Notes: Xcode's clang did not support `thread_local` until version
|
||||
// 8, and even then not for all iOS < 9.0.
|
||||
#undef EIGEN_THREAD_LOCAL
|
||||
|
||||
#elif defined(__ANDROID__) && EIGEN_COMP_CLANG
|
||||
// There are platforms for which TLS should not be used even though the compiler
|
||||
// makes it seem like it's supported (Android NDK < r12b for example).
|
||||
// This is primarily because of linker problems and toolchain misconfiguration:
|
||||
// TLS isn't supported until NDK r12b per
|
||||
// https://developer.android.com/ndk/downloads/revision_history.html
|
||||
|
||||
#if defined(__ANDROID__) && defined(__clang__) && defined(__NDK_MAJOR__) && defined(__NDK_MINOR__) && \
|
||||
((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1)))
|
||||
#undef EIGEN_THREAD_LOCAL
|
||||
#endif
|
||||
#endif // defined(__ANDROID__) && defined(__clang__)
|
||||
|
||||
#endif // EIGEN_AVOID_THREAD_LOCAL
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
template <typename T>
|
||||
struct ThreadLocalNoOpInitialize {
|
||||
void operator()(T&) const {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ThreadLocalNoOpRelease {
|
||||
void operator()(T&) const {}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Thread local container for elements of type T, that does not use thread local
|
||||
// storage. As long as the number of unique threads accessing this storage
|
||||
// is smaller than `capacity_`, it is lock-free and wait-free. Otherwise it will
|
||||
// use a mutex for synchronization.
|
||||
//
|
||||
// Type `T` has to be default constructible, and by default each thread will get
|
||||
// a default constructed value. It is possible to specify custom `initialize`
|
||||
// callable, that will be called lazily from each thread accessing this object,
|
||||
// and will be passed a default initialized object of type `T`. Also it's
|
||||
// possible to pass a custom `release` callable, that will be invoked before
|
||||
// calling ~T().
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// struct Counter {
|
||||
// int value = 0;
|
||||
// }
|
||||
//
|
||||
// Eigen::ThreadLocal<Counter> counter(10);
|
||||
//
|
||||
// // Each thread will have access to it's own counter object.
|
||||
// Counter& cnt = counter.local();
|
||||
// cnt++;
|
||||
//
|
||||
// WARNING: Eigen::ThreadLocal uses the OS-specific value returned by
|
||||
// std::this_thread::get_id() to identify threads. This value is not guaranteed
|
||||
// to be unique except for the life of the thread. A newly created thread may
|
||||
// get an OS-specific ID equal to that of an already destroyed thread.
|
||||
//
|
||||
// Somewhat similar to TBB thread local storage, with similar restrictions:
|
||||
// https://www.threadingbuildingblocks.org/docs/help/reference/thread_local_storage/enumerable_thread_specific_cls.html
|
||||
//
|
||||
template <typename T, typename Initialize = internal::ThreadLocalNoOpInitialize<T>,
|
||||
typename Release = internal::ThreadLocalNoOpRelease<T>>
|
||||
class ThreadLocal {
|
||||
// We preallocate default constructed elements in MaxSizedVector.
|
||||
static_assert(std::is_default_constructible<T>::value, "ThreadLocal data type must be default constructible");
|
||||
|
||||
public:
|
||||
explicit ThreadLocal(int capacity)
|
||||
: ThreadLocal(capacity, internal::ThreadLocalNoOpInitialize<T>(), internal::ThreadLocalNoOpRelease<T>()) {}
|
||||
|
||||
ThreadLocal(int capacity, Initialize initialize)
|
||||
: ThreadLocal(capacity, std::move(initialize), internal::ThreadLocalNoOpRelease<T>()) {}
|
||||
|
||||
ThreadLocal(int capacity, Initialize initialize, Release release)
|
||||
: initialize_(std::move(initialize)),
|
||||
release_(std::move(release)),
|
||||
capacity_(capacity),
|
||||
data_(capacity_),
|
||||
ptr_(capacity_),
|
||||
filled_records_(0) {
|
||||
eigen_assert(capacity_ >= 0);
|
||||
data_.resize(capacity_);
|
||||
for (int i = 0; i < capacity_; ++i) {
|
||||
ptr_.emplace_back(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
T& local() {
|
||||
std::thread::id this_thread = std::this_thread::get_id();
|
||||
if (capacity_ == 0) return SpilledLocal(this_thread);
|
||||
|
||||
std::size_t h = std::hash<std::thread::id>()(this_thread);
|
||||
const int start_idx = h % capacity_;
|
||||
|
||||
// NOTE: From the definition of `std::this_thread::get_id()` it is
|
||||
// guaranteed that we never can have concurrent insertions with the same key
|
||||
// to our hash-map like data structure. If we didn't find an element during
|
||||
// the initial traversal, it's guaranteed that no one else could have
|
||||
// inserted it while we are in this function. This allows to massively
|
||||
// simplify out lock-free insert-only hash map.
|
||||
|
||||
// Check if we already have an element for `this_thread`.
|
||||
int idx = start_idx;
|
||||
while (ptr_[idx].load() != nullptr) {
|
||||
ThreadIdAndValue& record = *(ptr_[idx].load());
|
||||
if (record.thread_id == this_thread) return record.value;
|
||||
|
||||
idx += 1;
|
||||
if (idx >= capacity_) idx -= capacity_;
|
||||
if (idx == start_idx) break;
|
||||
}
|
||||
|
||||
// If we are here, it means that we found an insertion point in lookup
|
||||
// table at `idx`, or we did a full traversal and table is full.
|
||||
|
||||
// If lock-free storage is full, fallback on mutex.
|
||||
if (filled_records_.load() >= capacity_) return SpilledLocal(this_thread);
|
||||
|
||||
// We double check that we still have space to insert an element into a lock
|
||||
// free storage. If old value in `filled_records_` is larger than the
|
||||
// records capacity, it means that some other thread added an element while
|
||||
// we were traversing lookup table.
|
||||
int insertion_index = filled_records_.fetch_add(1, std::memory_order_relaxed);
|
||||
if (insertion_index >= capacity_) return SpilledLocal(this_thread);
|
||||
|
||||
// At this point it's guaranteed that we can access to
|
||||
// data_[insertion_index_] without a data race.
|
||||
data_[insertion_index].thread_id = this_thread;
|
||||
initialize_(data_[insertion_index].value);
|
||||
|
||||
// That's the pointer we'll put into the lookup table.
|
||||
ThreadIdAndValue* inserted = &data_[insertion_index];
|
||||
|
||||
// We'll use nullptr pointer to ThreadIdAndValue in a compare-and-swap loop.
|
||||
ThreadIdAndValue* empty = nullptr;
|
||||
|
||||
// Now we have to find an insertion point into the lookup table. We start
|
||||
// from the `idx` that was identified as an insertion point above, it's
|
||||
// guaranteed that we will have an empty record somewhere in a lookup table
|
||||
// (because we created a record in the `data_`).
|
||||
const int insertion_idx = idx;
|
||||
|
||||
do {
|
||||
// Always start search from the original insertion candidate.
|
||||
idx = insertion_idx;
|
||||
while (ptr_[idx].load() != nullptr) {
|
||||
idx += 1;
|
||||
if (idx >= capacity_) idx -= capacity_;
|
||||
// If we did a full loop, it means that we don't have any free entries
|
||||
// in the lookup table, and this means that something is terribly wrong.
|
||||
eigen_assert(idx != insertion_idx);
|
||||
}
|
||||
// Atomic CAS of the pointer guarantees that any other thread, that will
|
||||
// follow this pointer will see all the mutations in the `data_`.
|
||||
} while (!ptr_[idx].compare_exchange_weak(empty, inserted));
|
||||
|
||||
return inserted->value;
|
||||
}
|
||||
|
||||
// WARN: It's not thread safe to call it concurrently with `local()`.
|
||||
void ForEach(std::function<void(std::thread::id, T&)> f) {
|
||||
// Reading directly from `data_` is unsafe, because only CAS to the
|
||||
// record in `ptr_` makes all changes visible to other threads.
|
||||
for (auto& ptr : ptr_) {
|
||||
ThreadIdAndValue* record = ptr.load();
|
||||
if (record == nullptr) continue;
|
||||
f(record->thread_id, record->value);
|
||||
}
|
||||
|
||||
// We did not spill into the map based storage.
|
||||
if (filled_records_.load(std::memory_order_relaxed) < capacity_) return;
|
||||
|
||||
// Adds a happens before edge from the last call to SpilledLocal().
|
||||
EIGEN_MUTEX_LOCK lock(mu_);
|
||||
for (auto& kv : per_thread_map_) {
|
||||
f(kv.first, kv.second);
|
||||
}
|
||||
}
|
||||
|
||||
// WARN: It's not thread safe to call it concurrently with `local()`.
|
||||
~ThreadLocal() {
|
||||
// Reading directly from `data_` is unsafe, because only CAS to the record
|
||||
// in `ptr_` makes all changes visible to other threads.
|
||||
for (auto& ptr : ptr_) {
|
||||
ThreadIdAndValue* record = ptr.load();
|
||||
if (record == nullptr) continue;
|
||||
release_(record->value);
|
||||
}
|
||||
|
||||
// We did not spill into the map based storage.
|
||||
if (filled_records_.load(std::memory_order_relaxed) < capacity_) return;
|
||||
|
||||
// Adds a happens before edge from the last call to SpilledLocal().
|
||||
EIGEN_MUTEX_LOCK lock(mu_);
|
||||
for (auto& kv : per_thread_map_) {
|
||||
release_(kv.second);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct ThreadIdAndValue {
|
||||
std::thread::id thread_id;
|
||||
T value;
|
||||
};
|
||||
|
||||
// Use unordered map guarded by a mutex when lock free storage is full.
|
||||
T& SpilledLocal(std::thread::id this_thread) {
|
||||
EIGEN_MUTEX_LOCK lock(mu_);
|
||||
|
||||
auto it = per_thread_map_.find(this_thread);
|
||||
if (it == per_thread_map_.end()) {
|
||||
auto result = per_thread_map_.emplace(this_thread, T());
|
||||
eigen_assert(result.second);
|
||||
initialize_((*result.first).second);
|
||||
return (*result.first).second;
|
||||
} else {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
Initialize initialize_;
|
||||
Release release_;
|
||||
const int capacity_;
|
||||
|
||||
// Storage that backs lock-free lookup table `ptr_`. Records stored in this
|
||||
// storage contiguously starting from index 0.
|
||||
MaxSizeVector<ThreadIdAndValue> data_;
|
||||
|
||||
// Atomic pointers to the data stored in `data_`. Used as a lookup table for
|
||||
// linear probing hash map (https://en.wikipedia.org/wiki/Linear_probing).
|
||||
MaxSizeVector<std::atomic<ThreadIdAndValue*>> ptr_;
|
||||
|
||||
// Number of records stored in the `data_`.
|
||||
std::atomic<int> filled_records_;
|
||||
|
||||
// We fallback on per thread map if lock-free storage is full. In practice
|
||||
// this should never happen, if `capacity_` is a reasonable estimate of the
|
||||
// number of threads running in a system.
|
||||
EIGEN_MUTEX mu_; // Protects per_thread_map_.
|
||||
std::unordered_map<std::thread::id, T> per_thread_map_;
|
||||
};
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_CXX11_THREADPOOL_THREAD_LOCAL_H
|
||||
@@ -0,0 +1,50 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_CXX11_THREADPOOL_THREAD_POOL_INTERFACE_H
|
||||
#define EIGEN_CXX11_THREADPOOL_THREAD_POOL_INTERFACE_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
// This defines an interface that ThreadPoolDevice can take to use
|
||||
// custom thread pools underneath.
|
||||
class ThreadPoolInterface {
|
||||
public:
|
||||
// Submits a closure to be run by a thread in the pool.
|
||||
virtual void Schedule(std::function<void()> fn) = 0;
|
||||
|
||||
// Submits a closure to be run by threads in the range [start, end) in the
|
||||
// pool.
|
||||
virtual void ScheduleWithHint(std::function<void()> fn, int /*start*/, int /*end*/) {
|
||||
// Just defer to Schedule in case sub-classes aren't interested in
|
||||
// overriding this functionality.
|
||||
Schedule(fn);
|
||||
}
|
||||
|
||||
// If implemented, stop processing the closures that have been enqueued.
|
||||
// Currently running closures may still be processed.
|
||||
// If not implemented, does nothing.
|
||||
virtual void Cancel() {}
|
||||
|
||||
// Returns the number of threads in the pool.
|
||||
virtual int NumThreads() const = 0;
|
||||
|
||||
// Returns a logical thread index between 0 and NumThreads() - 1 if called
|
||||
// from one of the threads in the pool. Returns -1 otherwise.
|
||||
virtual int CurrentThreadId() const = 0;
|
||||
|
||||
virtual ~ThreadPoolInterface() {}
|
||||
};
|
||||
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_CXX11_THREADPOOL_THREAD_POOL_INTERFACE_H
|
||||
@@ -0,0 +1,16 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2016 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_CXX11_THREADPOOL_THREAD_YIELD_H
|
||||
#define EIGEN_CXX11_THREADPOOL_THREAD_YIELD_H
|
||||
|
||||
// Try to come up with a portable way to yield
|
||||
#define EIGEN_THREAD_YIELD() std::this_thread::yield()
|
||||
|
||||
#endif // EIGEN_CXX11_THREADPOOL_THREAD_YIELD_H
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_UMFPACKSUPPORT_MODULE_H
|
||||
#error "Please include Eigen/UmfPackSupport instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_CORE_MODULE_H
|
||||
#error "Please include Eigen/Core instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,163 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2021 Erik Schultheis <erik.schultheis@aalto.fi>
|
||||
//
|
||||
// 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_LAPACKE_HELPERS_H
|
||||
#define EIGEN_LAPACKE_HELPERS_H
|
||||
|
||||
// IWYU pragma: private
|
||||
#include "./InternalHeaderCheck.h"
|
||||
|
||||
#ifdef EIGEN_USE_MKL
|
||||
#include "mkl_lapacke.h"
|
||||
#else
|
||||
#include "lapacke.h"
|
||||
#endif
|
||||
|
||||
namespace Eigen {
|
||||
namespace internal {
|
||||
/**
|
||||
* \internal
|
||||
* \brief Implementation details and helper functions for the lapacke glue code.
|
||||
*/
|
||||
namespace lapacke_helpers {
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
// Translation from Eigen to Lapacke for types and constants
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// For complex numbers, the types in Eigen and Lapacke are different, but layout compatible.
|
||||
template <typename Scalar>
|
||||
struct translate_type_imp;
|
||||
template <>
|
||||
struct translate_type_imp<float> {
|
||||
using type = float;
|
||||
};
|
||||
template <>
|
||||
struct translate_type_imp<double> {
|
||||
using type = double;
|
||||
};
|
||||
template <>
|
||||
struct translate_type_imp<std::complex<double>> {
|
||||
using type = lapack_complex_double;
|
||||
};
|
||||
template <>
|
||||
struct translate_type_imp<std::complex<float>> {
|
||||
using type = lapack_complex_float;
|
||||
};
|
||||
|
||||
/// Given an Eigen types, this is defined to be the corresponding, layout-compatible lapack type
|
||||
template <typename Scalar>
|
||||
using translated_type = typename translate_type_imp<Scalar>::type;
|
||||
|
||||
/// These functions convert their arguments from Eigen to Lapack types
|
||||
/// This function performs conversion for any of the translations defined above.
|
||||
template <typename Source, typename Target = translated_type<Source>>
|
||||
EIGEN_ALWAYS_INLINE auto to_lapack(Source value) {
|
||||
return static_cast<Target>(value);
|
||||
}
|
||||
|
||||
/// This function performs conversions for pointer types corresponding to the translations abovce.
|
||||
/// This is valid because the translations are between layout-compatible types.
|
||||
template <typename Source, typename Target = translated_type<Source>>
|
||||
EIGEN_ALWAYS_INLINE auto to_lapack(Source *value) {
|
||||
return reinterpret_cast<Target *>(value);
|
||||
}
|
||||
|
||||
/// This function converts the Eigen Index to a lapack index, with possible range checks
|
||||
/// \sa internal::convert_index
|
||||
EIGEN_ALWAYS_INLINE lapack_int to_lapack(Index index) { return convert_index<lapack_int>(index); }
|
||||
|
||||
/// translates storage order of the given Eigen object to the corresponding lapack constant
|
||||
template <typename Derived>
|
||||
EIGEN_ALWAYS_INLINE constexpr lapack_int lapack_storage_of(const EigenBase<Derived> &) {
|
||||
return Derived::IsRowMajor ? LAPACK_ROW_MAJOR : LAPACK_COL_MAJOR;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
// Automatic generation of low-level wrappers
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Helper type to facilitate the wrapping of raw LAPACKE functions for different types into a single, overloaded
|
||||
* C++ function. This is achieved in combination with \r EIGEN_MAKE_LAPACKE_WRAPPER \details This implementation works
|
||||
* by providing an overloaded call function that just forwards its arguments to the underlying lapack function. Each of
|
||||
* these overloads is enabled only if the call is actually well formed. Because these lapack functions take pointers to
|
||||
* the underlying scalar type as arguments, even though the actual Scalars would be implicitly convertible, the pointers
|
||||
* are not and therefore only a single overload can be valid at the same time. Thus, despite all functions taking fully
|
||||
* generic `Args&&... args` as arguments, there is never any ambiguity.
|
||||
*/
|
||||
template <typename DoubleFn, typename SingleFn, typename DoubleCpxFn, typename SingleCpxFn>
|
||||
struct WrappingHelper {
|
||||
// The naming of double, single, double complex and single complex is purely for readability
|
||||
// and doesn't actually affect the workings of this class. In principle, the arguments can
|
||||
// be supplied in any permuted order.
|
||||
DoubleFn double_;
|
||||
SingleFn single_;
|
||||
DoubleCpxFn double_cpx_;
|
||||
SingleCpxFn single_cpx_;
|
||||
|
||||
template <typename... Args>
|
||||
auto call(Args &&...args) -> decltype(double_(std::forward<Args>(args)...)) {
|
||||
return double_(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
auto call(Args &&...args) -> decltype(single_(std::forward<Args>(args)...)) {
|
||||
return single_(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
auto call(Args &&...args) -> decltype(double_cpx_(std::forward<Args>(args)...)) {
|
||||
return double_cpx_(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
auto call(Args &&...args) -> decltype(single_cpx_(std::forward<Args>(args)...)) {
|
||||
return single_cpx_(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
/** \internal Helper function that generates a `WrappingHelper` object with the given function pointers and
|
||||
* invokes its `call` method, thus selecting one of the overloads.
|
||||
* \sa EIGEN_MAKE_LAPACKE_WRAPPER
|
||||
*/
|
||||
template <typename DoubleFn, typename SingleFn, typename DoubleCpxFn, typename SingleCpxFn, typename... Args>
|
||||
EIGEN_ALWAYS_INLINE auto call_wrapper(DoubleFn df, SingleFn sf, DoubleCpxFn dcf, SingleCpxFn scf, Args &&...args) {
|
||||
WrappingHelper<DoubleFn, SingleFn, DoubleCpxFn, SingleCpxFn> helper{df, sf, dcf, scf};
|
||||
return helper.call(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* \internal
|
||||
* Generates a new function `Function` that dispatches to the corresponding LAPACKE_? prefixed functions.
|
||||
* \sa WrappingHelper
|
||||
*/
|
||||
#define EIGEN_MAKE_LAPACKE_WRAPPER(FUNCTION) \
|
||||
template <typename... Args> \
|
||||
EIGEN_ALWAYS_INLINE auto FUNCTION(Args &&...args) { \
|
||||
return call_wrapper(LAPACKE_d##FUNCTION, LAPACKE_s##FUNCTION, LAPACKE_z##FUNCTION, LAPACKE_c##FUNCTION, \
|
||||
std::forward<Args>(args)...); \
|
||||
}
|
||||
|
||||
// Now with this macro and the helper wrappers, we can generate the dispatch for all the lapacke functions that are
|
||||
// used in Eigen.
|
||||
// We define these here instead of in the files where they are used because this allows us to #undef the macro again
|
||||
// right here
|
||||
EIGEN_MAKE_LAPACKE_WRAPPER(potrf)
|
||||
EIGEN_MAKE_LAPACKE_WRAPPER(getrf)
|
||||
EIGEN_MAKE_LAPACKE_WRAPPER(geqrf)
|
||||
EIGEN_MAKE_LAPACKE_WRAPPER(gesdd)
|
||||
|
||||
#undef EIGEN_MAKE_LAPACKE_WRAPPER
|
||||
} // namespace lapacke_helpers
|
||||
} // namespace internal
|
||||
} // namespace Eigen
|
||||
|
||||
#endif // EIGEN_LAPACKE_HELPERS_H
|
||||
@@ -0,0 +1,344 @@
|
||||
|
||||
/** \returns an expression of the coefficient wise product of \c *this and \a other
|
||||
*
|
||||
* \sa MatrixBase::cwiseProduct
|
||||
*/
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const EIGEN_CWISE_BINARY_RETURN_TYPE(Derived, OtherDerived, product) operator*(
|
||||
const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const {
|
||||
return EIGEN_CWISE_BINARY_RETURN_TYPE(Derived, OtherDerived, product)(derived(), other.derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient wise quotient of \c *this and \a other
|
||||
*
|
||||
* \sa MatrixBase::cwiseQuotient
|
||||
*/
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseBinaryOp<
|
||||
internal::scalar_quotient_op<Scalar, typename OtherDerived::Scalar>, const Derived, const OtherDerived>
|
||||
operator/(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const {
|
||||
return CwiseBinaryOp<internal::scalar_quotient_op<Scalar, typename OtherDerived::Scalar>, const Derived,
|
||||
const OtherDerived>(derived(), other.derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise min of \c *this and \a other
|
||||
*
|
||||
* Example: \include Cwise_min.cpp
|
||||
* Output: \verbinclude Cwise_min.out
|
||||
*
|
||||
* \sa max()
|
||||
*/
|
||||
template <int NaNPropagation = PropagateFast, typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const
|
||||
CwiseBinaryOp<internal::scalar_min_op<Scalar, Scalar, NaNPropagation>, const Derived, const OtherDerived>
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
min
|
||||
#else
|
||||
(min)
|
||||
#endif
|
||||
(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const {
|
||||
return CwiseBinaryOp<internal::scalar_min_op<Scalar, Scalar, NaNPropagation>, const Derived, const OtherDerived>(
|
||||
derived(), other.derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise min of \c *this and scalar \a other
|
||||
*
|
||||
* \sa max()
|
||||
*/
|
||||
template <int NaNPropagation = PropagateFast>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const
|
||||
CwiseBinaryOp<internal::scalar_min_op<Scalar, Scalar, NaNPropagation>, const Derived,
|
||||
const CwiseNullaryOp<internal::scalar_constant_op<Scalar>, PlainObject> >
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
min
|
||||
#else
|
||||
(min)
|
||||
#endif
|
||||
(const Scalar &other) const {
|
||||
return (min<NaNPropagation>)(Derived::PlainObject::Constant(rows(), cols(), other));
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise max of \c *this and \a other
|
||||
*
|
||||
* Example: \include Cwise_max.cpp
|
||||
* Output: \verbinclude Cwise_max.out
|
||||
*
|
||||
* \sa min()
|
||||
*/
|
||||
template <int NaNPropagation = PropagateFast, typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const
|
||||
CwiseBinaryOp<internal::scalar_max_op<Scalar, Scalar, NaNPropagation>, const Derived, const OtherDerived>
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
max
|
||||
#else
|
||||
(max)
|
||||
#endif
|
||||
(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const {
|
||||
return CwiseBinaryOp<internal::scalar_max_op<Scalar, Scalar, NaNPropagation>, const Derived, const OtherDerived>(
|
||||
derived(), other.derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise max of \c *this and scalar \a other
|
||||
*
|
||||
* \sa min()
|
||||
*/
|
||||
template <int NaNPropagation = PropagateFast>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const
|
||||
CwiseBinaryOp<internal::scalar_max_op<Scalar, Scalar, NaNPropagation>, const Derived,
|
||||
const CwiseNullaryOp<internal::scalar_constant_op<Scalar>, PlainObject> >
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
max
|
||||
#else
|
||||
(max)
|
||||
#endif
|
||||
(const Scalar &other) const {
|
||||
return (max<NaNPropagation>)(Derived::PlainObject::Constant(rows(), cols(), other));
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise absdiff of \c *this and \a other
|
||||
*
|
||||
* \sa absolute_difference()
|
||||
*/
|
||||
EIGEN_MAKE_CWISE_BINARY_OP(absolute_difference, absolute_difference)
|
||||
|
||||
/** \returns an expression of the coefficient-wise absolute_difference of \c *this and scalar \a other
|
||||
*
|
||||
* \sa absolute_difference()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const
|
||||
CwiseBinaryOp<internal::scalar_absolute_difference_op<Scalar, Scalar>, const Derived,
|
||||
const CwiseNullaryOp<internal::scalar_constant_op<Scalar>, PlainObject> >
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
absolute_difference
|
||||
#else
|
||||
(absolute_difference)
|
||||
#endif
|
||||
(const Scalar &other) const {
|
||||
return (absolute_difference)(Derived::PlainObject::Constant(rows(), cols(), other));
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise power of \c *this to the given array of \a exponents.
|
||||
*
|
||||
* This function computes the coefficient-wise power.
|
||||
*
|
||||
* Example: \include Cwise_array_power_array.cpp
|
||||
* Output: \verbinclude Cwise_array_power_array.out
|
||||
*/
|
||||
EIGEN_MAKE_CWISE_BINARY_OP(pow, pow)
|
||||
|
||||
/** \returns an expression of the coefficient-wise atan2(\c *this, \a y), where \a y is the given array argument.
|
||||
*
|
||||
* This function computes the coefficient-wise atan2.
|
||||
*
|
||||
*/
|
||||
EIGEN_MAKE_CWISE_BINARY_OP(atan2, atan2)
|
||||
|
||||
// TODO code generating macros could be moved to Macros.h and could include generation of documentation
|
||||
#define EIGEN_MAKE_CWISE_COMP_OP(OP, COMPARATOR) \
|
||||
template <typename OtherDerived> \
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const \
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, typename OtherDerived::Scalar, internal::cmp_##COMPARATOR>, \
|
||||
const Derived, const OtherDerived> \
|
||||
OP(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const { \
|
||||
return CwiseBinaryOp<internal::scalar_cmp_op<Scalar, typename OtherDerived::Scalar, internal::cmp_##COMPARATOR>, \
|
||||
const Derived, const OtherDerived>(derived(), other.derived()); \
|
||||
} \
|
||||
typedef CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_##COMPARATOR>, const Derived, \
|
||||
const CwiseNullaryOp<internal::scalar_constant_op<Scalar>, PlainObject> > \
|
||||
Cmp##COMPARATOR##ReturnType; \
|
||||
typedef CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_##COMPARATOR>, \
|
||||
const CwiseNullaryOp<internal::scalar_constant_op<Scalar>, PlainObject>, const Derived> \
|
||||
RCmp##COMPARATOR##ReturnType; \
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Cmp##COMPARATOR##ReturnType OP(const Scalar &s) const { \
|
||||
return this->OP(Derived::PlainObject::Constant(rows(), cols(), s)); \
|
||||
} \
|
||||
EIGEN_DEVICE_FUNC friend EIGEN_STRONG_INLINE const RCmp##COMPARATOR##ReturnType OP( \
|
||||
const Scalar &s, const EIGEN_CURRENT_STORAGE_BASE_CLASS<Derived> &d) { \
|
||||
return Derived::PlainObject::Constant(d.rows(), d.cols(), s).OP(d); \
|
||||
}
|
||||
|
||||
#define EIGEN_MAKE_CWISE_COMP_R_OP(OP, R_OP, RCOMPARATOR) \
|
||||
template <typename OtherDerived> \
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const \
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<typename OtherDerived::Scalar, Scalar, internal::cmp_##RCOMPARATOR>, \
|
||||
const OtherDerived, const Derived> \
|
||||
OP(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived> &other) const { \
|
||||
return CwiseBinaryOp<internal::scalar_cmp_op<typename OtherDerived::Scalar, Scalar, internal::cmp_##RCOMPARATOR>, \
|
||||
const OtherDerived, const Derived>(other.derived(), derived()); \
|
||||
} \
|
||||
EIGEN_DEVICE_FUNC inline const RCmp##RCOMPARATOR##ReturnType OP(const Scalar &s) const { \
|
||||
return Derived::PlainObject::Constant(rows(), cols(), s).R_OP(*this); \
|
||||
} \
|
||||
friend inline const Cmp##RCOMPARATOR##ReturnType OP(const Scalar &s, const Derived &d) { \
|
||||
return d.R_OP(Derived::PlainObject::Constant(d.rows(), d.cols(), s)); \
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise \< operator of *this and \a other
|
||||
*
|
||||
* Example: \include Cwise_less.cpp
|
||||
* Output: \verbinclude Cwise_less.out
|
||||
*
|
||||
* \sa all(), any(), operator>(), operator<=()
|
||||
*/
|
||||
EIGEN_MAKE_CWISE_COMP_OP(operator<, LT)
|
||||
|
||||
/** \returns an expression of the coefficient-wise \<= operator of *this and \a other
|
||||
*
|
||||
* Example: \include Cwise_less_equal.cpp
|
||||
* Output: \verbinclude Cwise_less_equal.out
|
||||
*
|
||||
* \sa all(), any(), operator>=(), operator<()
|
||||
*/
|
||||
EIGEN_MAKE_CWISE_COMP_OP(operator<=, LE)
|
||||
|
||||
/** \returns an expression of the coefficient-wise \> operator of *this and \a other
|
||||
*
|
||||
* Example: \include Cwise_greater.cpp
|
||||
* Output: \verbinclude Cwise_greater.out
|
||||
*
|
||||
* \sa all(), any(), operator>=(), operator<()
|
||||
*/
|
||||
EIGEN_MAKE_CWISE_COMP_R_OP(operator>, operator<, LT)
|
||||
|
||||
/** \returns an expression of the coefficient-wise \>= operator of *this and \a other
|
||||
*
|
||||
* Example: \include Cwise_greater_equal.cpp
|
||||
* Output: \verbinclude Cwise_greater_equal.out
|
||||
*
|
||||
* \sa all(), any(), operator>(), operator<=()
|
||||
*/
|
||||
EIGEN_MAKE_CWISE_COMP_R_OP(operator>=, operator<=, LE)
|
||||
|
||||
/** \returns an expression of the coefficient-wise == operator of *this and \a other
|
||||
*
|
||||
* \warning this performs an exact comparison, which is generally a bad idea with floating-point types.
|
||||
* In order to check for equality between two vectors or matrices with floating-point coefficients, it is
|
||||
* generally a far better idea to use a fuzzy comparison as provided by isApprox() and
|
||||
* isMuchSmallerThan().
|
||||
*
|
||||
* Example: \include Cwise_equal_equal.cpp
|
||||
* Output: \verbinclude Cwise_equal_equal.out
|
||||
*
|
||||
* \sa all(), any(), isApprox(), isMuchSmallerThan()
|
||||
*/
|
||||
EIGEN_MAKE_CWISE_COMP_OP(operator==, EQ)
|
||||
|
||||
/** \returns an expression of the coefficient-wise != operator of *this and \a other
|
||||
*
|
||||
* \warning this performs an exact comparison, which is generally a bad idea with floating-point types.
|
||||
* In order to check for equality between two vectors or matrices with floating-point coefficients, it is
|
||||
* generally a far better idea to use a fuzzy comparison as provided by isApprox() and
|
||||
* isMuchSmallerThan().
|
||||
*
|
||||
* Example: \include Cwise_not_equal.cpp
|
||||
* Output: \verbinclude Cwise_not_equal.out
|
||||
*
|
||||
* \sa all(), any(), isApprox(), isMuchSmallerThan()
|
||||
*/
|
||||
EIGEN_MAKE_CWISE_COMP_OP(operator!=, NEQ)
|
||||
|
||||
#undef EIGEN_MAKE_CWISE_COMP_OP
|
||||
#undef EIGEN_MAKE_CWISE_COMP_R_OP
|
||||
|
||||
// scalar addition
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
EIGEN_MAKE_SCALAR_BINARY_OP(operator+, sum)
|
||||
#else
|
||||
/** \returns an expression of \c *this with each coeff incremented by the constant \a scalar
|
||||
*
|
||||
* \tparam T is the scalar type of \a scalar. It must be compatible with the scalar type of the given expression.
|
||||
*
|
||||
* Example: \include Cwise_plus.cpp
|
||||
* Output: \verbinclude Cwise_plus.out
|
||||
*
|
||||
* \sa operator+=(), operator-()
|
||||
*/
|
||||
template <typename T>
|
||||
const CwiseBinaryOp<internal::scalar_sum_op<Scalar, T>, Derived, Constant<T> > operator+(const T &scalar) const;
|
||||
/** \returns an expression of \a expr with each coeff incremented by the constant \a scalar
|
||||
*
|
||||
* \tparam T is the scalar type of \a scalar. It must be compatible with the scalar type of the given expression.
|
||||
*/
|
||||
template <typename T>
|
||||
friend const CwiseBinaryOp<internal::scalar_sum_op<T, Scalar>, Constant<T>, Derived> operator+(
|
||||
const T &scalar, const StorageBaseType &expr);
|
||||
#endif
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
EIGEN_MAKE_SCALAR_BINARY_OP(operator-, difference)
|
||||
#else
|
||||
/** \returns an expression of \c *this with each coeff decremented by the constant \a scalar
|
||||
*
|
||||
* \tparam T is the scalar type of \a scalar. It must be compatible with the scalar type of the given expression.
|
||||
*
|
||||
* Example: \include Cwise_minus.cpp
|
||||
* Output: \verbinclude Cwise_minus.out
|
||||
*
|
||||
* \sa operator+=(), operator-()
|
||||
*/
|
||||
template <typename T>
|
||||
const CwiseBinaryOp<internal::scalar_difference_op<Scalar, T>, Derived, Constant<T> > operator-(const T &scalar) const;
|
||||
/** \returns an expression of the constant matrix of value \a scalar decremented by the coefficients of \a expr
|
||||
*
|
||||
* \tparam T is the scalar type of \a scalar. It must be compatible with the scalar type of the given expression.
|
||||
*/
|
||||
template <typename T>
|
||||
friend const CwiseBinaryOp<internal::scalar_difference_op<T, Scalar>, Constant<T>, Derived> operator-(
|
||||
const T &scalar, const StorageBaseType &expr);
|
||||
#endif
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
EIGEN_MAKE_SCALAR_BINARY_OP_ONTHELEFT(operator/, quotient)
|
||||
#else
|
||||
/**
|
||||
* \brief Component-wise division of the scalar \a s by array elements of \a a.
|
||||
*
|
||||
* \tparam Scalar is the scalar type of \a x. It must be compatible with the scalar type of the given array expression
|
||||
* (\c Derived::Scalar).
|
||||
*/
|
||||
template <typename T>
|
||||
friend inline const CwiseBinaryOp<internal::scalar_quotient_op<T, Scalar>, Constant<T>, Derived> operator/(
|
||||
const T &s, const StorageBaseType &a);
|
||||
#endif
|
||||
|
||||
// NOTE disabled until we agree on argument order
|
||||
#if 0
|
||||
/** \cpp11 \returns an expression of the coefficient-wise polygamma function.
|
||||
*
|
||||
* \specialfunctions_module
|
||||
*
|
||||
* It returns the \a n -th derivative of the digamma(psi) evaluated at \c *this.
|
||||
*
|
||||
* \warning Be careful with the order of the parameters: x.polygamma(n) is equivalent to polygamma(n,x)
|
||||
*
|
||||
* \sa Eigen::polygamma()
|
||||
*/
|
||||
template<typename DerivedN>
|
||||
inline const CwiseBinaryOp<internal::scalar_polygamma_op<Scalar>, const DerivedN, const Derived>
|
||||
polygamma(const EIGEN_CURRENT_STORAGE_BASE_CLASS<DerivedN> &n) const
|
||||
{
|
||||
return CwiseBinaryOp<internal::scalar_polygamma_op<Scalar>, const DerivedN, const Derived>(n.derived(), this->derived());
|
||||
}
|
||||
#endif
|
||||
|
||||
/** \returns an expression of the coefficient-wise zeta function.
|
||||
*
|
||||
* \specialfunctions_module
|
||||
*
|
||||
* It returns the Riemann zeta function of two arguments \c *this and \a q:
|
||||
*
|
||||
* \param q is the shift, it must be > 0
|
||||
*
|
||||
* \note *this is the exponent, it must be > 1.
|
||||
* \note This function supports only float and double scalar types. To support other scalar types, the user has
|
||||
* to provide implementations of zeta(T,T) for any scalar type T to be supported.
|
||||
*
|
||||
* This method is an alias for zeta(*this,q);
|
||||
*
|
||||
* \sa Eigen::zeta()
|
||||
*/
|
||||
template <typename DerivedQ>
|
||||
inline const CwiseBinaryOp<internal::scalar_zeta_op<Scalar>, const Derived, const DerivedQ> zeta(
|
||||
const EIGEN_CURRENT_STORAGE_BASE_CLASS<DerivedQ> &q) const {
|
||||
return CwiseBinaryOp<internal::scalar_zeta_op<Scalar>, const Derived, const DerivedQ>(this->derived(), q.derived());
|
||||
}
|
||||
@@ -0,0 +1,544 @@
|
||||
typedef CwiseUnaryOp<internal::scalar_abs_op<Scalar>, const Derived> AbsReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_arg_op<Scalar>, const Derived> ArgReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_carg_op<Scalar>, const Derived> CArgReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_abs2_op<Scalar>, const Derived> Abs2ReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_sqrt_op<Scalar>, const Derived> SqrtReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_cbrt_op<Scalar>, const Derived> CbrtReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_rsqrt_op<Scalar>, const Derived> RsqrtReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_sign_op<Scalar>, const Derived> SignReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_inverse_op<Scalar>, const Derived> InverseReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_boolean_not_op<Scalar>, const Derived> BooleanNotReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_bitwise_not_op<Scalar>, const Derived> BitwiseNotReturnType;
|
||||
|
||||
typedef CwiseUnaryOp<internal::scalar_exp_op<Scalar>, const Derived> ExpReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_exp2_op<Scalar>, const Derived> Exp2ReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_expm1_op<Scalar>, const Derived> Expm1ReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_log_op<Scalar>, const Derived> LogReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_log1p_op<Scalar>, const Derived> Log1pReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_log10_op<Scalar>, const Derived> Log10ReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_log2_op<Scalar>, const Derived> Log2ReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_cos_op<Scalar>, const Derived> CosReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_sin_op<Scalar>, const Derived> SinReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_tan_op<Scalar>, const Derived> TanReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_acos_op<Scalar>, const Derived> AcosReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_asin_op<Scalar>, const Derived> AsinReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_atan_op<Scalar>, const Derived> AtanReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_tanh_op<Scalar>, const Derived> TanhReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_logistic_op<Scalar>, const Derived> LogisticReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_sinh_op<Scalar>, const Derived> SinhReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_atanh_op<Scalar>, const Derived> AtanhReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_asinh_op<Scalar>, const Derived> AsinhReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_acosh_op<Scalar>, const Derived> AcoshReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_cosh_op<Scalar>, const Derived> CoshReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_square_op<Scalar>, const Derived> SquareReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_cube_op<Scalar>, const Derived> CubeReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_round_op<Scalar>, const Derived> RoundReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_rint_op<Scalar>, const Derived> RintReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_floor_op<Scalar>, const Derived> FloorReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_ceil_op<Scalar>, const Derived> CeilReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_trunc_op<Scalar>, const Derived> TruncReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_isnan_op<Scalar>, const Derived> IsNaNReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_isinf_op<Scalar>, const Derived> IsInfReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_isfinite_op<Scalar>, const Derived> IsFiniteReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_isfinite_op<Scalar, true>, const Derived> IsFiniteTypedReturnType;
|
||||
|
||||
/** \returns an expression of the coefficient-wise absolute value of \c *this
|
||||
*
|
||||
* Example: \include Cwise_abs.cpp
|
||||
* Output: \verbinclude Cwise_abs.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_abs">Math functions</a>, abs2()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const AbsReturnType abs() const { return AbsReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise phase angle of \c *this
|
||||
*
|
||||
* Example: \include Cwise_arg.cpp
|
||||
* Output: \verbinclude Cwise_arg.out
|
||||
*
|
||||
* \sa abs()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const ArgReturnType arg() const { return ArgReturnType(derived()); }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CArgReturnType carg() const { return CArgReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise squared absolute value of \c *this
|
||||
*
|
||||
* Example: \include Cwise_abs2.cpp
|
||||
* Output: \verbinclude Cwise_abs2.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_abs2">Math functions</a>, abs(), square()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Abs2ReturnType abs2() const { return Abs2ReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise exponential of *this.
|
||||
*
|
||||
* This function computes the coefficient-wise exponential. The function MatrixBase::exp() in the
|
||||
* unsupported module MatrixFunctions computes the matrix exponential.
|
||||
*
|
||||
* Example: \include Cwise_exp.cpp
|
||||
* Output: \verbinclude Cwise_exp.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_exp">Math functions</a>, exp2(), pow(), log(), sin(),
|
||||
* cos()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const ExpReturnType exp() const { return ExpReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise exponential of *this.
|
||||
*
|
||||
* This function computes the coefficient-wise base2 exponential, i.e. 2^x.
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_exp">Math functions</a>, exp(), pow(), log(), sin(),
|
||||
* cos()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const Exp2ReturnType exp2() const { return Exp2ReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise exponential of *this minus 1.
|
||||
*
|
||||
* In exact arithmetic, \c x.expm1() is equivalent to \c x.exp() - 1,
|
||||
* however, with finite precision, this function is much more accurate when \c x is close to zero.
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_expm1">Math functions</a>, exp()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const Expm1ReturnType expm1() const { return Expm1ReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise logarithm of *this.
|
||||
*
|
||||
* This function computes the coefficient-wise logarithm. The function MatrixBase::log() in the
|
||||
* unsupported module MatrixFunctions computes the matrix logarithm.
|
||||
*
|
||||
* Example: \include Cwise_log.cpp
|
||||
* Output: \verbinclude Cwise_log.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_log">Math functions</a>, log()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const LogReturnType log() const { return LogReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise logarithm of 1 plus \c *this.
|
||||
*
|
||||
* In exact arithmetic, \c x.log() is equivalent to \c (x+1).log(),
|
||||
* however, with finite precision, this function is much more accurate when \c x is close to zero.
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_log1p">Math functions</a>, log()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const Log1pReturnType log1p() const { return Log1pReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise base-10 logarithm of *this.
|
||||
*
|
||||
* This function computes the coefficient-wise base-10 logarithm.
|
||||
*
|
||||
* Example: \include Cwise_log10.cpp
|
||||
* Output: \verbinclude Cwise_log10.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_log10">Math functions</a>, log()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const Log10ReturnType log10() const { return Log10ReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise base-2 logarithm of *this.
|
||||
*
|
||||
* This function computes the coefficient-wise base-2 logarithm.
|
||||
*
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const Log2ReturnType log2() const { return Log2ReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise square root of *this.
|
||||
*
|
||||
* This function computes the coefficient-wise square root. The function MatrixBase::sqrt() in the
|
||||
* unsupported module MatrixFunctions computes the matrix square root.
|
||||
*
|
||||
* Example: \include Cwise_sqrt.cpp
|
||||
* Output: \verbinclude Cwise_sqrt.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_sqrt">Math functions</a>, pow(), square(), cbrt()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const SqrtReturnType sqrt() const { return SqrtReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise cube root of *this.
|
||||
*
|
||||
* This function computes the coefficient-wise cube root.
|
||||
*
|
||||
* Example: \include Cwise_cbrt.cpp
|
||||
* Output: \verbinclude Cwise_cbrt.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_cbrt">Math functions</a>, sqrt(), pow(), square()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const CbrtReturnType cbrt() const { return CbrtReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise inverse square root of *this.
|
||||
*
|
||||
* This function computes the coefficient-wise inverse square root.
|
||||
*
|
||||
* Example: \include Cwise_sqrt.cpp
|
||||
* Output: \verbinclude Cwise_sqrt.out
|
||||
*
|
||||
* \sa pow(), square()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const RsqrtReturnType rsqrt() const { return RsqrtReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise signum of *this.
|
||||
*
|
||||
* This function computes the coefficient-wise signum.
|
||||
*
|
||||
* Example: \include Cwise_sign.cpp
|
||||
* Output: \verbinclude Cwise_sign.out
|
||||
*
|
||||
* \sa pow(), square()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const SignReturnType sign() const { return SignReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise cosine of *this.
|
||||
*
|
||||
* This function computes the coefficient-wise cosine. The function MatrixBase::cos() in the
|
||||
* unsupported module MatrixFunctions computes the matrix cosine.
|
||||
*
|
||||
* Example: \include Cwise_cos.cpp
|
||||
* Output: \verbinclude Cwise_cos.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_cos">Math functions</a>, sin(), acos()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const CosReturnType cos() const { return CosReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise sine of *this.
|
||||
*
|
||||
* This function computes the coefficient-wise sine. The function MatrixBase::sin() in the
|
||||
* unsupported module MatrixFunctions computes the matrix sine.
|
||||
*
|
||||
* Example: \include Cwise_sin.cpp
|
||||
* Output: \verbinclude Cwise_sin.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_sin">Math functions</a>, cos(), asin()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const SinReturnType sin() const { return SinReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise tan of *this.
|
||||
*
|
||||
* Example: \include Cwise_tan.cpp
|
||||
* Output: \verbinclude Cwise_tan.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_tan">Math functions</a>, cos(), sin()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const TanReturnType tan() const { return TanReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise arc tan of *this.
|
||||
*
|
||||
* Example: \include Cwise_atan.cpp
|
||||
* Output: \verbinclude Cwise_atan.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_atan">Math functions</a>, tan(), asin(), acos()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const AtanReturnType atan() const { return AtanReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise arc cosine of *this.
|
||||
*
|
||||
* Example: \include Cwise_acos.cpp
|
||||
* Output: \verbinclude Cwise_acos.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_acos">Math functions</a>, cos(), asin()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const AcosReturnType acos() const { return AcosReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise arc sine of *this.
|
||||
*
|
||||
* Example: \include Cwise_asin.cpp
|
||||
* Output: \verbinclude Cwise_asin.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_asin">Math functions</a>, sin(), acos()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const AsinReturnType asin() const { return AsinReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise hyperbolic tan of *this.
|
||||
*
|
||||
* Example: \include Cwise_tanh.cpp
|
||||
* Output: \verbinclude Cwise_tanh.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_tanh">Math functions</a>, tan(), sinh(), cosh()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const TanhReturnType tanh() const { return TanhReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise hyperbolic sin of *this.
|
||||
*
|
||||
* Example: \include Cwise_sinh.cpp
|
||||
* Output: \verbinclude Cwise_sinh.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_sinh">Math functions</a>, sin(), tanh(), cosh()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const SinhReturnType sinh() const { return SinhReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise hyperbolic cos of *this.
|
||||
*
|
||||
* Example: \include Cwise_cosh.cpp
|
||||
* Output: \verbinclude Cwise_cosh.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_cosh">Math functions</a>, tanh(), sinh(), cosh()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const CoshReturnType cosh() const { return CoshReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise inverse hyperbolic tan of *this.
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_atanh">Math functions</a>, atanh(), asinh(), acosh()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const AtanhReturnType atanh() const { return AtanhReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise inverse hyperbolic sin of *this.
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_asinh">Math functions</a>, atanh(), asinh(), acosh()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const AsinhReturnType asinh() const { return AsinhReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise inverse hyperbolic cos of *this.
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_acosh">Math functions</a>, atanh(), asinh(), acosh()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const AcoshReturnType acosh() const { return AcoshReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise logistic of *this.
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const LogisticReturnType logistic() const { return LogisticReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise inverse of *this.
|
||||
*
|
||||
* Example: \include Cwise_inverse.cpp
|
||||
* Output: \verbinclude Cwise_inverse.out
|
||||
*
|
||||
* \sa operator/(), operator*()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const InverseReturnType inverse() const { return InverseReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise square of *this.
|
||||
*
|
||||
* Example: \include Cwise_square.cpp
|
||||
* Output: \verbinclude Cwise_square.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_squareE">Math functions</a>, abs2(), cube(), pow()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const SquareReturnType square() const { return SquareReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise cube of *this.
|
||||
*
|
||||
* Example: \include Cwise_cube.cpp
|
||||
* Output: \verbinclude Cwise_cube.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_cube">Math functions</a>, square(), pow()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const CubeReturnType cube() const { return CubeReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise rint of *this.
|
||||
*
|
||||
* Example: \include Cwise_rint.cpp
|
||||
* Output: \verbinclude Cwise_rint.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_rint">Math functions</a>, ceil(), floor()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const RintReturnType rint() const { return RintReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise round of *this.
|
||||
*
|
||||
* Example: \include Cwise_round.cpp
|
||||
* Output: \verbinclude Cwise_round.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_round">Math functions</a>, ceil(), floor()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const RoundReturnType round() const { return RoundReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise floor of *this.
|
||||
*
|
||||
* Example: \include Cwise_floor.cpp
|
||||
* Output: \verbinclude Cwise_floor.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_floor">Math functions</a>, ceil(), round()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const FloorReturnType floor() const { return FloorReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise ceil of *this.
|
||||
*
|
||||
* Example: \include Cwise_ceil.cpp
|
||||
* Output: \verbinclude Cwise_ceil.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_ceil">Math functions</a>, floor(), round()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const CeilReturnType ceil() const { return CeilReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise truncation of *this.
|
||||
*
|
||||
* Example: \include Cwise_trunc.cpp
|
||||
* Output: \verbinclude Cwise_trunc.out
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_trunc">Math functions</a>, floor(), round()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const TruncReturnType trunc() const { return TruncReturnType(derived()); }
|
||||
|
||||
template <int N>
|
||||
struct ShiftRightXpr {
|
||||
typedef CwiseUnaryOp<internal::scalar_shift_right_op<Scalar, N>, const Derived> Type;
|
||||
};
|
||||
|
||||
/** \returns an expression of \c *this with the \a Scalar type arithmetically
|
||||
* shifted right by \a N bit positions.
|
||||
*
|
||||
* The template parameter \a N specifies the number of bit positions to shift.
|
||||
*
|
||||
* \sa shiftLeft()
|
||||
*/
|
||||
template <int N>
|
||||
EIGEN_DEVICE_FUNC typename ShiftRightXpr<N>::Type shiftRight() const {
|
||||
return typename ShiftRightXpr<N>::Type(derived());
|
||||
}
|
||||
|
||||
template <int N>
|
||||
struct ShiftLeftXpr {
|
||||
typedef CwiseUnaryOp<internal::scalar_shift_left_op<Scalar, N>, const Derived> Type;
|
||||
};
|
||||
|
||||
/** \returns an expression of \c *this with the \a Scalar type logically
|
||||
* shifted left by \a N bit positions.
|
||||
*
|
||||
* The template parameter \a N specifies the number of bit positions to shift.
|
||||
*
|
||||
* \sa shiftRight()
|
||||
*/
|
||||
template <int N>
|
||||
EIGEN_DEVICE_FUNC typename ShiftLeftXpr<N>::Type shiftLeft() const {
|
||||
return typename ShiftLeftXpr<N>::Type(derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise isnan of *this.
|
||||
*
|
||||
* Example: \include Cwise_isNaN.cpp
|
||||
* Output: \verbinclude Cwise_isNaN.out
|
||||
*
|
||||
* \sa isfinite(), isinf()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const IsNaNReturnType isNaN() const { return IsNaNReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise isinf of *this.
|
||||
*
|
||||
* Example: \include Cwise_isInf.cpp
|
||||
* Output: \verbinclude Cwise_isInf.out
|
||||
*
|
||||
* \sa isnan(), isfinite()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const IsInfReturnType isInf() const { return IsInfReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise isfinite of *this.
|
||||
*
|
||||
* Example: \include Cwise_isFinite.cpp
|
||||
* Output: \verbinclude Cwise_isFinite.out
|
||||
*
|
||||
* \sa isnan(), isinf()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const IsFiniteReturnType isFinite() const { return IsFiniteReturnType(derived()); }
|
||||
EIGEN_DEVICE_FUNC inline const IsFiniteTypedReturnType isFiniteTyped() const {
|
||||
return IsFiniteTypedReturnType(derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise ! operator of *this
|
||||
*
|
||||
* Example: \include Cwise_boolean_not.cpp
|
||||
* Output: \verbinclude Cwise_boolean_not.out
|
||||
*
|
||||
* \sa operator!=()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const BooleanNotReturnType operator!() const { return BooleanNotReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the bitwise ~ operator of *this
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const BitwiseNotReturnType operator~() const { return BitwiseNotReturnType(derived()); }
|
||||
|
||||
// --- SpecialFunctions module ---
|
||||
|
||||
typedef CwiseUnaryOp<internal::scalar_lgamma_op<Scalar>, const Derived> LgammaReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_digamma_op<Scalar>, const Derived> DigammaReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_erf_op<Scalar>, const Derived> ErfReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_erfc_op<Scalar>, const Derived> ErfcReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_ndtri_op<Scalar>, const Derived> NdtriReturnType;
|
||||
|
||||
/** \cpp11 \returns an expression of the coefficient-wise ln(|gamma(*this)|).
|
||||
*
|
||||
* \specialfunctions_module
|
||||
*
|
||||
* \note This function supports only float and double scalar types in c++11 mode. To support other scalar types,
|
||||
* or float/double in non c++11 mode, the user has to provide implementations of lgamma(T) for any scalar
|
||||
* type T to be supported.
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_lgamma">Math functions</a>, digamma()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const LgammaReturnType lgamma() const { return LgammaReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise digamma (psi, derivative of lgamma).
|
||||
*
|
||||
* \specialfunctions_module
|
||||
*
|
||||
* \note This function supports only float and double scalar types. To support other scalar types,
|
||||
* the user has to provide implementations of digamma(T) for any scalar
|
||||
* type T to be supported.
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_digamma">Math functions</a>, Eigen::digamma(),
|
||||
* Eigen::polygamma(), lgamma()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const DigammaReturnType digamma() const { return DigammaReturnType(derived()); }
|
||||
|
||||
/** \cpp11 \returns an expression of the coefficient-wise Gauss error
|
||||
* function of *this.
|
||||
*
|
||||
* \specialfunctions_module
|
||||
*
|
||||
* \note This function supports only float and double scalar types in c++11 mode. To support other scalar types,
|
||||
* or float/double in non c++11 mode, the user has to provide implementations of erf(T) for any scalar
|
||||
* type T to be supported.
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_erf">Math functions</a>, erfc()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const ErfReturnType erf() const { return ErfReturnType(derived()); }
|
||||
|
||||
/** \cpp11 \returns an expression of the coefficient-wise Complementary error
|
||||
* function of *this.
|
||||
*
|
||||
* \specialfunctions_module
|
||||
*
|
||||
* \note This function supports only float and double scalar types in c++11 mode. To support other scalar types,
|
||||
* or float/double in non c++11 mode, the user has to provide implementations of erfc(T) for any scalar
|
||||
* type T to be supported.
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_erfc">Math functions</a>, erf()
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const ErfcReturnType erfc() const { return ErfcReturnType(derived()); }
|
||||
|
||||
/** \returns an expression of the coefficient-wise inverse of the CDF of the Normal distribution function
|
||||
* function of *this.
|
||||
*
|
||||
* \specialfunctions_module
|
||||
*
|
||||
* In other words, considering `x = ndtri(y)`, it returns the argument, x, for which the area under the
|
||||
* Gaussian probability density function (integrated from minus infinity to x) is equal to y.
|
||||
*
|
||||
* \note This function supports only float and double scalar types. To support other scalar types,
|
||||
* the user has to provide implementations of ndtri(T) for any scalar type T to be supported.
|
||||
*
|
||||
* \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_ndtri">Math functions</a>
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const NdtriReturnType ndtri() const { return NdtriReturnType(derived()); }
|
||||
|
||||
template <typename ScalarExponent>
|
||||
using UnaryPowReturnType =
|
||||
std::enable_if_t<internal::is_arithmetic<typename NumTraits<ScalarExponent>::Real>::value,
|
||||
CwiseUnaryOp<internal::scalar_unary_pow_op<Scalar, ScalarExponent>, const Derived>>;
|
||||
|
||||
/** \returns an expression of the coefficients of \c *this raised to the constant power \a exponent
|
||||
*
|
||||
* \tparam ScalarExponent is the scalar type of \a exponent. It must be compatible with the scalar type
|
||||
* of the given expression.
|
||||
* \param exponent the scalar exponent value.
|
||||
*
|
||||
* This function computes the coefficient-wise power. The function MatrixBase::pow() in the
|
||||
* unsupported module MatrixFunctions computes the matrix power.
|
||||
*
|
||||
* Example: \include Cwise_pow.cpp
|
||||
* Output: \verbinclude Cwise_pow.out
|
||||
*
|
||||
* \sa ArrayBase::pow(ArrayBase), square(), cube(), exp(), log()
|
||||
*/
|
||||
template <typename ScalarExponent>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const UnaryPowReturnType<ScalarExponent> pow(
|
||||
const ScalarExponent& exponent) const {
|
||||
return UnaryPowReturnType<ScalarExponent>(derived(), internal::scalar_unary_pow_op<Scalar, ScalarExponent>(exponent));
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,116 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008-2016 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
// This file is a base class plugin containing common coefficient wise functions.
|
||||
|
||||
/** \returns an expression of the difference of \c *this and \a other
|
||||
*
|
||||
* \note If you want to subtract a given scalar from all coefficients, see Cwise::operator-().
|
||||
*
|
||||
* \sa class CwiseBinaryOp, operator-=()
|
||||
*/
|
||||
EIGEN_MAKE_CWISE_BINARY_OP(operator-, difference)
|
||||
|
||||
/** \returns an expression of the sum of \c *this and \a other
|
||||
*
|
||||
* \note If you want to add a given scalar to all coefficients, see Cwise::operator+().
|
||||
*
|
||||
* \sa class CwiseBinaryOp, operator+=()
|
||||
*/
|
||||
EIGEN_MAKE_CWISE_BINARY_OP(operator+, sum)
|
||||
|
||||
/** \returns an expression of a custom coefficient-wise operator \a func of *this and \a other
|
||||
*
|
||||
* The template parameter \a CustomBinaryOp is the type of the functor
|
||||
* of the custom operator (see class CwiseBinaryOp for an example)
|
||||
*
|
||||
* Here is an example illustrating the use of custom functors:
|
||||
* \include class_CwiseBinaryOp.cpp
|
||||
* Output: \verbinclude class_CwiseBinaryOp.out
|
||||
*
|
||||
* \sa class CwiseBinaryOp, operator+(), operator-(), cwiseProduct()
|
||||
*/
|
||||
template <typename CustomBinaryOp, typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseBinaryOp<CustomBinaryOp, const Derived, const OtherDerived> binaryExpr(
|
||||
const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other, const CustomBinaryOp& func = CustomBinaryOp()) const {
|
||||
return CwiseBinaryOp<CustomBinaryOp, const Derived, const OtherDerived>(derived(), other.derived(), func);
|
||||
}
|
||||
|
||||
/** \returns an expression of \c *this scaled by the scalar factor \a scalar
|
||||
*
|
||||
* \tparam T is the scalar type of \a scalar. It must be compatible with the scalar type of the given expression.
|
||||
*/
|
||||
EIGEN_MAKE_SCALAR_BINARY_OP(operator*, product)
|
||||
|
||||
/** \returns an expression of \c *this divided by the scalar value \a scalar
|
||||
*
|
||||
* \tparam T is the scalar type of \a scalar. It must be compatible with the scalar type of the given expression.
|
||||
*/
|
||||
EIGEN_MAKE_SCALAR_BINARY_OP_ONTHERIGHT(operator/, quotient)
|
||||
|
||||
/** \returns an expression of the coefficient-wise boolean \b and operator of \c *this and \a other
|
||||
*
|
||||
* Example: \include Cwise_boolean_and.cpp
|
||||
* Output: \verbinclude Cwise_boolean_and.out
|
||||
*
|
||||
* \sa operator||(), select()
|
||||
*/
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC inline const CwiseBinaryOp<internal::scalar_boolean_and_op<Scalar>, const Derived, const OtherDerived>
|
||||
operator&&(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryOp<internal::scalar_boolean_and_op<Scalar>, const Derived, const OtherDerived>(derived(),
|
||||
other.derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise boolean \b or operator of \c *this and \a other
|
||||
*
|
||||
* Example: \include Cwise_boolean_or.cpp
|
||||
* Output: \verbinclude Cwise_boolean_or.out
|
||||
*
|
||||
* \sa operator&&(), select()
|
||||
*/
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC inline const CwiseBinaryOp<internal::scalar_boolean_or_op<Scalar>, const Derived, const OtherDerived>
|
||||
operator||(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryOp<internal::scalar_boolean_or_op<Scalar>, const Derived, const OtherDerived>(derived(),
|
||||
other.derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of the bitwise \b and operator of \c *this and \a other
|
||||
*
|
||||
* \sa operator|(), operator^()
|
||||
*/
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC inline const CwiseBinaryOp<internal::scalar_bitwise_and_op<Scalar>, const Derived, const OtherDerived>
|
||||
operator&(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryOp<internal::scalar_bitwise_and_op<Scalar>, const Derived, const OtherDerived>(derived(),
|
||||
other.derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of the bitwise boolean \b or operator of \c *this and \a other
|
||||
*
|
||||
* \sa operator&(), operator^()
|
||||
*/
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC inline const CwiseBinaryOp<internal::scalar_bitwise_or_op<Scalar>, const Derived, const OtherDerived>
|
||||
operator|(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryOp<internal::scalar_bitwise_or_op<Scalar>, const Derived, const OtherDerived>(derived(),
|
||||
other.derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of the bitwise xor operator of *this and \a other
|
||||
* \sa operator&(), operator|()
|
||||
*/
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC inline const CwiseBinaryOp<internal::scalar_bitwise_xor_op<Scalar>, const Derived, const OtherDerived>
|
||||
operator^(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryOp<internal::scalar_bitwise_xor_op<Scalar>, const Derived, const OtherDerived>(derived(),
|
||||
other.derived());
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
// This file is a base class plugin containing common coefficient wise functions.
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
/** \internal the return type of conjugate() */
|
||||
typedef std::conditional_t<NumTraits<Scalar>::IsComplex,
|
||||
const CwiseUnaryOp<internal::scalar_conjugate_op<Scalar>, const Derived>, const Derived&>
|
||||
ConjugateReturnType;
|
||||
/** \internal the return type of real() const */
|
||||
typedef std::conditional_t<NumTraits<Scalar>::IsComplex,
|
||||
const CwiseUnaryOp<internal::scalar_real_op<Scalar>, const Derived>, const Derived&>
|
||||
RealReturnType;
|
||||
/** \internal the return type of real() */
|
||||
typedef std::conditional_t<NumTraits<Scalar>::IsComplex, CwiseUnaryView<internal::scalar_real_ref_op<Scalar>, Derived>,
|
||||
Derived&>
|
||||
NonConstRealReturnType;
|
||||
/** \internal the return type of imag() const */
|
||||
typedef CwiseUnaryOp<internal::scalar_imag_op<Scalar>, const Derived> ImagReturnType;
|
||||
/** \internal the return type of imag() */
|
||||
typedef CwiseUnaryView<internal::scalar_imag_ref_op<Scalar>, Derived> NonConstImagReturnType;
|
||||
|
||||
typedef CwiseUnaryOp<internal::scalar_opposite_op<Scalar>, const Derived> NegativeReturnType;
|
||||
|
||||
#endif // not EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
/// \returns an expression of the opposite of \c *this
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(operator-, opposite)
|
||||
///
|
||||
EIGEN_DEVICE_FUNC inline const NegativeReturnType operator-() const { return NegativeReturnType(derived()); }
|
||||
|
||||
template <class NewType>
|
||||
struct CastXpr {
|
||||
typedef typename internal::cast_return_type<
|
||||
Derived, const CwiseUnaryOp<internal::core_cast_op<Scalar, NewType>, const Derived> >::type Type;
|
||||
};
|
||||
|
||||
/// \returns an expression of \c *this with the \a Scalar type casted to
|
||||
/// \a NewScalar.
|
||||
///
|
||||
/// The template parameter \a NewScalar is the type we are casting the scalars to.
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(cast, conversion function)
|
||||
///
|
||||
/// \sa class CwiseUnaryOp
|
||||
///
|
||||
template <typename NewType>
|
||||
EIGEN_DEVICE_FUNC typename CastXpr<NewType>::Type cast() const {
|
||||
return typename CastXpr<NewType>::Type(derived());
|
||||
}
|
||||
|
||||
/// \returns an expression of the complex conjugate of \c *this.
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(conjugate, complex conjugate)
|
||||
///
|
||||
/// \sa <a href="group__CoeffwiseMathFunctions.html#cwisetable_conj">Math functions</a>, MatrixBase::adjoint()
|
||||
EIGEN_DEVICE_FUNC inline ConjugateReturnType conjugate() const { return ConjugateReturnType(derived()); }
|
||||
|
||||
/// \returns an expression of the complex conjugate of \c *this if Cond==true, returns derived() otherwise.
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(conjugate, complex conjugate)
|
||||
///
|
||||
/// \sa conjugate()
|
||||
template <bool Cond>
|
||||
EIGEN_DEVICE_FUNC inline std::conditional_t<Cond, ConjugateReturnType, const Derived&> conjugateIf() const {
|
||||
typedef std::conditional_t<Cond, ConjugateReturnType, const Derived&> ReturnType;
|
||||
return ReturnType(derived());
|
||||
}
|
||||
|
||||
/// \returns a read-only expression of the real part of \c *this.
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(real, real part function)
|
||||
///
|
||||
/// \sa imag()
|
||||
EIGEN_DEVICE_FUNC inline RealReturnType real() const { return RealReturnType(derived()); }
|
||||
|
||||
/// \returns an read-only expression of the imaginary part of \c *this.
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(imag, imaginary part function)
|
||||
///
|
||||
/// \sa real()
|
||||
EIGEN_DEVICE_FUNC inline const ImagReturnType imag() const { return ImagReturnType(derived()); }
|
||||
|
||||
/// \brief Apply a unary operator coefficient-wise
|
||||
/// \param[in] func Functor implementing the unary operator
|
||||
/// \tparam CustomUnaryOp Type of \a func
|
||||
/// \returns An expression of a custom coefficient-wise unary operator \a func of *this
|
||||
///
|
||||
/// The function \c ptr_fun() from the C++ standard library can be used to make functors out of normal functions.
|
||||
///
|
||||
/// Example:
|
||||
/// \include class_CwiseUnaryOp_ptrfun.cpp
|
||||
/// Output: \verbinclude class_CwiseUnaryOp_ptrfun.out
|
||||
///
|
||||
/// Genuine functors allow for more possibilities, for instance it may contain a state.
|
||||
///
|
||||
/// Example:
|
||||
/// \include class_CwiseUnaryOp.cpp
|
||||
/// Output: \verbinclude class_CwiseUnaryOp.out
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(unaryExpr, unary function)
|
||||
///
|
||||
/// \sa unaryViewExpr, binaryExpr, class CwiseUnaryOp
|
||||
///
|
||||
template <typename CustomUnaryOp>
|
||||
EIGEN_DEVICE_FUNC inline const CwiseUnaryOp<CustomUnaryOp, const Derived> unaryExpr(
|
||||
const CustomUnaryOp& func = CustomUnaryOp()) const {
|
||||
return CwiseUnaryOp<CustomUnaryOp, const Derived>(derived(), func);
|
||||
}
|
||||
|
||||
/// \returns a const expression of a custom coefficient-wise unary operator \a func of *this
|
||||
///
|
||||
/// The template parameter \a CustomUnaryOp is the type of the functor
|
||||
/// of the custom unary operator.
|
||||
///
|
||||
/// Example:
|
||||
/// \include class_CwiseUnaryOp.cpp
|
||||
/// Output: \verbinclude class_CwiseUnaryOp.out
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(unaryViewExpr, unary function)
|
||||
///
|
||||
/// \sa unaryExpr, binaryExpr class CwiseUnaryOp
|
||||
///
|
||||
template <typename CustomViewOp>
|
||||
EIGEN_DEVICE_FUNC inline const CwiseUnaryView<CustomViewOp, const Derived> unaryViewExpr(
|
||||
const CustomViewOp& func = CustomViewOp()) const {
|
||||
return CwiseUnaryView<CustomViewOp, const Derived>(derived(), func);
|
||||
}
|
||||
|
||||
/// \returns a non-const expression of a custom coefficient-wise unary view \a func of *this
|
||||
///
|
||||
/// The template parameter \a CustomUnaryOp is the type of the functor
|
||||
/// of the custom unary operator.
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(unaryViewExpr, unary function)
|
||||
///
|
||||
/// \sa unaryExpr, binaryExpr class CwiseUnaryOp
|
||||
///
|
||||
template <typename CustomViewOp>
|
||||
EIGEN_DEVICE_FUNC inline CwiseUnaryView<CustomViewOp, Derived> unaryViewExpr(
|
||||
const CustomViewOp& func = CustomViewOp()) {
|
||||
return CwiseUnaryView<CustomViewOp, Derived>(derived(), func);
|
||||
}
|
||||
|
||||
/// \returns a non const expression of the real part of \c *this.
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(real, real part function)
|
||||
///
|
||||
/// \sa imag()
|
||||
EIGEN_DEVICE_FUNC inline NonConstRealReturnType real() { return NonConstRealReturnType(derived()); }
|
||||
|
||||
/// \returns a non const expression of the imaginary part of \c *this.
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(imag, imaginary part function)
|
||||
///
|
||||
/// \sa real()
|
||||
EIGEN_DEVICE_FUNC inline NonConstImagReturnType imag() { return NonConstImagReturnType(derived()); }
|
||||
@@ -0,0 +1,192 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2017 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#if !defined(EIGEN_PARSED_BY_DOXYGEN)
|
||||
|
||||
public:
|
||||
// SFINAE dummy types
|
||||
|
||||
template <typename RowIndices, typename ColIndices>
|
||||
using EnableOverload = std::enable_if_t<
|
||||
internal::valid_indexed_view_overload<RowIndices, ColIndices>::value && internal::is_lvalue<Derived>::value, bool>;
|
||||
|
||||
template <typename RowIndices, typename ColIndices>
|
||||
using EnableConstOverload =
|
||||
std::enable_if_t<internal::valid_indexed_view_overload<RowIndices, ColIndices>::value, bool>;
|
||||
|
||||
template <typename Indices>
|
||||
using EnableVectorOverload =
|
||||
std::enable_if_t<!internal::is_valid_index_type<Indices>::value && internal::is_lvalue<Derived>::value, bool>;
|
||||
|
||||
template <typename Indices>
|
||||
using EnableConstVectorOverload = std::enable_if_t<!internal::is_valid_index_type<Indices>::value, bool>;
|
||||
|
||||
public:
|
||||
// Public API for 2D matrices/arrays
|
||||
|
||||
// non-const versions
|
||||
|
||||
template <typename RowIndices, typename ColIndices>
|
||||
using IndexedViewType = typename internal::IndexedViewSelector<Derived, RowIndices, ColIndices>::ReturnType;
|
||||
|
||||
template <typename RowIndices, typename ColIndices, EnableOverload<RowIndices, ColIndices> = true>
|
||||
IndexedViewType<RowIndices, ColIndices> operator()(const RowIndices& rowIndices, const ColIndices& colIndices) {
|
||||
return internal::IndexedViewSelector<Derived, RowIndices, ColIndices>::run(derived(), rowIndices, colIndices);
|
||||
}
|
||||
|
||||
template <typename RowType, size_t RowSize, typename ColIndices, typename RowIndices = Array<RowType, RowSize, 1>,
|
||||
EnableOverload<RowIndices, ColIndices> = true>
|
||||
IndexedViewType<RowIndices, ColIndices> operator()(const RowType (&rowIndices)[RowSize], const ColIndices& colIndices) {
|
||||
return internal::IndexedViewSelector<Derived, RowIndices, ColIndices>::run(derived(), RowIndices{rowIndices},
|
||||
colIndices);
|
||||
}
|
||||
|
||||
template <typename RowIndices, typename ColType, size_t ColSize, typename ColIndices = Array<ColType, ColSize, 1>,
|
||||
EnableOverload<RowIndices, ColIndices> = true>
|
||||
IndexedViewType<RowIndices, ColIndices> operator()(const RowIndices& rowIndices, const ColType (&colIndices)[ColSize]) {
|
||||
return internal::IndexedViewSelector<Derived, RowIndices, ColIndices>::run(derived(), rowIndices,
|
||||
ColIndices{colIndices});
|
||||
}
|
||||
|
||||
template <typename RowType, size_t RowSize, typename ColType, size_t ColSize,
|
||||
typename RowIndices = Array<RowType, RowSize, 1>, typename ColIndices = Array<ColType, ColSize, 1>,
|
||||
EnableOverload<RowIndices, ColIndices> = true>
|
||||
IndexedViewType<RowIndices, ColIndices> operator()(const RowType (&rowIndices)[RowSize],
|
||||
const ColType (&colIndices)[ColSize]) {
|
||||
return internal::IndexedViewSelector<Derived, RowIndices, ColIndices>::run(derived(), RowIndices{rowIndices},
|
||||
ColIndices{colIndices});
|
||||
}
|
||||
|
||||
// const versions
|
||||
|
||||
template <typename RowIndices, typename ColIndices>
|
||||
using ConstIndexedViewType = typename internal::IndexedViewSelector<Derived, RowIndices, ColIndices>::ConstReturnType;
|
||||
|
||||
template <typename RowIndices, typename ColIndices, EnableConstOverload<RowIndices, ColIndices> = true>
|
||||
ConstIndexedViewType<RowIndices, ColIndices> operator()(const RowIndices& rowIndices,
|
||||
const ColIndices& colIndices) const {
|
||||
return internal::IndexedViewSelector<Derived, RowIndices, ColIndices>::run(derived(), rowIndices, colIndices);
|
||||
}
|
||||
|
||||
template <typename RowType, size_t RowSize, typename ColIndices, typename RowIndices = Array<RowType, RowSize, 1>,
|
||||
EnableConstOverload<RowIndices, ColIndices> = true>
|
||||
ConstIndexedViewType<RowIndices, ColIndices> operator()(const RowType (&rowIndices)[RowSize],
|
||||
const ColIndices& colIndices) const {
|
||||
return internal::IndexedViewSelector<Derived, RowIndices, ColIndices>::run(derived(), RowIndices{rowIndices},
|
||||
colIndices);
|
||||
}
|
||||
|
||||
template <typename RowIndices, typename ColType, size_t ColSize, typename ColIndices = Array<ColType, ColSize, 1>,
|
||||
EnableConstOverload<RowIndices, ColIndices> = true>
|
||||
ConstIndexedViewType<RowIndices, ColIndices> operator()(const RowIndices& rowIndices,
|
||||
const ColType (&colIndices)[ColSize]) const {
|
||||
return internal::IndexedViewSelector<Derived, RowIndices, ColIndices>::run(derived(), rowIndices,
|
||||
ColIndices{colIndices});
|
||||
}
|
||||
|
||||
template <typename RowType, size_t RowSize, typename ColType, size_t ColSize,
|
||||
typename RowIndices = Array<RowType, RowSize, 1>, typename ColIndices = Array<ColType, ColSize, 1>,
|
||||
EnableConstOverload<RowIndices, ColIndices> = true>
|
||||
ConstIndexedViewType<RowIndices, ColIndices> operator()(const RowType (&rowIndices)[RowSize],
|
||||
const ColType (&colIndices)[ColSize]) const {
|
||||
return internal::IndexedViewSelector<Derived, RowIndices, ColIndices>::run(derived(), RowIndices{rowIndices},
|
||||
ColIndices{colIndices});
|
||||
}
|
||||
|
||||
// Public API for 1D vectors/arrays
|
||||
|
||||
// non-const versions
|
||||
|
||||
template <typename Indices>
|
||||
using VectorIndexedViewType = typename internal::VectorIndexedViewSelector<Derived, Indices>::ReturnType;
|
||||
|
||||
template <typename Indices, EnableVectorOverload<Indices> = true>
|
||||
VectorIndexedViewType<Indices> operator()(const Indices& indices) {
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return internal::VectorIndexedViewSelector<Derived, Indices>::run(derived(), indices);
|
||||
}
|
||||
|
||||
template <typename IndexType, size_t Size, typename Indices = Array<IndexType, Size, 1>,
|
||||
EnableVectorOverload<Indices> = true>
|
||||
VectorIndexedViewType<Indices> operator()(const IndexType (&indices)[Size]) {
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return internal::VectorIndexedViewSelector<Derived, Indices>::run(derived(), Indices{indices});
|
||||
}
|
||||
|
||||
// const versions
|
||||
|
||||
template <typename Indices>
|
||||
using ConstVectorIndexedViewType = typename internal::VectorIndexedViewSelector<Derived, Indices>::ConstReturnType;
|
||||
|
||||
template <typename Indices, EnableConstVectorOverload<Indices> = true>
|
||||
ConstVectorIndexedViewType<Indices> operator()(const Indices& indices) const {
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return internal::VectorIndexedViewSelector<Derived, Indices>::run(derived(), indices);
|
||||
}
|
||||
|
||||
template <typename IndexType, size_t Size, typename Indices = Array<IndexType, Size, 1>,
|
||||
EnableConstVectorOverload<Indices> = true>
|
||||
ConstVectorIndexedViewType<Indices> operator()(const IndexType (&indices)[Size]) const {
|
||||
EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
|
||||
return internal::VectorIndexedViewSelector<Derived, Indices>::run(derived(), Indices{indices});
|
||||
}
|
||||
|
||||
#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::placeholders::all indexing the full set of respective rows or columns in increasing order
|
||||
* - An ArithmeticSequence as returned by the Eigen::seq and Eigen::seqN functions
|
||||
* - Any %Eigen's vector/array of integers or expressions
|
||||
* - Plain C arrays: \c int[N]
|
||||
* - And more generally any type exposing the following two member functions:
|
||||
* \code
|
||||
* <integral type> operator[](<integral type>) const;
|
||||
* <integral type> size() const;
|
||||
* \endcode
|
||||
* where \c <integral \c type> stands for any integer type compatible with Eigen::Index (i.e. \c std::ptrdiff_t).
|
||||
*
|
||||
* The last statement implies compatibility with \c std::vector, \c std::valarray, \c std::array, many of the Range-v3's
|
||||
* ranges, etc.
|
||||
*
|
||||
* If the submatrix can be represented using a starting position \c (i,j) and positive sizes \c (rows,columns), then
|
||||
* this method will returns a Block object after extraction of the relevant information from the passed arguments. This
|
||||
* is the case when all arguments are either:
|
||||
* - An integer
|
||||
* - Eigen::placeholders::all
|
||||
* - An ArithmeticSequence with compile-time increment strictly equal to 1, as returned by Eigen::seq(a,b), and
|
||||
* Eigen::seqN(a,N).
|
||||
*
|
||||
* Otherwise a more general IndexedView<Derived,RowIndices',ColIndices'> object will be returned, after conversion of
|
||||
* the inputs to more suitable types \c RowIndices' and \c ColIndices'.
|
||||
*
|
||||
* For 1D vectors and arrays, you better use the operator()(const Indices&) overload, which behave the same way but
|
||||
* taking a single parameter.
|
||||
*
|
||||
* See also this <a
|
||||
* href="https://stackoverflow.com/questions/46110917/eigen-replicate-items-along-one-dimension-without-useless-allocations">question</a>
|
||||
* and its answer for an example of how to duplicate coefficients.
|
||||
*
|
||||
* \sa operator()(const Indices&), class Block, class IndexedView, DenseBase::block(Index,Index,Index,Index)
|
||||
*/
|
||||
template <typename RowIndices, typename ColIndices>
|
||||
IndexedView_or_Block operator()(const RowIndices& rowIndices, const ColIndices& colIndices);
|
||||
|
||||
/** This is an overload of operator()(const RowIndices&, const ColIndices&) for 1D vectors or arrays
|
||||
*
|
||||
* \only_for_vectors
|
||||
*/
|
||||
template <typename Indices>
|
||||
IndexedView_or_VectorBlock operator()(const Indices& indices);
|
||||
|
||||
#endif // EIGEN_PARSED_BY_DOXYGEN
|
||||
@@ -0,0 +1,3 @@
|
||||
#ifndef EIGEN_CORE_MODULE_H
|
||||
#error "Please include Eigen/plugins instead of including headers inside the src directory directly."
|
||||
#endif
|
||||
@@ -0,0 +1,331 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
// This file is a base class plugin containing matrix specifics coefficient wise functions.
|
||||
|
||||
/** \returns an expression of the Schur product (coefficient wise product) of *this and \a other
|
||||
*
|
||||
* Example: \include MatrixBase_cwiseProduct.cpp
|
||||
* Output: \verbinclude MatrixBase_cwiseProduct.out
|
||||
*
|
||||
* \sa class CwiseBinaryOp, cwiseAbs2
|
||||
*/
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const EIGEN_CWISE_BINARY_RETURN_TYPE(Derived, OtherDerived, product)
|
||||
cwiseProduct(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return EIGEN_CWISE_BINARY_RETURN_TYPE(Derived, OtherDerived, product)(derived(), other.derived());
|
||||
}
|
||||
|
||||
template <typename OtherDerived>
|
||||
using CwiseBinaryEqualReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_EQ>, const Derived, const OtherDerived>;
|
||||
template <typename OtherDerived>
|
||||
using CwiseBinaryNotEqualReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_NEQ>, const Derived, const OtherDerived>;
|
||||
template <typename OtherDerived>
|
||||
using CwiseBinaryLessReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_LT>, const Derived, const OtherDerived>;
|
||||
template <typename OtherDerived>
|
||||
using CwiseBinaryGreaterReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_GT>, const Derived, const OtherDerived>;
|
||||
template <typename OtherDerived>
|
||||
using CwiseBinaryLessOrEqualReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_LE>, const Derived, const OtherDerived>;
|
||||
template <typename OtherDerived>
|
||||
using CwiseBinaryGreaterOrEqualReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_GE>, const Derived, const OtherDerived>;
|
||||
|
||||
/** \returns an expression of the coefficient-wise == operator of *this and \a other
|
||||
*
|
||||
* \warning this performs an exact comparison, which is generally a bad idea with floating-point types.
|
||||
* In order to check for equality between two vectors or matrices with floating-point coefficients, it is
|
||||
* generally a far better idea to use a fuzzy comparison as provided by isApprox() and
|
||||
* isMuchSmallerThan().
|
||||
*
|
||||
* Example: \include MatrixBase_cwiseEqual.cpp
|
||||
* Output: \verbinclude MatrixBase_cwiseEqual.out
|
||||
*
|
||||
* \sa cwiseNotEqual(), isApprox(), isMuchSmallerThan()
|
||||
*/
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC inline const CwiseBinaryEqualReturnType<OtherDerived> cwiseEqual(
|
||||
const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryEqualReturnType<OtherDerived>(derived(), other.derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise != operator of *this and \a other
|
||||
*
|
||||
* \warning this performs an exact comparison, which is generally a bad idea with floating-point types.
|
||||
* In order to check for equality between two vectors or matrices with floating-point coefficients, it is
|
||||
* generally a far better idea to use a fuzzy comparison as provided by isApprox() and
|
||||
* isMuchSmallerThan().
|
||||
*
|
||||
* Example: \include MatrixBase_cwiseNotEqual.cpp
|
||||
* Output: \verbinclude MatrixBase_cwiseNotEqual.out
|
||||
*
|
||||
* \sa cwiseEqual(), isApprox(), isMuchSmallerThan()
|
||||
*/
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC inline const CwiseBinaryNotEqualReturnType<OtherDerived> cwiseNotEqual(
|
||||
const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryNotEqualReturnType<OtherDerived>(derived(), other.derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise < operator of *this and \a other */
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC inline const CwiseBinaryLessReturnType<OtherDerived> cwiseLess(
|
||||
const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryLessReturnType<OtherDerived>(derived(), other.derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise > operator of *this and \a other */
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC inline const CwiseBinaryGreaterReturnType<OtherDerived> cwiseGreater(
|
||||
const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryGreaterReturnType<OtherDerived>(derived(), other.derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise <= operator of *this and \a other */
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC inline const CwiseBinaryLessOrEqualReturnType<OtherDerived> cwiseLessOrEqual(
|
||||
const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryLessOrEqualReturnType<OtherDerived>(derived(), other.derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise >= operator of *this and \a other */
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC inline const CwiseBinaryGreaterOrEqualReturnType<OtherDerived> cwiseGreaterOrEqual(
|
||||
const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryGreaterOrEqualReturnType<OtherDerived>(derived(), other.derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise min of *this and \a other
|
||||
*
|
||||
* Example: \include MatrixBase_cwiseMin.cpp
|
||||
* Output: \verbinclude MatrixBase_cwiseMin.out
|
||||
*
|
||||
* \sa class CwiseBinaryOp, max()
|
||||
*/
|
||||
template <int NaNPropagation = PropagateFast, typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const
|
||||
CwiseBinaryOp<internal::scalar_min_op<Scalar, Scalar, NaNPropagation>, const Derived, const OtherDerived>
|
||||
cwiseMin(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryOp<internal::scalar_min_op<Scalar, Scalar, NaNPropagation>, const Derived, const OtherDerived>(
|
||||
derived(), other.derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise min of *this and scalar \a other
|
||||
*
|
||||
* \sa class CwiseBinaryOp, min()
|
||||
*/
|
||||
template <int NaNPropagation = PropagateFast>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const
|
||||
CwiseBinaryOp<internal::scalar_min_op<Scalar, Scalar, NaNPropagation>, const Derived, const ConstantReturnType>
|
||||
cwiseMin(const Scalar& other) const {
|
||||
return cwiseMin<NaNPropagation>(Derived::Constant(rows(), cols(), other));
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise max of *this and \a other
|
||||
*
|
||||
* Example: \include MatrixBase_cwiseMax.cpp
|
||||
* Output: \verbinclude MatrixBase_cwiseMax.out
|
||||
*
|
||||
* \sa class CwiseBinaryOp, min()
|
||||
*/
|
||||
template <int NaNPropagation = PropagateFast, typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const
|
||||
CwiseBinaryOp<internal::scalar_max_op<Scalar, Scalar, NaNPropagation>, const Derived, const OtherDerived>
|
||||
cwiseMax(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryOp<internal::scalar_max_op<Scalar, Scalar, NaNPropagation>, const Derived, const OtherDerived>(
|
||||
derived(), other.derived());
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise max of *this and scalar \a other
|
||||
*
|
||||
* \sa class CwiseBinaryOp, min()
|
||||
*/
|
||||
template <int NaNPropagation = PropagateFast>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const
|
||||
CwiseBinaryOp<internal::scalar_max_op<Scalar, Scalar, NaNPropagation>, const Derived, const ConstantReturnType>
|
||||
cwiseMax(const Scalar& other) const {
|
||||
return cwiseMax<NaNPropagation>(Derived::Constant(rows(), cols(), other));
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise quotient of *this and \a other
|
||||
*
|
||||
* Example: \include MatrixBase_cwiseQuotient.cpp
|
||||
* Output: \verbinclude MatrixBase_cwiseQuotient.out
|
||||
*
|
||||
* \sa class CwiseBinaryOp, cwiseProduct(), cwiseInverse()
|
||||
*/
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const
|
||||
CwiseBinaryOp<internal::scalar_quotient_op<Scalar>, const Derived, const OtherDerived>
|
||||
cwiseQuotient(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryOp<internal::scalar_quotient_op<Scalar>, const Derived, const OtherDerived>(derived(),
|
||||
other.derived());
|
||||
}
|
||||
|
||||
using CwiseScalarEqualReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_EQ>, const Derived, const ConstantReturnType>;
|
||||
using CwiseScalarNotEqualReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_NEQ>, const Derived, const ConstantReturnType>;
|
||||
using CwiseScalarLessReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_LT>, const Derived, const ConstantReturnType>;
|
||||
using CwiseScalarGreaterReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_GT>, const Derived, const ConstantReturnType>;
|
||||
using CwiseScalarLessOrEqualReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_LE>, const Derived, const ConstantReturnType>;
|
||||
using CwiseScalarGreaterOrEqualReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_GE>, const Derived, const ConstantReturnType>;
|
||||
|
||||
/** \returns an expression of the coefficient-wise == operator of \c *this and a scalar \a s
|
||||
*
|
||||
* \warning this performs an exact comparison, which is generally a bad idea with floating-point types.
|
||||
* In order to check for equality between two vectors or matrices with floating-point coefficients, it is
|
||||
* generally a far better idea to use a fuzzy comparison as provided by isApprox() and
|
||||
* isMuchSmallerThan().
|
||||
*
|
||||
* \sa cwiseEqual(const MatrixBase<OtherDerived> &) const
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const CwiseScalarEqualReturnType cwiseEqual(const Scalar& s) const {
|
||||
return CwiseScalarEqualReturnType(derived(), Derived::Constant(rows(), cols(), s));
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise == operator of \c *this and a scalar \a s
|
||||
*
|
||||
* \warning this performs an exact comparison, which is generally a bad idea with floating-point types.
|
||||
* In order to check for equality between two vectors or matrices with floating-point coefficients, it is
|
||||
* generally a far better idea to use a fuzzy comparison as provided by isApprox() and
|
||||
* isMuchSmallerThan().
|
||||
*
|
||||
* \sa cwiseEqual(const MatrixBase<OtherDerived> &) const
|
||||
*/
|
||||
EIGEN_DEVICE_FUNC inline const CwiseScalarNotEqualReturnType cwiseNotEqual(const Scalar& s) const {
|
||||
return CwiseScalarNotEqualReturnType(derived(), Derived::Constant(rows(), cols(), s));
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise < operator of \c *this and a scalar \a s */
|
||||
EIGEN_DEVICE_FUNC inline const CwiseScalarLessReturnType cwiseLess(const Scalar& s) const {
|
||||
return CwiseScalarLessReturnType(derived(), Derived::Constant(rows(), cols(), s));
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise > operator of \c *this and a scalar \a s */
|
||||
EIGEN_DEVICE_FUNC inline const CwiseScalarGreaterReturnType cwiseGreater(const Scalar& s) const {
|
||||
return CwiseScalarGreaterReturnType(derived(), Derived::Constant(rows(), cols(), s));
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise <= operator of \c *this and a scalar \a s */
|
||||
EIGEN_DEVICE_FUNC inline const CwiseScalarLessOrEqualReturnType cwiseLessOrEqual(const Scalar& s) const {
|
||||
return CwiseScalarLessOrEqualReturnType(derived(), Derived::Constant(rows(), cols(), s));
|
||||
}
|
||||
|
||||
/** \returns an expression of the coefficient-wise >= operator of \c *this and a scalar \a s */
|
||||
EIGEN_DEVICE_FUNC inline const CwiseScalarGreaterOrEqualReturnType cwiseGreaterOrEqual(const Scalar& s) const {
|
||||
return CwiseScalarGreaterOrEqualReturnType(derived(), Derived::Constant(rows(), cols(), s));
|
||||
}
|
||||
|
||||
template <typename OtherDerived>
|
||||
using CwiseBinaryTypedEqualReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_EQ, true>, const Derived, const OtherDerived>;
|
||||
template <typename OtherDerived>
|
||||
using CwiseBinaryTypedNotEqualReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_NEQ, true>, const Derived, const OtherDerived>;
|
||||
template <typename OtherDerived>
|
||||
using CwiseBinaryTypedLessReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_LT, true>, const Derived, const OtherDerived>;
|
||||
template <typename OtherDerived>
|
||||
using CwiseBinaryTypedGreaterReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_GT, true>, const Derived, const OtherDerived>;
|
||||
template <typename OtherDerived>
|
||||
using CwiseBinaryTypedLessOrEqualReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_LE, true>, const Derived, const OtherDerived>;
|
||||
template <typename OtherDerived>
|
||||
using CwiseBinaryTypedGreaterOrEqualReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_GE, true>, const Derived, const OtherDerived>;
|
||||
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseBinaryTypedEqualReturnType<OtherDerived> cwiseTypedEqual(
|
||||
const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryTypedEqualReturnType<OtherDerived>(derived(), other.derived());
|
||||
}
|
||||
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseBinaryTypedNotEqualReturnType<OtherDerived> cwiseTypedNotEqual(
|
||||
const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryTypedNotEqualReturnType<OtherDerived>(derived(), other.derived());
|
||||
}
|
||||
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseBinaryTypedLessReturnType<OtherDerived> cwiseTypedLess(
|
||||
const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryTypedLessReturnType<OtherDerived>(derived(), other.derived());
|
||||
}
|
||||
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseBinaryTypedGreaterReturnType<OtherDerived> cwiseTypedGreater(
|
||||
const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryTypedGreaterReturnType<OtherDerived>(derived(), other.derived());
|
||||
}
|
||||
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseBinaryTypedLessOrEqualReturnType<OtherDerived> cwiseTypedLessOrEqual(
|
||||
const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryTypedLessOrEqualReturnType<OtherDerived>(derived(), other.derived());
|
||||
}
|
||||
|
||||
template <typename OtherDerived>
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseBinaryTypedGreaterOrEqualReturnType<OtherDerived>
|
||||
cwiseTypedGreaterOrEqual(const EIGEN_CURRENT_STORAGE_BASE_CLASS<OtherDerived>& other) const {
|
||||
return CwiseBinaryTypedGreaterOrEqualReturnType<OtherDerived>(derived(), other.derived());
|
||||
}
|
||||
|
||||
using CwiseScalarTypedEqualReturnType = CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_EQ, true>,
|
||||
const Derived, const ConstantReturnType>;
|
||||
using CwiseScalarTypedNotEqualReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_NEQ, true>, const Derived,
|
||||
const ConstantReturnType>;
|
||||
using CwiseScalarTypedLessReturnType = CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_LT, true>,
|
||||
const Derived, const ConstantReturnType>;
|
||||
using CwiseScalarTypedGreaterReturnType = CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_GT, true>,
|
||||
const Derived, const ConstantReturnType>;
|
||||
using CwiseScalarTypedLessOrEqualReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_LE, true>, const Derived,
|
||||
const ConstantReturnType>;
|
||||
using CwiseScalarTypedGreaterOrEqualReturnType =
|
||||
CwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_GE, true>, const Derived,
|
||||
const ConstantReturnType>;
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseScalarTypedEqualReturnType cwiseTypedEqual(const Scalar& s) const {
|
||||
return CwiseScalarTypedEqualReturnType(derived(), ConstantReturnType(rows(), cols(), s));
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseScalarTypedNotEqualReturnType
|
||||
cwiseTypedNotEqual(const Scalar& s) const {
|
||||
return CwiseScalarTypedNotEqualReturnType(derived(), ConstantReturnType(rows(), cols(), s));
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseScalarTypedLessReturnType cwiseTypedLess(const Scalar& s) const {
|
||||
return CwiseScalarTypedLessReturnType(derived(), ConstantReturnType(rows(), cols(), s));
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseScalarTypedGreaterReturnType cwiseTypedGreater(const Scalar& s) const {
|
||||
return CwiseScalarTypedGreaterReturnType(derived(), ConstantReturnType(rows(), cols(), s));
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseScalarTypedLessOrEqualReturnType
|
||||
cwiseTypedLessOrEqual(const Scalar& s) const {
|
||||
return CwiseScalarTypedLessOrEqualReturnType(derived(), ConstantReturnType(rows(), cols(), s));
|
||||
}
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseScalarTypedGreaterOrEqualReturnType
|
||||
cwiseTypedGreaterOrEqual(const Scalar& s) const {
|
||||
return CwiseScalarTypedGreaterOrEqualReturnType(derived(), ConstantReturnType(rows(), cols(), s));
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
// This file is included into the body of the base classes supporting matrix specific coefficient-wise functions.
|
||||
// This include MatrixBase and SparseMatrixBase.
|
||||
|
||||
typedef CwiseUnaryOp<internal::scalar_abs_op<Scalar>, const Derived> CwiseAbsReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_abs2_op<Scalar>, const Derived> CwiseAbs2ReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_arg_op<Scalar>, const Derived> CwiseArgReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_carg_op<Scalar>, const Derived> CwiseCArgReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_sqrt_op<Scalar>, const Derived> CwiseSqrtReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_cbrt_op<Scalar>, const Derived> CwiseCbrtReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_square_op<Scalar>, const Derived> CwiseSquareReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_sign_op<Scalar>, const Derived> CwiseSignReturnType;
|
||||
typedef CwiseUnaryOp<internal::scalar_inverse_op<Scalar>, const Derived> CwiseInverseReturnType;
|
||||
|
||||
/// \returns an expression of the coefficient-wise absolute value of \c *this
|
||||
///
|
||||
/// Example: \include MatrixBase_cwiseAbs.cpp
|
||||
/// Output: \verbinclude MatrixBase_cwiseAbs.out
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(cwiseAbs, absolute value)
|
||||
///
|
||||
/// \sa cwiseAbs2()
|
||||
///
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseAbsReturnType cwiseAbs() const {
|
||||
return CwiseAbsReturnType(derived());
|
||||
}
|
||||
|
||||
/// \returns an expression of the coefficient-wise squared absolute value of \c *this
|
||||
///
|
||||
/// Example: \include MatrixBase_cwiseAbs2.cpp
|
||||
/// Output: \verbinclude MatrixBase_cwiseAbs2.out
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(cwiseAbs2, squared absolute value)
|
||||
///
|
||||
/// \sa cwiseAbs()
|
||||
///
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseAbs2ReturnType cwiseAbs2() const {
|
||||
return CwiseAbs2ReturnType(derived());
|
||||
}
|
||||
|
||||
/// \returns an expression of the coefficient-wise square root of *this.
|
||||
///
|
||||
/// Example: \include MatrixBase_cwiseSqrt.cpp
|
||||
/// Output: \verbinclude MatrixBase_cwiseSqrt.out
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(cwiseSqrt, square - root)
|
||||
///
|
||||
/// \sa cwisePow(), cwiseSquare(), cwiseCbrt()
|
||||
///
|
||||
EIGEN_DEVICE_FUNC inline const CwiseSqrtReturnType cwiseSqrt() const { return CwiseSqrtReturnType(derived()); }
|
||||
|
||||
/// \returns an expression of the coefficient-wise cube root of *this.
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(cwiseCbrt, cube - root)
|
||||
///
|
||||
/// \sa cwiseSqrt(), cwiseSquare(), cwisePow()
|
||||
///
|
||||
EIGEN_DEVICE_FUNC inline const CwiseCbrtReturnType cwiseCbrt() const { return CwiseCbrtReturnType(derived()); }
|
||||
|
||||
/// \returns an expression of the coefficient-wise square of *this.
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(cwiseSquare, square)
|
||||
///
|
||||
/// \sa cwisePow(), cwiseSqrt(), cwiseCbrt()
|
||||
///
|
||||
EIGEN_DEVICE_FUNC inline const CwiseSquareReturnType cwiseSquare() const { return CwiseSquareReturnType(derived()); }
|
||||
|
||||
/// \returns an expression of the coefficient-wise signum of *this.
|
||||
///
|
||||
/// Example: \include MatrixBase_cwiseSign.cpp
|
||||
/// Output: \verbinclude MatrixBase_cwiseSign.out
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(cwiseSign, sign function)
|
||||
///
|
||||
EIGEN_DEVICE_FUNC inline const CwiseSignReturnType cwiseSign() const { return CwiseSignReturnType(derived()); }
|
||||
|
||||
/// \returns an expression of the coefficient-wise inverse of *this.
|
||||
///
|
||||
/// Example: \include MatrixBase_cwiseInverse.cpp
|
||||
/// Output: \verbinclude MatrixBase_cwiseInverse.out
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(cwiseInverse, inverse)
|
||||
///
|
||||
/// \sa cwiseProduct()
|
||||
///
|
||||
EIGEN_DEVICE_FUNC inline const CwiseInverseReturnType cwiseInverse() const { return CwiseInverseReturnType(derived()); }
|
||||
|
||||
/// \returns an expression of the coefficient-wise phase angle of \c *this
|
||||
///
|
||||
/// Example: \include MatrixBase_cwiseArg.cpp
|
||||
/// Output: \verbinclude MatrixBase_cwiseArg.out
|
||||
///
|
||||
EIGEN_DOC_UNARY_ADDONS(cwiseArg, arg)
|
||||
|
||||
EIGEN_DEVICE_FUNC inline const CwiseArgReturnType cwiseArg() const { return CwiseArgReturnType(derived()); }
|
||||
|
||||
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseCArgReturnType cwiseCArg() const {
|
||||
return CwiseCArgReturnType(derived());
|
||||
}
|
||||
|
||||
template <typename ScalarExponent>
|
||||
using CwisePowReturnType =
|
||||
std::enable_if_t<internal::is_arithmetic<typename NumTraits<ScalarExponent>::Real>::value,
|
||||
CwiseUnaryOp<internal::scalar_unary_pow_op<Scalar, ScalarExponent>, const Derived>>;
|
||||
|
||||
template <typename ScalarExponent>
|
||||
EIGEN_DEVICE_FUNC inline const CwisePowReturnType<ScalarExponent> cwisePow(const ScalarExponent& exponent) const {
|
||||
return CwisePowReturnType<ScalarExponent>(derived(), internal::scalar_unary_pow_op<Scalar, ScalarExponent>(exponent));
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
|
||||
/// \returns an expression of \c *this with reshaped sizes.
|
||||
///
|
||||
/// \param nRows the number of rows in the reshaped expression, specified at either run-time or compile-time, or
|
||||
/// AutoSize \param nCols the number of columns in the reshaped expression, specified at either run-time or
|
||||
/// compile-time, or AutoSize \tparam Order specifies whether the coefficients should be processed in column-major-order
|
||||
/// (ColMajor), in row-major-order (RowMajor),
|
||||
/// or follows the \em natural order of the nested expression (AutoOrder). The default is ColMajor.
|
||||
/// \tparam NRowsType the type of the value handling the number of rows, typically Index.
|
||||
/// \tparam NColsType the type of the value handling the number of columns, typically Index.
|
||||
///
|
||||
/// Dynamic size example: \include MatrixBase_reshaped_int_int.cpp
|
||||
/// Output: \verbinclude MatrixBase_reshaped_int_int.out
|
||||
///
|
||||
/// The number of rows \a nRows and columns \a nCols can also be specified at compile-time by passing Eigen::fix<N>,
|
||||
/// or Eigen::fix<N>(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 and columns: \include
|
||||
/// MatrixBase_reshaped_fixed.cpp Output: \verbinclude MatrixBase_reshaped_fixed.out
|
||||
///
|
||||
/// Finally, one of the sizes parameter can be automatically deduced from the other one by passing AutoSize as in the
|
||||
/// following example: \include MatrixBase_reshaped_auto.cpp Output: \verbinclude MatrixBase_reshaped_auto.out AutoSize
|
||||
/// does preserve compile-time sizes when possible, i.e., when the sizes of the input are known at compile time \b and
|
||||
/// that the other size is passed at compile-time using Eigen::fix<N> as above.
|
||||
///
|
||||
/// \sa class Reshaped, fix, fix<N>(int)
|
||||
///
|
||||
template <int Order = ColMajor, typename NRowsType, typename NColsType>
|
||||
EIGEN_DEVICE_FUNC inline Reshaped<Derived, ...> reshaped(NRowsType nRows, NColsType nCols);
|
||||
|
||||
/// This is the const version of reshaped(NRowsType,NColsType).
|
||||
template <int Order = ColMajor, typename NRowsType, typename NColsType>
|
||||
EIGEN_DEVICE_FUNC inline const Reshaped<const Derived, ...> reshaped(NRowsType nRows, NColsType nCols) const;
|
||||
|
||||
/// \returns an expression of \c *this with columns (or rows) stacked to a linear column vector
|
||||
///
|
||||
/// \tparam Order specifies whether the coefficients should be processed in column-major-order (ColMajor), in
|
||||
/// row-major-order (RowMajor),
|
||||
/// or follows the \em natural order of the nested expression (AutoOrder). The default is ColMajor.
|
||||
///
|
||||
/// This overloads is essentially a shortcut for `A.reshaped<Order>(AutoSize,fix<1>)`.
|
||||
///
|
||||
/// - If `Order==ColMajor` (the default), then it returns a column-vector from the stacked columns of \c *this.
|
||||
/// - If `Order==RowMajor`, then it returns a column-vector from the stacked rows of \c *this.
|
||||
/// - If `Order==AutoOrder`, then it returns a column-vector with elements stacked following the storage order of \c
|
||||
/// *this.
|
||||
/// This mode is the recommended one when the particular ordering of the element is not relevant.
|
||||
///
|
||||
/// Example:
|
||||
/// \include MatrixBase_reshaped_to_vector.cpp
|
||||
/// Output: \verbinclude MatrixBase_reshaped_to_vector.out
|
||||
///
|
||||
/// If you want more control, you can still fall back to reshaped(NRowsType,NColsType).
|
||||
///
|
||||
/// \sa reshaped(NRowsType,NColsType), class Reshaped
|
||||
///
|
||||
template <int Order = ColMajor>
|
||||
EIGEN_DEVICE_FUNC inline Reshaped<Derived, ...> reshaped();
|
||||
|
||||
/// This is the const version of reshaped().
|
||||
template <int Order = ColMajor>
|
||||
EIGEN_DEVICE_FUNC inline const Reshaped<const Derived, ...> reshaped() const;
|
||||
|
||||
#else
|
||||
|
||||
// This file is automatically included twice to generate const and non-const versions
|
||||
|
||||
#ifndef EIGEN_RESHAPED_METHOD_2ND_PASS
|
||||
#define EIGEN_RESHAPED_METHOD_CONST const
|
||||
#else
|
||||
#define EIGEN_RESHAPED_METHOD_CONST
|
||||
#endif
|
||||
|
||||
#ifndef EIGEN_RESHAPED_METHOD_2ND_PASS
|
||||
|
||||
// This part is included once
|
||||
|
||||
#endif
|
||||
|
||||
template <typename NRowsType, typename NColsType>
|
||||
EIGEN_DEVICE_FUNC inline Reshaped<
|
||||
EIGEN_RESHAPED_METHOD_CONST Derived,
|
||||
internal::get_compiletime_reshape_size<NRowsType, NColsType, SizeAtCompileTime>::value,
|
||||
internal::get_compiletime_reshape_size<NColsType, NRowsType, SizeAtCompileTime>::value>
|
||||
reshaped(NRowsType nRows, NColsType nCols) EIGEN_RESHAPED_METHOD_CONST {
|
||||
return Reshaped<EIGEN_RESHAPED_METHOD_CONST Derived,
|
||||
internal::get_compiletime_reshape_size<NRowsType, NColsType, SizeAtCompileTime>::value,
|
||||
internal::get_compiletime_reshape_size<NColsType, NRowsType, SizeAtCompileTime>::value>(
|
||||
derived(), internal::get_runtime_reshape_size(nRows, internal::get_runtime_value(nCols), size()),
|
||||
internal::get_runtime_reshape_size(nCols, internal::get_runtime_value(nRows), size()));
|
||||
}
|
||||
|
||||
template <int Order, typename NRowsType, typename NColsType>
|
||||
EIGEN_DEVICE_FUNC inline Reshaped<
|
||||
EIGEN_RESHAPED_METHOD_CONST Derived,
|
||||
internal::get_compiletime_reshape_size<NRowsType, NColsType, SizeAtCompileTime>::value,
|
||||
internal::get_compiletime_reshape_size<NColsType, NRowsType, SizeAtCompileTime>::value,
|
||||
internal::get_compiletime_reshape_order(Flags, Order)>
|
||||
reshaped(NRowsType nRows, NColsType nCols) EIGEN_RESHAPED_METHOD_CONST {
|
||||
return Reshaped<EIGEN_RESHAPED_METHOD_CONST Derived,
|
||||
internal::get_compiletime_reshape_size<NRowsType, NColsType, SizeAtCompileTime>::value,
|
||||
internal::get_compiletime_reshape_size<NColsType, NRowsType, SizeAtCompileTime>::value,
|
||||
internal::get_compiletime_reshape_order(Flags, Order)>(
|
||||
derived(), internal::get_runtime_reshape_size(nRows, internal::get_runtime_value(nCols), size()),
|
||||
internal::get_runtime_reshape_size(nCols, internal::get_runtime_value(nRows), size()));
|
||||
}
|
||||
|
||||
// Views as linear vectors
|
||||
|
||||
EIGEN_DEVICE_FUNC inline Reshaped<EIGEN_RESHAPED_METHOD_CONST Derived, SizeAtCompileTime, 1> reshaped()
|
||||
EIGEN_RESHAPED_METHOD_CONST {
|
||||
return Reshaped<EIGEN_RESHAPED_METHOD_CONST Derived, SizeAtCompileTime, 1>(derived(), size(), 1);
|
||||
}
|
||||
|
||||
template <int Order>
|
||||
EIGEN_DEVICE_FUNC inline Reshaped<EIGEN_RESHAPED_METHOD_CONST Derived, SizeAtCompileTime, 1,
|
||||
internal::get_compiletime_reshape_order(Flags, Order)>
|
||||
reshaped() EIGEN_RESHAPED_METHOD_CONST {
|
||||
EIGEN_STATIC_ASSERT(Order == RowMajor || Order == ColMajor || Order == AutoOrder, INVALID_TEMPLATE_PARAMETER);
|
||||
return Reshaped<EIGEN_RESHAPED_METHOD_CONST Derived, SizeAtCompileTime, 1,
|
||||
internal::get_compiletime_reshape_order(Flags, Order)>(derived(), size(), 1);
|
||||
}
|
||||
|
||||
#undef EIGEN_RESHAPED_METHOD_CONST
|
||||
|
||||
#ifndef EIGEN_RESHAPED_METHOD_2ND_PASS
|
||||
#define EIGEN_RESHAPED_METHOD_2ND_PASS
|
||||
#include "ReshapedMethods.inc"
|
||||
#undef EIGEN_RESHAPED_METHOD_2ND_PASS
|
||||
#endif
|
||||
|
||||
#endif // EIGEN_PARSED_BY_DOXYGEN
|
||||
Reference in New Issue
Block a user