chromium/third_party/eigen3/src/Eigen/src/Core/CoreEvaluators.h

// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2011 Benoit Jacob <[email protected]>
// Copyright (C) 2011-2014 Gael Guennebaud <[email protected]>
// Copyright (C) 2011-2012 Jitse Niesen <[email protected]>
//
// 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_COREEVALUATORS_H
#define EIGEN_COREEVALUATORS_H

// IWYU pragma: private
#include "./InternalHeaderCheck.h"

namespace Eigen {

namespace internal {

// This class returns the evaluator kind from the expression storage kind.
// Default assumes index based accessors
template <typename StorageKind>
struct storage_kind_to_evaluator_kind {};

// This class returns the evaluator shape from the expression storage kind.
// It can be Dense, Sparse, Triangular, Diagonal, SelfAdjoint, Band, etc.
template <typename StorageKind>
struct storage_kind_to_shape;

template <>
struct storage_kind_to_shape<Dense> {};
template <>
struct storage_kind_to_shape<SolverStorage> {};
template <>
struct storage_kind_to_shape<PermutationStorage> {};
template <>
struct storage_kind_to_shape<TranspositionsStorage> {};

// Evaluators have to be specialized with respect to various criteria such as:
//  - storage/structure/shape
//  - scalar type
//  - etc.
// Therefore, we need specialization of evaluator providing additional template arguments for each kind of evaluators.
// We currently distinguish the following kind of evaluators:
// - unary_evaluator    for expressions taking only one arguments (CwiseUnaryOp, CwiseUnaryView, Transpose,
// MatrixWrapper, ArrayWrapper, Reverse, Replicate)
// - binary_evaluator   for expression taking two arguments (CwiseBinaryOp)
// - ternary_evaluator   for expression taking three arguments (CwiseTernaryOp)
// - product_evaluator  for linear algebra products (Product); special case of binary_evaluator because it requires
// additional tags for dispatching.
// - mapbase_evaluator  for Map, Block, Ref
// - block_evaluator    for Block (special dispatching to a mapbase_evaluator or unary_evaluator)

template <typename T, typename Arg1Kind = typename evaluator_traits<typename T::Arg1>::Kind,
          typename Arg2Kind = typename evaluator_traits<typename T::Arg2>::Kind,
          typename Arg3Kind = typename evaluator_traits<typename T::Arg3>::Kind,
          typename Arg1Scalar = typename traits<typename T::Arg1>::Scalar,
          typename Arg2Scalar = typename traits<typename T::Arg2>::Scalar,
          typename Arg3Scalar = typename traits<typename T::Arg3>::Scalar>
struct ternary_evaluator;

template <typename T, typename LhsKind = typename evaluator_traits<typename T::Lhs>::Kind,
          typename RhsKind = typename evaluator_traits<typename T::Rhs>::Kind,
          typename LhsScalar = typename traits<typename T::Lhs>::Scalar,
          typename RhsScalar = typename traits<typename T::Rhs>::Scalar>
struct binary_evaluator;

template <typename T, typename Kind = typename evaluator_traits<typename T::NestedExpression>::Kind,
          typename Scalar = typename T::Scalar>
struct unary_evaluator;

// evaluator_traits<T> contains traits for evaluator<T>

template <typename T>
struct evaluator_traits_base {};

// Default evaluator traits
template <typename T>
struct evaluator_traits : public evaluator_traits_base<T> {};

template <typename T, typename Shape = typename evaluator_traits<T>::Shape>
struct evaluator_assume_aliasing {};

// By default, we assume a unary expression:
template <typename T>
struct evaluator : public unary_evaluator<T> {};

// TODO: Think about const-correctness
evaluator<const T>;

// ---------- base class for all evaluators ----------

template <typename ExpressionType>
struct evaluator_base {};

// -------------------- Matrix and Array --------------------
//
// evaluator<PlainObjectBase> is a common base class for the
// Matrix and Array evaluators.
// Here we directly specialize evaluator. This is not really a unary expression, and it is, by definition, dense,
// so no need for more sophisticated dispatching.

// this helper permits to completely eliminate m_outerStride if it is known at compiletime.
template <typename Scalar, int OuterStride>
class plainobjectbase_evaluator_data {};

plainobjectbase_evaluator_data<Scalar, Dynamic>;

evaluator<PlainObjectBase<Derived>>;

evaluator<Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>>;

evaluator<Array<Scalar, Rows, Cols, Options, MaxRows, MaxCols>>;

// -------------------- Transpose --------------------

unary_evaluator<Transpose<ArgType>, IndexBased>;

// -------------------- CwiseNullaryOp --------------------
// Like Matrix and Array, this is not really a unary expression, so we directly specialize evaluator.
// Likewise, there is not need to more sophisticated dispatching here.

template <typename Scalar, typename NullaryOp, bool has_nullary = has_nullary_operator<NullaryOp>::value,
          bool has_unary = has_unary_operator<NullaryOp>::value,
          bool has_binary = has_binary_operator<NullaryOp>::value>
struct nullary_wrapper {};

nullary_wrapper<Scalar, NullaryOp, true, false, false>;

nullary_wrapper<Scalar, NullaryOp, false, false, true>;

// We need the following specialization for vector-only functors assigned to a runtime vector,
// for instance, using linspace and assigning a RowVectorXd to a MatrixXd or even a row of a MatrixXd.
// In this case, i==0 and j is used for the actual iteration.
nullary_wrapper<Scalar, NullaryOp, false, true, false>;

nullary_wrapper<Scalar, NullaryOp, false, false, false>;

#if 0 && EIGEN_COMP_MSVC > 0
// Disable this ugly workaround. This is now handled in traits<Ref>::match,
// but this piece of code might still become handly if some other weird compilation
// erros pop up again.

// MSVC exhibits a weird compilation error when
// compiling:
//    Eigen::MatrixXf A = MatrixXf::Random(3,3);
//    Ref<const MatrixXf> R = 2.f*A;
// and that has_*ary_operator<scalar_constant_op<float>> have not been instantiated yet.
// The "problem" is that evaluator<2.f*A> is instantiated by traits<Ref>::match<2.f*A>
// and at that time has_*ary_operator<T> returns true regardless of T.
// Then nullary_wrapper is badly instantiated as nullary_wrapper<.,.,true,true,true>.
// The trick is thus to defer the proper instantiation of nullary_wrapper when coeff(),
// and packet() are really instantiated as implemented below:

// This is a simple wrapper around Index to enforce the re-instantiation of
// has_*ary_operator when needed.
template<typename T> struct nullary_wrapper_workaround_msvc {
  nullary_wrapper_workaround_msvc(const T&);
  operator T()const;
};

template<typename Scalar,typename NullaryOp>
struct nullary_wrapper<Scalar,NullaryOp,true,true,true>
{
  template <typename IndexType>
  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i, IndexType j) const {
    return nullary_wrapper<Scalar,NullaryOp,
    has_nullary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value,
    has_unary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value,
    has_binary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value>().operator()(op,i,j);
  }
  template <typename IndexType>
  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i) const {
    return nullary_wrapper<Scalar,NullaryOp,
    has_nullary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value,
    has_unary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value,
    has_binary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value>().operator()(op,i);
  }

  template <typename T, typename IndexType>
  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j) const {
    return nullary_wrapper<Scalar,NullaryOp,
    has_nullary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value,
    has_unary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value,
    has_binary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value>().template packetOp<T>(op,i,j);
  }
  template <typename T, typename IndexType>
  EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i) const {
    return nullary_wrapper<Scalar,NullaryOp,
    has_nullary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value,
    has_unary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value,
    has_binary_operator<NullaryOp,nullary_wrapper_workaround_msvc<IndexType> >::value>().template packetOp<T>(op,i);
  }
};
#endif  // MSVC workaround

evaluator<CwiseNullaryOp<NullaryOp, PlainObjectType>>;

// -------------------- CwiseUnaryOp --------------------

unary_evaluator<CwiseUnaryOp<UnaryOp, ArgType>, IndexBased>;

// ----------------------- Casting ---------------------

unary_evaluator<CwiseUnaryOp<core_cast_op<SrcType, DstType>, ArgType>, IndexBased>;

// -------------------- CwiseTernaryOp --------------------

// this is a ternary expression
evaluator<CwiseTernaryOp<TernaryOp, Arg1, Arg2, Arg3>>;

ternary_evaluator<CwiseTernaryOp<TernaryOp, Arg1, Arg2, Arg3>, IndexBased, IndexBased>;

// specialization for expresions like (a < b).select(c, d) to enable full vectorization
evaluator<CwiseTernaryOp<scalar_boolean_select_op<Scalar, Scalar, bool>, Arg1, Arg2, CwiseBinaryOp<scalar_cmp_op<Scalar, Scalar, cmp, false>, CmpLhsType, CmpRhsType>>>;

// -------------------- CwiseBinaryOp --------------------

// this is a binary expression
evaluator<CwiseBinaryOp<BinaryOp, Lhs, Rhs>>;

binary_evaluator<CwiseBinaryOp<BinaryOp, Lhs, Rhs>, IndexBased, IndexBased>;

// -------------------- CwiseUnaryView --------------------

unary_evaluator<CwiseUnaryView<UnaryOp, ArgType, StrideType>, IndexBased>;

// -------------------- Map --------------------

// FIXME perhaps the PlainObjectType could be provided by Derived::PlainObject ?
// but that might complicate template specialization
template <typename Derived, typename PlainObjectType>
struct mapbase_evaluator;

template <typename Derived, typename PlainObjectType>
struct mapbase_evaluator : evaluator_base<Derived> {};

evaluator<Map<PlainObjectType, MapOptions, StrideType>>;

// -------------------- Ref --------------------

evaluator<Ref<PlainObjectType, RefOptions, StrideType>>;

// -------------------- Block --------------------

template <typename ArgType, int BlockRows, int BlockCols, bool InnerPanel,
          bool HasDirectAccess = internal::has_direct_access<ArgType>::ret>
struct block_evaluator;

evaluator<Block<ArgType, BlockRows, BlockCols, InnerPanel>>;

// no direct-access => dispatch to a unary evaluator
block_evaluator<ArgType, BlockRows, BlockCols, InnerPanel, false>;

unary_evaluator<Block<ArgType, BlockRows, BlockCols, InnerPanel>, IndexBased>;

// TODO: This evaluator does not actually use the child evaluator;
// all action is via the data() as returned by the Block expression.

block_evaluator<ArgType, BlockRows, BlockCols, InnerPanel, true>;

// -------------------- Select --------------------
// NOTE shall we introduce a ternary_evaluator?

// TODO enable vectorization for Select
evaluator<Select<ConditionMatrixType, ThenMatrixType, ElseMatrixType>>;

// -------------------- Replicate --------------------

unary_evaluator<Replicate<ArgType, RowFactor, ColFactor>>;

// -------------------- MatrixWrapper and ArrayWrapper --------------------
//
// evaluator_wrapper_base<T> is a common base class for the
// MatrixWrapper and ArrayWrapper evaluators.

template <typename XprType>
struct evaluator_wrapper_base : evaluator_base<XprType> {};

unary_evaluator<MatrixWrapper<TArgType>>;

unary_evaluator<ArrayWrapper<TArgType>>;

// -------------------- Reverse --------------------

// defined in Reverse.h:
template <typename PacketType, bool ReversePacket>
struct reverse_packet_cond;

unary_evaluator<Reverse<ArgType, Direction>>;

// -------------------- Diagonal --------------------

evaluator<Diagonal<ArgType, DiagIndex>>;

//----------------------------------------------------------------------
// deprecated code
//----------------------------------------------------------------------

// -------------------- EvalToTemp --------------------

// expression class for evaluating nested expression to a temporary

template <typename ArgType>
class EvalToTemp;

traits<EvalToTemp<ArgType>>;

template <typename ArgType>
class EvalToTemp : public dense_xpr_base<EvalToTemp<ArgType>>::type {};

evaluator<EvalToTemp<ArgType>>;

}  // namespace internal

}  // end namespace Eigen

#endif  // EIGEN_COREEVALUATORS_H