Home | History | Annotate | Download | only in Tensor
      1 // This file is part of Eigen, a lightweight C++ template library
      2 // for linear algebra.
      3 //
      4 // Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog (at) gmail.com>
      5 //
      6 // This Source Code Form is subject to the terms of the Mozilla
      7 // Public License v. 2.0. If a copy of the MPL was not distributed
      8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
      9 
     10 #ifndef EIGEN_CXX11_TENSOR_TENSOR_BASE_H
     11 #define EIGEN_CXX11_TENSOR_TENSOR_BASE_H
     12 
     13 // clang-format off
     14 
     15 namespace Eigen {
     16 
     17 /** \class TensorBase
     18   * \ingroup CXX11_Tensor_Module
     19   *
     20   * \brief The tensor base class.
     21   *
     22   * This class is the common parent of the Tensor and TensorMap class, thus
     23   * making it possible to use either class interchangably in expressions.
     24   */
     25 
     26 template<typename Derived>
     27 class TensorBase<Derived, ReadOnlyAccessors>
     28 {
     29   public:
     30     typedef internal::traits<Derived> DerivedTraits;
     31     typedef typename DerivedTraits::Scalar Scalar;
     32     typedef typename DerivedTraits::Index Index;
     33     typedef typename internal::remove_const<Scalar>::type CoeffReturnType;
     34     static const int NumDimensions = DerivedTraits::NumDimensions;
     35 
     36     // Generic nullary operation support.
     37     template <typename CustomNullaryOp> EIGEN_DEVICE_FUNC
     38     EIGEN_STRONG_INLINE const TensorCwiseNullaryOp<CustomNullaryOp, const Derived>
     39     nullaryExpr(const CustomNullaryOp& func) const {
     40       return TensorCwiseNullaryOp<CustomNullaryOp, const Derived>(derived(), func);
     41     }
     42 
     43     // Coefficient-wise nullary operators
     44     EIGEN_DEVICE_FUNC
     45     EIGEN_STRONG_INLINE const TensorCwiseNullaryOp<internal::scalar_constant_op<Scalar>, const Derived>
     46     constant(const Scalar& value) const {
     47       return nullaryExpr(internal::scalar_constant_op<Scalar>(value));
     48     }
     49 
     50     EIGEN_DEVICE_FUNC
     51     EIGEN_STRONG_INLINE const TensorCwiseNullaryOp<internal::UniformRandomGenerator<Scalar>, const Derived>
     52     random() const {
     53       return nullaryExpr(internal::UniformRandomGenerator<Scalar>());
     54     }
     55     template <typename RandomGenerator> EIGEN_DEVICE_FUNC
     56     EIGEN_STRONG_INLINE const TensorCwiseNullaryOp<RandomGenerator, const Derived>
     57     random(const RandomGenerator& gen = RandomGenerator()) const {
     58       return nullaryExpr(gen);
     59     }
     60 
     61     // Tensor generation
     62     template <typename Generator> EIGEN_DEVICE_FUNC
     63     EIGEN_STRONG_INLINE const TensorGeneratorOp<Generator, const Derived>
     64     generate(const Generator& generator) const {
     65       return TensorGeneratorOp<Generator, const Derived>(derived(), generator);
     66     }
     67 
     68     // Generic unary operation support.
     69     template <typename CustomUnaryOp> EIGEN_DEVICE_FUNC
     70     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<CustomUnaryOp, const Derived>
     71     unaryExpr(const CustomUnaryOp& func) const {
     72       return TensorCwiseUnaryOp<CustomUnaryOp, const Derived>(derived(), func);
     73     }
     74 
     75     // Coefficient-wise unary operators
     76     EIGEN_DEVICE_FUNC
     77     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_opposite_op<Scalar>, const Derived>
     78     operator-() const {
     79       return unaryExpr(internal::scalar_opposite_op<Scalar>());
     80     }
     81 
     82     EIGEN_DEVICE_FUNC
     83     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_sqrt_op<Scalar>, const Derived>
     84     sqrt() const {
     85       return unaryExpr(internal::scalar_sqrt_op<Scalar>());
     86     }
     87 
     88     EIGEN_DEVICE_FUNC
     89     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_sign_op<Scalar>, const Derived>
     90     sign() const {
     91       return unaryExpr(internal::scalar_sign_op<Scalar>());
     92     }
     93 
     94     EIGEN_DEVICE_FUNC
     95     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_rsqrt_op<Scalar>, const Derived>
     96     rsqrt() const {
     97       return unaryExpr(internal::scalar_rsqrt_op<Scalar>());
     98     }
     99 
    100     EIGEN_DEVICE_FUNC
    101     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_square_op<Scalar>, const Derived>
    102     square() const {
    103       return unaryExpr(internal::scalar_square_op<Scalar>());
    104     }
    105 
    106     EIGEN_DEVICE_FUNC
    107     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_cube_op<Scalar>, const Derived>
    108     cube() const {
    109       return unaryExpr(internal::scalar_cube_op<Scalar>());
    110     }
    111 
    112     EIGEN_DEVICE_FUNC
    113     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_inverse_op<Scalar>, const Derived>
    114     inverse() const {
    115       return unaryExpr(internal::scalar_inverse_op<Scalar>());
    116     }
    117 
    118     EIGEN_DEVICE_FUNC
    119     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_tanh_op<Scalar>, const Derived>
    120     tanh() const {
    121       return unaryExpr(internal::scalar_tanh_op<Scalar>());
    122     }
    123 
    124     EIGEN_DEVICE_FUNC
    125     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_lgamma_op<Scalar>, const Derived>
    126     lgamma() const {
    127       return unaryExpr(internal::scalar_lgamma_op<Scalar>());
    128     }
    129 
    130     EIGEN_DEVICE_FUNC
    131     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_digamma_op<Scalar>, const Derived>
    132     digamma() const {
    133       return unaryExpr(internal::scalar_digamma_op<Scalar>());
    134     }
    135 
    136     // igamma(a = this, x = other)
    137     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    138     const TensorCwiseBinaryOp<internal::scalar_igamma_op<Scalar>, const Derived, const OtherDerived>
    139     igamma(const OtherDerived& other) const {
    140       return binaryExpr(other.derived(), internal::scalar_igamma_op<Scalar>());
    141     }
    142 
    143     // igammac(a = this, x = other)
    144     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    145     const TensorCwiseBinaryOp<internal::scalar_igammac_op<Scalar>, const Derived, const OtherDerived>
    146     igammac(const OtherDerived& other) const {
    147       return binaryExpr(other.derived(), internal::scalar_igammac_op<Scalar>());
    148     }
    149 
    150     // zeta(x = this, q = other)
    151     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    152     const TensorCwiseBinaryOp<internal::scalar_zeta_op<Scalar>, const Derived, const OtherDerived>
    153     zeta(const OtherDerived& other) const {
    154       return binaryExpr(other.derived(), internal::scalar_zeta_op<Scalar>());
    155     }
    156 
    157     // polygamma(n = this, x = other)
    158     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    159     const TensorCwiseBinaryOp<internal::scalar_polygamma_op<Scalar>, const Derived, const OtherDerived>
    160     polygamma(const OtherDerived& other) const {
    161       return binaryExpr(other.derived(), internal::scalar_polygamma_op<Scalar>());
    162     }
    163 
    164     EIGEN_DEVICE_FUNC
    165     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_erf_op<Scalar>, const Derived>
    166     erf() const {
    167       return unaryExpr(internal::scalar_erf_op<Scalar>());
    168     }
    169 
    170     EIGEN_DEVICE_FUNC
    171     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_erfc_op<Scalar>, const Derived>
    172     erfc() const {
    173       return unaryExpr(internal::scalar_erfc_op<Scalar>());
    174     }
    175 
    176     EIGEN_DEVICE_FUNC
    177     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_sigmoid_op<Scalar>, const Derived>
    178     sigmoid() const {
    179       return unaryExpr(internal::scalar_sigmoid_op<Scalar>());
    180     }
    181 
    182     EIGEN_DEVICE_FUNC
    183     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_exp_op<Scalar>, const Derived>
    184     exp() const {
    185       return unaryExpr(internal::scalar_exp_op<Scalar>());
    186     }
    187 
    188     EIGEN_DEVICE_FUNC
    189     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_log_op<Scalar>, const Derived>
    190     log() const {
    191       return unaryExpr(internal::scalar_log_op<Scalar>());
    192     }
    193 
    194     EIGEN_DEVICE_FUNC
    195     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_log1p_op<Scalar>, const Derived>
    196     log1p() const {
    197       return unaryExpr(internal::scalar_log1p_op<Scalar>());
    198     }
    199 
    200     EIGEN_DEVICE_FUNC
    201     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_abs_op<Scalar>, const Derived>
    202     abs() const {
    203       return unaryExpr(internal::scalar_abs_op<Scalar>());
    204     }
    205 
    206     EIGEN_DEVICE_FUNC
    207     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_conjugate_op<Scalar>, const Derived>
    208     conjugate() const {
    209       return unaryExpr(internal::scalar_conjugate_op<Scalar>());
    210     }
    211 
    212     EIGEN_DEVICE_FUNC
    213     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::bind2nd_op<internal::scalar_pow_op<Scalar,Scalar> >, const Derived>
    214     pow(Scalar exponent) const {
    215       return unaryExpr(internal::bind2nd_op<internal::scalar_pow_op<Scalar,Scalar> >(exponent));
    216     }
    217 
    218     EIGEN_DEVICE_FUNC
    219     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_real_op<Scalar>, const Derived>
    220     real() const {
    221       return unaryExpr(internal::scalar_real_op<Scalar>());
    222     }
    223 
    224     EIGEN_DEVICE_FUNC
    225     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_imag_op<Scalar>, const Derived>
    226     imag() const {
    227       return unaryExpr(internal::scalar_imag_op<Scalar>());
    228     }
    229 
    230     EIGEN_DEVICE_FUNC
    231     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::bind2nd_op<internal::scalar_sum_op<Scalar,Scalar> >, const Derived>
    232     operator+ (Scalar rhs) const {
    233       return unaryExpr(internal::bind2nd_op<internal::scalar_sum_op<Scalar,Scalar> >(rhs));
    234     }
    235 
    236     EIGEN_DEVICE_FUNC
    237     EIGEN_STRONG_INLINE friend
    238     const TensorCwiseUnaryOp<internal::bind1st_op<internal::scalar_sum_op<Scalar> >, const Derived>
    239     operator+ (Scalar lhs, const Derived& rhs) {
    240       return rhs.unaryExpr(internal::bind1st_op<internal::scalar_sum_op<Scalar> >(lhs));
    241     }
    242 
    243     EIGEN_DEVICE_FUNC
    244     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::bind2nd_op<internal::scalar_difference_op<Scalar,Scalar> >, const Derived>
    245     operator- (Scalar rhs) const {
    246       EIGEN_STATIC_ASSERT((NumTraits<Scalar>::IsSigned || internal::is_same<Scalar, const std::complex<float> >::value), YOU_MADE_A_PROGRAMMING_MISTAKE);
    247       return unaryExpr(internal::bind2nd_op<internal::scalar_difference_op<Scalar,Scalar> >(rhs));
    248     }
    249 
    250     EIGEN_DEVICE_FUNC
    251     EIGEN_STRONG_INLINE friend
    252     const TensorCwiseUnaryOp<internal::bind1st_op<internal::scalar_difference_op<Scalar> >, const Derived>
    253     operator- (Scalar lhs, const Derived& rhs) {
    254       return rhs.unaryExpr(internal::bind1st_op<internal::scalar_difference_op<Scalar> >(lhs));
    255     }
    256 
    257     EIGEN_DEVICE_FUNC
    258     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::bind2nd_op<internal::scalar_product_op<Scalar,Scalar> >, const Derived>
    259     operator* (Scalar rhs) const {
    260       return unaryExpr(internal::bind2nd_op<internal::scalar_product_op<Scalar,Scalar> >(rhs));
    261     }
    262 
    263     EIGEN_DEVICE_FUNC
    264     EIGEN_STRONG_INLINE friend
    265     const TensorCwiseUnaryOp<internal::bind1st_op<internal::scalar_product_op<Scalar> >, const Derived>
    266     operator* (Scalar lhs, const Derived& rhs) {
    267       return rhs.unaryExpr(internal::bind1st_op<internal::scalar_product_op<Scalar> >(lhs));
    268     }
    269 
    270     EIGEN_DEVICE_FUNC
    271     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::bind2nd_op<internal::scalar_quotient_op<Scalar,Scalar> >, const Derived>
    272     operator/ (Scalar rhs) const {
    273       return unaryExpr(internal::bind2nd_op<internal::scalar_quotient_op<Scalar,Scalar> >(rhs));
    274     }
    275 
    276     EIGEN_DEVICE_FUNC
    277     EIGEN_STRONG_INLINE friend
    278     const TensorCwiseUnaryOp<internal::bind1st_op<internal::scalar_quotient_op<Scalar> >, const Derived>
    279     operator/ (Scalar lhs, const Derived& rhs) {
    280       return rhs.unaryExpr(internal::bind1st_op<internal::scalar_quotient_op<Scalar> >(lhs));
    281     }
    282 
    283     EIGEN_DEVICE_FUNC
    284     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_mod_op<Scalar>, const Derived>
    285     operator% (Scalar rhs) const {
    286       EIGEN_STATIC_ASSERT(NumTraits<Scalar>::IsInteger, YOU_MADE_A_PROGRAMMING_MISTAKE_TRY_MOD);
    287       return unaryExpr(internal::scalar_mod_op<Scalar>(rhs));
    288     }
    289 
    290     EIGEN_DEVICE_FUNC
    291     EIGEN_STRONG_INLINE const TensorCwiseBinaryOp<internal::scalar_max_op<Scalar>, const Derived, const TensorCwiseNullaryOp<internal::scalar_constant_op<Scalar>, const Derived> >
    292     cwiseMax(Scalar threshold) const {
    293       return cwiseMax(constant(threshold));
    294     }
    295 
    296     EIGEN_DEVICE_FUNC
    297     EIGEN_STRONG_INLINE const TensorCwiseBinaryOp<internal::scalar_min_op<Scalar>, const Derived, const TensorCwiseNullaryOp<internal::scalar_constant_op<Scalar>, const Derived> >
    298     cwiseMin(Scalar threshold) const {
    299       return cwiseMin(constant(threshold));
    300     }
    301 
    302     template <typename NewType> EIGEN_DEVICE_FUNC
    303     EIGEN_STRONG_INLINE const TensorConversionOp<NewType, const Derived>
    304     cast() const {
    305       return TensorConversionOp<NewType, const Derived>(derived());
    306     }
    307 
    308     EIGEN_DEVICE_FUNC
    309     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_round_op<Scalar>, const Derived>
    310     round() const {
    311       return unaryExpr(internal::scalar_round_op<Scalar>());
    312     }
    313 
    314     EIGEN_DEVICE_FUNC
    315     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_ceil_op<Scalar>, const Derived>
    316     ceil() const {
    317       return unaryExpr(internal::scalar_ceil_op<Scalar>());
    318     }
    319 
    320     EIGEN_DEVICE_FUNC
    321     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_floor_op<Scalar>, const Derived>
    322     floor() const {
    323       return unaryExpr(internal::scalar_floor_op<Scalar>());
    324     }
    325 
    326     // Generic binary operation support.
    327     template <typename CustomBinaryOp, typename OtherDerived> EIGEN_DEVICE_FUNC
    328     EIGEN_STRONG_INLINE const TensorCwiseBinaryOp<CustomBinaryOp, const Derived, const OtherDerived>
    329     binaryExpr(const OtherDerived& other, const CustomBinaryOp& func) const {
    330       return TensorCwiseBinaryOp<CustomBinaryOp, const Derived, const OtherDerived>(derived(), other, func);
    331     }
    332 
    333     // Coefficient-wise binary operators.
    334     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    335     const TensorCwiseBinaryOp<internal::scalar_sum_op<Scalar>, const Derived, const OtherDerived>
    336     operator+(const OtherDerived& other) const {
    337       return binaryExpr(other.derived(), internal::scalar_sum_op<Scalar>());
    338     }
    339 
    340     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    341     const TensorCwiseBinaryOp<internal::scalar_difference_op<Scalar>, const Derived, const OtherDerived>
    342     operator-(const OtherDerived& other) const {
    343       return binaryExpr(other.derived(), internal::scalar_difference_op<Scalar>());
    344     }
    345 
    346     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    347     const TensorCwiseBinaryOp<internal::scalar_product_op<Scalar>, const Derived, const OtherDerived>
    348     operator*(const OtherDerived& other) const {
    349       return binaryExpr(other.derived(), internal::scalar_product_op<Scalar>());
    350     }
    351 
    352     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    353     const TensorCwiseBinaryOp<internal::scalar_quotient_op<Scalar>, const Derived, const OtherDerived>
    354     operator/(const OtherDerived& other) const {
    355       return binaryExpr(other.derived(), internal::scalar_quotient_op<Scalar>());
    356     }
    357 
    358     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    359     const TensorCwiseBinaryOp<internal::scalar_max_op<Scalar>, const Derived, const OtherDerived>
    360     cwiseMax(const OtherDerived& other) const {
    361       return binaryExpr(other.derived(), internal::scalar_max_op<Scalar>());
    362     }
    363 
    364     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    365     const TensorCwiseBinaryOp<internal::scalar_min_op<Scalar>, const Derived, const OtherDerived>
    366     cwiseMin(const OtherDerived& other) const {
    367       return binaryExpr(other.derived(), internal::scalar_min_op<Scalar>());
    368     }
    369 
    370     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    371     const TensorCwiseBinaryOp<internal::scalar_boolean_and_op, const Derived, const OtherDerived>
    372     operator&&(const OtherDerived& other) const {
    373       return binaryExpr(other.derived(), internal::scalar_boolean_and_op());
    374     }
    375 
    376     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    377     const TensorCwiseBinaryOp<internal::scalar_boolean_or_op, const Derived, const OtherDerived>
    378     operator||(const OtherDerived& other) const {
    379       return binaryExpr(other.derived(), internal::scalar_boolean_or_op());
    380     }
    381 
    382     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    383     const TensorCwiseBinaryOp<internal::scalar_boolean_xor_op, const Derived, const OtherDerived>
    384     operator^(const OtherDerived& other) const {
    385       return binaryExpr(other.derived(), internal::scalar_boolean_xor_op());
    386     }
    387 
    388     // Comparisons and tests.
    389     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    390     const TensorCwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_LT>, const Derived, const OtherDerived>
    391     operator<(const OtherDerived& other) const {
    392       return binaryExpr(other.derived(), internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_LT>());
    393     }
    394     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    395     const TensorCwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_LE>, const Derived, const OtherDerived>
    396     operator<=(const OtherDerived& other) const {
    397       return binaryExpr(other.derived(), internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_LE>());
    398     }
    399     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    400     const TensorCwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_GT>, const Derived, const OtherDerived>
    401     operator>(const OtherDerived& other) const {
    402       return binaryExpr(other.derived(), internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_GT>());
    403     }
    404     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    405     const TensorCwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_GE>, const Derived, const OtherDerived>
    406     operator>=(const OtherDerived& other) const {
    407       return binaryExpr(other.derived(), internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_GE>());
    408     }
    409 
    410     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    411     const TensorCwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_EQ>, const Derived, const OtherDerived>
    412     operator==(const OtherDerived& other) const {
    413       return binaryExpr(other.derived(), internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_EQ>());
    414     }
    415 
    416     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    417     const TensorCwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_NEQ>, const Derived, const OtherDerived>
    418     operator!=(const OtherDerived& other) const {
    419       return binaryExpr(other.derived(), internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_NEQ>());
    420     }
    421 
    422     // comparisons and tests for Scalars
    423     EIGEN_DEVICE_FUNC
    424     EIGEN_STRONG_INLINE const TensorCwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_LT>, const Derived, const TensorCwiseNullaryOp<internal::scalar_constant_op<Scalar>, const Derived> >
    425     operator<(Scalar threshold) const {
    426       return operator<(constant(threshold));
    427     }
    428     EIGEN_DEVICE_FUNC
    429     EIGEN_STRONG_INLINE const TensorCwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_LE>, const Derived, const TensorCwiseNullaryOp<internal::scalar_constant_op<Scalar>, const Derived> >
    430     operator<=(Scalar threshold) const {
    431       return operator<=(constant(threshold));
    432     }
    433     EIGEN_DEVICE_FUNC
    434     EIGEN_STRONG_INLINE const TensorCwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_GT>, const Derived, const TensorCwiseNullaryOp<internal::scalar_constant_op<Scalar>, const Derived> >
    435     operator>(Scalar threshold) const {
    436       return operator>(constant(threshold));
    437     }
    438     EIGEN_DEVICE_FUNC
    439     EIGEN_STRONG_INLINE const TensorCwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_GE>, const Derived, const TensorCwiseNullaryOp<internal::scalar_constant_op<Scalar>, const Derived> >
    440     operator>=(Scalar threshold) const {
    441       return operator>=(constant(threshold));
    442     }
    443     EIGEN_DEVICE_FUNC
    444     EIGEN_STRONG_INLINE const TensorCwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_EQ>, const Derived, const TensorCwiseNullaryOp<internal::scalar_constant_op<Scalar>, const Derived> >
    445     operator==(Scalar threshold) const {
    446       return operator==(constant(threshold));
    447     }
    448     EIGEN_DEVICE_FUNC
    449     EIGEN_STRONG_INLINE const TensorCwiseBinaryOp<internal::scalar_cmp_op<Scalar, Scalar, internal::cmp_NEQ>, const Derived, const TensorCwiseNullaryOp<internal::scalar_constant_op<Scalar>, const Derived> >
    450     operator!=(Scalar threshold) const {
    451       return operator!=(constant(threshold));
    452     }
    453 
    454     // Checks
    455     EIGEN_DEVICE_FUNC
    456     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_isnan_op<Scalar>, const Derived>
    457     (isnan)() const {
    458       return unaryExpr(internal::scalar_isnan_op<Scalar>());
    459     }
    460     EIGEN_DEVICE_FUNC
    461     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_isinf_op<Scalar>, const Derived>
    462     (isinf)() const {
    463       return unaryExpr(internal::scalar_isinf_op<Scalar>());
    464     }
    465     EIGEN_DEVICE_FUNC
    466     EIGEN_STRONG_INLINE const TensorCwiseUnaryOp<internal::scalar_isfinite_op<Scalar>, const Derived>
    467     (isfinite)() const {
    468       return unaryExpr(internal::scalar_isfinite_op<Scalar>());
    469     }
    470 
    471     // Coefficient-wise ternary operators.
    472     template<typename ThenDerived, typename ElseDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    473     const TensorSelectOp<const Derived, const ThenDerived, const ElseDerived>
    474     select(const ThenDerived& thenTensor, const ElseDerived& elseTensor) const {
    475       return TensorSelectOp<const Derived, const ThenDerived, const ElseDerived>(derived(), thenTensor.derived(), elseTensor.derived());
    476     }
    477 
    478     // Contractions.
    479     typedef Eigen::IndexPair<Index> DimensionPair;
    480 
    481     template<typename OtherDerived, typename Dimensions> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    482     const TensorContractionOp<const Dimensions, const Derived, const OtherDerived>
    483     contract(const OtherDerived& other, const Dimensions& dims) const {
    484       return TensorContractionOp<const Dimensions, const Derived, const OtherDerived>(derived(), other.derived(), dims);
    485     }
    486 
    487     // Convolutions.
    488     template<typename KernelDerived, typename Dimensions> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    489     const TensorConvolutionOp<const Dimensions, const Derived, const KernelDerived>
    490     convolve(const KernelDerived& kernel, const Dimensions& dims) const {
    491       return TensorConvolutionOp<const Dimensions, const Derived, const KernelDerived>(derived(), kernel.derived(), dims);
    492     }
    493 
    494     // Fourier transforms
    495     template <int FFTDataType, int FFTDirection, typename FFT> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    496     const TensorFFTOp<const FFT, const Derived, FFTDataType, FFTDirection>
    497     fft(const FFT& fft) const {
    498       return TensorFFTOp<const FFT, const Derived, FFTDataType, FFTDirection>(derived(), fft);
    499     }
    500 
    501     // Scan.
    502     typedef TensorScanOp<internal::SumReducer<CoeffReturnType>, const Derived> TensorScanSumOp;
    503     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    504     const TensorScanSumOp
    505     cumsum(const Index& axis, bool exclusive = false) const {
    506       return TensorScanSumOp(derived(), axis, exclusive);
    507     }
    508 
    509     typedef TensorScanOp<internal::ProdReducer<CoeffReturnType>, const Derived> TensorScanProdOp;
    510     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    511     const TensorScanProdOp
    512     cumprod(const Index& axis, bool exclusive = false) const {
    513       return TensorScanProdOp(derived(), axis, exclusive);
    514     }
    515 
    516     template <typename Reducer>
    517     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    518     const TensorScanOp<Reducer, const Derived>
    519     scan(const Index& axis, const Reducer& reducer, bool exclusive = false) const {
    520       return TensorScanOp<Reducer, const Derived>(derived(), axis, exclusive, reducer);
    521     }
    522 
    523     // Reductions.
    524     template <typename Dims> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    525     const TensorReductionOp<internal::SumReducer<CoeffReturnType>, const Dims, const Derived>
    526     sum(const Dims& dims) const {
    527       return TensorReductionOp<internal::SumReducer<CoeffReturnType>, const Dims, const Derived>(derived(), dims, internal::SumReducer<CoeffReturnType>());
    528     }
    529 
    530     const TensorReductionOp<internal::SumReducer<CoeffReturnType>, const DimensionList<Index, NumDimensions>, const Derived>
    531     sum() const {
    532       DimensionList<Index, NumDimensions> in_dims;
    533       return TensorReductionOp<internal::SumReducer<CoeffReturnType>, const DimensionList<Index, NumDimensions>, const Derived>(derived(), in_dims, internal::SumReducer<CoeffReturnType>());
    534     }
    535 
    536     template <typename Dims> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    537     const TensorReductionOp<internal::MeanReducer<CoeffReturnType>, const Dims, const Derived>
    538     mean(const Dims& dims) const {
    539       return TensorReductionOp<internal::MeanReducer<CoeffReturnType>, const Dims, const Derived>(derived(), dims, internal::MeanReducer<CoeffReturnType>());
    540     }
    541 
    542     const TensorReductionOp<internal::MeanReducer<CoeffReturnType>, const DimensionList<Index, NumDimensions>, const Derived>
    543     mean() const {
    544       DimensionList<Index, NumDimensions> in_dims;
    545       return TensorReductionOp<internal::MeanReducer<CoeffReturnType>, const DimensionList<Index, NumDimensions>, const Derived>(derived(), in_dims, internal::MeanReducer<CoeffReturnType>());
    546     }
    547 
    548     template <typename Dims> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    549     const TensorReductionOp<internal::ProdReducer<CoeffReturnType>, const Dims, const Derived>
    550     prod(const Dims& dims) const {
    551       return TensorReductionOp<internal::ProdReducer<CoeffReturnType>, const Dims, const Derived>(derived(), dims, internal::ProdReducer<CoeffReturnType>());
    552     }
    553 
    554     const TensorReductionOp<internal::ProdReducer<CoeffReturnType>, const DimensionList<Index, NumDimensions>, const Derived>
    555     prod() const {
    556       DimensionList<Index, NumDimensions> in_dims;
    557       return TensorReductionOp<internal::ProdReducer<CoeffReturnType>, const DimensionList<Index, NumDimensions>, const Derived>(derived(), in_dims, internal::ProdReducer<CoeffReturnType>());
    558     }
    559 
    560     template <typename Dims> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    561     const TensorReductionOp<internal::MaxReducer<CoeffReturnType>, const Dims, const Derived>
    562     maximum(const Dims& dims) const {
    563       return TensorReductionOp<internal::MaxReducer<CoeffReturnType>, const Dims, const Derived>(derived(), dims, internal::MaxReducer<CoeffReturnType>());
    564     }
    565 
    566     const TensorReductionOp<internal::MaxReducer<CoeffReturnType>, const DimensionList<Index, NumDimensions>, const Derived>
    567     maximum() const {
    568       DimensionList<Index, NumDimensions> in_dims;
    569       return TensorReductionOp<internal::MaxReducer<CoeffReturnType>, const DimensionList<Index, NumDimensions>, const Derived>(derived(), in_dims, internal::MaxReducer<CoeffReturnType>());
    570     }
    571 
    572     template <typename Dims> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    573     const TensorReductionOp<internal::MinReducer<CoeffReturnType>, const Dims, const Derived>
    574     minimum(const Dims& dims) const {
    575       return TensorReductionOp<internal::MinReducer<CoeffReturnType>, const Dims, const Derived>(derived(), dims, internal::MinReducer<CoeffReturnType>());
    576     }
    577 
    578     const TensorReductionOp<internal::MinReducer<CoeffReturnType>, const DimensionList<Index, NumDimensions>, const Derived>
    579     minimum() const {
    580       DimensionList<Index, NumDimensions> in_dims;
    581       return TensorReductionOp<internal::MinReducer<CoeffReturnType>, const DimensionList<Index, NumDimensions>, const Derived>(derived(), in_dims, internal::MinReducer<CoeffReturnType>());
    582     }
    583 
    584     template <typename Dims> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    585     const TensorReductionOp<internal::AndReducer, const Dims, const TensorConversionOp<bool, const Derived> >
    586     all(const Dims& dims) const {
    587       return cast<bool>().reduce(dims, internal::AndReducer());
    588     }
    589 
    590     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    591     const TensorReductionOp<internal::AndReducer, const DimensionList<Index, NumDimensions>, const TensorConversionOp<bool, const Derived> >
    592     all() const {
    593       DimensionList<Index, NumDimensions> in_dims;
    594       return cast<bool>().reduce(in_dims, internal::AndReducer());
    595     }
    596 
    597     template <typename Dims> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    598     const TensorReductionOp<internal::OrReducer, const Dims, const TensorConversionOp<bool, const Derived> >
    599     any(const Dims& dims) const {
    600       return cast<bool>().reduce(dims, internal::OrReducer());
    601     }
    602 
    603     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    604     const TensorReductionOp<internal::OrReducer, const DimensionList<Index, NumDimensions>, const TensorConversionOp<bool, const Derived> >
    605     any() const {
    606       DimensionList<Index, NumDimensions> in_dims;
    607       return cast<bool>().reduce(in_dims, internal::OrReducer());
    608     }
    609 
    610    EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    611     const TensorTupleReducerOp<
    612       internal::ArgMaxTupleReducer<Tuple<Index, CoeffReturnType> >,
    613       const array<Index, NumDimensions>, const Derived>
    614     argmax() const {
    615       array<Index, NumDimensions> in_dims;
    616       for (int d = 0; d < NumDimensions; ++d) in_dims[d] = d;
    617       return TensorTupleReducerOp<
    618         internal::ArgMaxTupleReducer<Tuple<Index, CoeffReturnType> >,
    619         const array<Index, NumDimensions>,
    620         const Derived>(derived(), internal::ArgMaxTupleReducer<Tuple<Index, CoeffReturnType> >(), -1, in_dims);
    621     }
    622 
    623     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    624     const TensorTupleReducerOp<
    625       internal::ArgMinTupleReducer<Tuple<Index, CoeffReturnType> >,
    626       const array<Index, NumDimensions>, const Derived>
    627     argmin() const {
    628       array<Index, NumDimensions> in_dims;
    629       for (int d = 0; d < NumDimensions; ++d) in_dims[d] = d;
    630       return TensorTupleReducerOp<
    631         internal::ArgMinTupleReducer<Tuple<Index, CoeffReturnType> >,
    632         const array<Index, NumDimensions>,
    633         const Derived>(derived(), internal::ArgMinTupleReducer<Tuple<Index, CoeffReturnType> >(), -1, in_dims);
    634     }
    635 
    636     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    637     const TensorTupleReducerOp<
    638       internal::ArgMaxTupleReducer<Tuple<Index, CoeffReturnType> >,
    639       const array<Index, 1>, const Derived>
    640     argmax(const int return_dim) const {
    641       array<Index, 1> in_dims;
    642       in_dims[0] = return_dim;
    643       return TensorTupleReducerOp<
    644         internal::ArgMaxTupleReducer<Tuple<Index, CoeffReturnType> >,
    645         const array<Index, 1>,
    646         const Derived>(derived(), internal::ArgMaxTupleReducer<Tuple<Index, CoeffReturnType> >(), return_dim, in_dims);
    647     }
    648 
    649     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    650     const TensorTupleReducerOp<
    651       internal::ArgMinTupleReducer<Tuple<Index, CoeffReturnType> >,
    652       const array<Index, 1>, const Derived>
    653     argmin(const int return_dim) const {
    654       array<Index, 1> in_dims;
    655       in_dims[0] = return_dim;
    656       return TensorTupleReducerOp<
    657         internal::ArgMinTupleReducer<Tuple<Index, CoeffReturnType> >,
    658         const array<Index, 1>,
    659         const Derived>(derived(), internal::ArgMinTupleReducer<Tuple<Index, CoeffReturnType> >(), return_dim, in_dims);
    660     }
    661 
    662     template <typename Reducer, typename Dims> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    663     const TensorReductionOp<Reducer, const Dims, const Derived>
    664     reduce(const Dims& dims, const Reducer& reducer) const {
    665       return TensorReductionOp<Reducer, const Dims, const Derived>(derived(), dims, reducer);
    666     }
    667 
    668     template <typename Broadcast> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    669     const TensorBroadcastingOp<const Broadcast, const Derived>
    670     broadcast(const Broadcast& broadcast) const {
    671       return TensorBroadcastingOp<const Broadcast, const Derived>(derived(), broadcast);
    672     }
    673 
    674     template <typename Axis, typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    675     const TensorConcatenationOp<Axis, const Derived, const OtherDerived>
    676     concatenate(const OtherDerived& other, Axis axis) const {
    677       return TensorConcatenationOp<Axis, const Derived, const OtherDerived>(derived(), other.derived(), axis);
    678     }
    679 
    680     template <typename PatchDims> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    681     const TensorPatchOp<const PatchDims, const Derived>
    682     extract_patches(const PatchDims& patch_dims) const {
    683       return TensorPatchOp<const PatchDims, const Derived>(derived(), patch_dims);
    684     }
    685 
    686     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    687     const TensorImagePatchOp<Dynamic, Dynamic, const Derived>
    688     extract_image_patches(const Index patch_rows = 1, const Index patch_cols = 1,
    689                           const Index row_stride = 1, const Index col_stride = 1,
    690                           const Index in_row_stride = 1, const Index in_col_stride = 1,
    691                           const PaddingType padding_type = PADDING_SAME, const Scalar padding_value = Scalar(0)) const {
    692       return TensorImagePatchOp<Dynamic, Dynamic, const Derived>(derived(), patch_rows, patch_cols, row_stride, col_stride,
    693                                                                  in_row_stride, in_col_stride, 1, 1, padding_type, padding_value);
    694     }
    695 
    696     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    697     const TensorImagePatchOp<Dynamic, Dynamic, const Derived>
    698     extract_image_patches(const Index patch_rows, const Index patch_cols,
    699                           const Index row_stride, const Index col_stride,
    700                           const Index in_row_stride, const Index in_col_stride,
    701                           const Index row_inflate_stride, const Index col_inflate_stride,
    702                           const Index padding_top, const Index padding_bottom,
    703                           const Index padding_left,const Index padding_right,
    704                           const Scalar padding_value) const {
    705       return TensorImagePatchOp<Dynamic, Dynamic, const Derived>(derived(), patch_rows, patch_cols, row_stride, col_stride,
    706                                                                  in_row_stride, in_col_stride, row_inflate_stride, col_inflate_stride,
    707                                                                  padding_top, padding_bottom, padding_left, padding_right, padding_value);
    708     }
    709 
    710     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    711     const TensorVolumePatchOp<Dynamic, Dynamic, Dynamic, const Derived>
    712     extract_volume_patches(const Index patch_planes, const Index patch_rows, const Index patch_cols,
    713                            const Index plane_stride = 1, const Index row_stride = 1, const Index col_stride = 1,
    714                            const PaddingType padding_type = PADDING_SAME, const Scalar padding_value = Scalar(0)) const {
    715       return TensorVolumePatchOp<Dynamic, Dynamic, Dynamic, const Derived>(derived(), patch_planes, patch_rows, patch_cols, plane_stride, row_stride, col_stride, 1, 1, 1, 1, 1, 1, padding_type, padding_value);
    716     }
    717 
    718 
    719     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    720     const TensorVolumePatchOp<Dynamic, Dynamic, Dynamic, const Derived>
    721     extract_volume_patches(const Index patch_planes, const Index patch_rows, const Index patch_cols,
    722                            const Index plane_stride, const Index row_stride, const Index col_stride,
    723                            const Index plane_inflate_stride, const Index row_inflate_stride, const Index col_inflate_stride,
    724                            const Index padding_top_z, const Index padding_bottom_z,
    725                            const Index padding_top, const Index padding_bottom,
    726                            const Index padding_left, const Index padding_right, const Scalar padding_value = Scalar(0)) const {
    727       return TensorVolumePatchOp<Dynamic, Dynamic, Dynamic, const Derived>(derived(), patch_planes, patch_rows, patch_cols, plane_stride, row_stride, col_stride, 1, 1, 1, plane_inflate_stride, row_inflate_stride, col_inflate_stride, padding_top_z, padding_bottom_z, padding_top, padding_bottom, padding_left, padding_right, padding_value);
    728     }
    729 
    730     // Morphing operators.
    731     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    732     const TensorLayoutSwapOp<const Derived>
    733     swap_layout() const {
    734       return TensorLayoutSwapOp<const Derived>(derived());
    735     }
    736     template <typename NewDimensions> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    737     const TensorReshapingOp<const NewDimensions, const Derived>
    738     reshape(const NewDimensions& newDimensions) const {
    739       return TensorReshapingOp<const NewDimensions, const Derived>(derived(), newDimensions);
    740     }
    741     template <typename StartIndices, typename Sizes> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    742     const TensorSlicingOp<const StartIndices, const Sizes, const Derived>
    743     slice(const StartIndices& startIndices, const Sizes& sizes) const {
    744       return TensorSlicingOp<const StartIndices, const Sizes, const Derived>(derived(), startIndices, sizes);
    745     }
    746     template <typename StartIndices, typename StopIndices, typename Strides> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    747     const TensorStridingSlicingOp<const StartIndices, const StopIndices, const Strides, const Derived>
    748     stridedSlice(const StartIndices& startIndices, const StopIndices& stopIndices, const Strides& strides) const {
    749       return TensorStridingSlicingOp<const StartIndices, const StopIndices, const Strides,
    750                                 const Derived>(derived(), startIndices, stopIndices, strides);
    751     }
    752     template <Index DimId> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    753     const TensorChippingOp<DimId, const Derived>
    754     chip(const Index offset) const {
    755       return TensorChippingOp<DimId, const Derived>(derived(), offset, DimId);
    756     }
    757     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    758     const TensorChippingOp<Dynamic, const Derived>
    759     chip(const Index offset, const Index dim) const {
    760       return TensorChippingOp<Dynamic, const Derived>(derived(), offset, dim);
    761     }
    762     template <typename ReverseDimensions> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    763     const TensorReverseOp<const ReverseDimensions, const Derived>
    764     reverse(const ReverseDimensions& rev) const {
    765       return TensorReverseOp<const ReverseDimensions, const Derived>(derived(), rev);
    766     }
    767     template <typename PaddingDimensions> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    768     const TensorPaddingOp<const PaddingDimensions, const Derived>
    769     pad(const PaddingDimensions& padding) const {
    770       return TensorPaddingOp<const PaddingDimensions, const Derived>(derived(), padding, internal::scalar_cast_op<int, Scalar>()(0));
    771     }
    772     template <typename PaddingDimensions> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    773     const TensorPaddingOp<const PaddingDimensions, const Derived>
    774     pad(const PaddingDimensions& padding, const Scalar padding_value) const {
    775       return TensorPaddingOp<const PaddingDimensions, const Derived>(derived(), padding, padding_value);
    776     }
    777     template <typename Shuffle> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    778     const TensorShufflingOp<const Shuffle, const Derived>
    779     shuffle(const Shuffle& shuffle) const {
    780       return TensorShufflingOp<const Shuffle, const Derived>(derived(), shuffle);
    781     }
    782     template <typename Strides> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    783     const TensorStridingOp<const Strides, const Derived>
    784     stride(const Strides& strides) const {
    785       return TensorStridingOp<const Strides, const Derived>(derived(), strides);
    786     }
    787     template <typename Strides> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    788     const TensorInflationOp<const Strides, const Derived>
    789     inflate(const Strides& strides) const {
    790       return TensorInflationOp<const Strides, const Derived>(derived(), strides);
    791     }
    792 
    793     // Returns a tensor containing index/value tuples
    794     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    795     const TensorIndexTupleOp<const Derived>
    796     index_tuples() const {
    797       return TensorIndexTupleOp<const Derived>(derived());
    798     }
    799 
    800     // Support for custom unary and binary operations
    801     template <typename CustomUnaryFunc>
    802     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    803     const TensorCustomUnaryOp<const CustomUnaryFunc, const Derived> customOp(const CustomUnaryFunc& op) const {
    804       return TensorCustomUnaryOp<const CustomUnaryFunc, const Derived>(derived(), op);
    805     }
    806     template <typename OtherDerived, typename CustomBinaryFunc>
    807     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    808     const TensorCustomBinaryOp<const CustomBinaryFunc, const Derived, const OtherDerived> customOp(const OtherDerived& other, const CustomBinaryFunc& op) const {
    809       return TensorCustomBinaryOp<const CustomBinaryFunc, const Derived, const OtherDerived>(derived(), other, op);
    810     }
    811 
    812     // Force the evaluation of the expression.
    813     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    814     const TensorForcedEvalOp<const Derived> eval() const {
    815       return TensorForcedEvalOp<const Derived>(derived());
    816     }
    817 
    818   protected:
    819     template <typename Scalar, int NumIndices, int Options, typename IndexType> friend class Tensor;
    820     template <typename Scalar, typename Dimensions, int Option, typename IndexTypes> friend class TensorFixedSize;
    821     template <typename OtherDerived, int AccessLevel> friend class TensorBase;
    822     EIGEN_DEVICE_FUNC
    823     EIGEN_STRONG_INLINE const Derived& derived() const { return *static_cast<const Derived*>(this); }
    824 };
    825 
    826 template<typename Derived, int AccessLevel = internal::accessors_level<Derived>::value>
    827 class TensorBase : public TensorBase<Derived, ReadOnlyAccessors> {
    828  public:
    829     typedef internal::traits<Derived> DerivedTraits;
    830     typedef typename DerivedTraits::Scalar Scalar;
    831     typedef typename DerivedTraits::Index Index;
    832     typedef Scalar CoeffReturnType;
    833     static const int NumDimensions = DerivedTraits::NumDimensions;
    834 
    835     template <typename Scalar, int NumIndices, int Options, typename IndexType> friend class Tensor;
    836     template <typename Scalar, typename Dimensions, int Option, typename IndexTypes> friend class TensorFixedSize;
    837     template <typename OtherDerived, int OtherAccessLevel> friend class TensorBase;
    838 
    839     EIGEN_DEVICE_FUNC
    840     EIGEN_STRONG_INLINE Derived& setZero() {
    841       return setConstant(Scalar(0));
    842     }
    843     EIGEN_DEVICE_FUNC
    844     EIGEN_STRONG_INLINE Derived& setConstant(const Scalar& val) {
    845       return derived() = this->constant(val);
    846     }
    847     EIGEN_DEVICE_FUNC
    848     EIGEN_STRONG_INLINE Derived& setRandom() {
    849       return derived() = this->random();
    850     }
    851     template <typename RandomGenerator> EIGEN_DEVICE_FUNC
    852     EIGEN_STRONG_INLINE Derived& setRandom() {
    853       return derived() = this->template random<RandomGenerator>();
    854     }
    855 
    856 #if EIGEN_HAS_VARIADIC_TEMPLATES
    857     EIGEN_DEVICE_FUNC
    858     EIGEN_STRONG_INLINE Derived& setValues(
    859         const typename internal::Initializer<Derived, NumDimensions>::InitList& vals) {
    860       TensorEvaluator<Derived, DefaultDevice> eval(derived(), DefaultDevice());
    861       internal::initialize_tensor<Derived, NumDimensions>(eval, vals);
    862       return derived();
    863     }
    864 #endif  // EIGEN_HAS_VARIADIC_TEMPLATES
    865 
    866     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    867     Derived& operator+=(const OtherDerived& other) {
    868       return derived() = derived() + other.derived();
    869     }
    870     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    871     Derived& operator-=(const OtherDerived& other) {
    872       return derived() = derived() - other.derived();
    873     }
    874     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    875     Derived& operator*=(const OtherDerived& other) {
    876       return derived() = derived() * other.derived();
    877     }
    878     template<typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    879     Derived& operator/=(const OtherDerived& other) {
    880       return derived() = derived() / other.derived();
    881     }
    882 
    883     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    884     const TensorLayoutSwapOp<const Derived>
    885     swap_layout() const {
    886       return TensorLayoutSwapOp<const Derived>(derived());
    887     }
    888     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    889     TensorLayoutSwapOp<Derived>
    890     swap_layout() {
    891       return TensorLayoutSwapOp<Derived>(derived());
    892     }
    893 
    894     template <typename Axis, typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    895     const TensorConcatenationOp<const Axis, const Derived, const OtherDerived>
    896     concatenate(const OtherDerived& other, const Axis& axis) const {
    897       return TensorConcatenationOp<const Axis, const Derived, const OtherDerived>(derived(), other, axis);
    898     }
    899     template <typename Axis, typename OtherDerived> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    900     TensorConcatenationOp<const Axis, Derived, OtherDerived>
    901     concatenate(const OtherDerived& other, const Axis& axis) {
    902       return TensorConcatenationOp<const Axis, Derived, OtherDerived>(derived(), other, axis);
    903     }
    904 
    905     template <typename NewDimensions> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    906     const TensorReshapingOp<const NewDimensions, const Derived>
    907     reshape(const NewDimensions& newDimensions) const {
    908       return TensorReshapingOp<const NewDimensions, const Derived>(derived(), newDimensions);
    909     }
    910     template <typename NewDimensions> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    911     TensorReshapingOp<const NewDimensions, Derived>
    912     reshape(const NewDimensions& newDimensions) {
    913       return TensorReshapingOp<const NewDimensions, Derived>(derived(), newDimensions);
    914     }
    915 
    916     template <typename StartIndices, typename Sizes> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    917     const TensorSlicingOp<const StartIndices, const Sizes, const Derived>
    918     slice(const StartIndices& startIndices, const Sizes& sizes) const {
    919       return TensorSlicingOp<const StartIndices, const Sizes, const Derived>(derived(), startIndices, sizes);
    920     }
    921     template <typename StartIndices, typename Sizes> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    922     TensorSlicingOp<const StartIndices, const Sizes, Derived>
    923     slice(const StartIndices& startIndices, const Sizes& sizes) {
    924       return TensorSlicingOp<const StartIndices, const Sizes, Derived>(derived(), startIndices, sizes);
    925     }
    926 
    927     template <typename StartIndices, typename StopIndices, typename Strides> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    928     const TensorStridingSlicingOp<const StartIndices, const StopIndices, const Strides, const Derived>
    929     stridedSlice(const StartIndices& startIndices, const StopIndices& stopIndices, const Strides& strides) const {
    930       return TensorStridingSlicingOp<const StartIndices, const StopIndices, const Strides,
    931                                 const Derived>(derived(), startIndices, stopIndices, strides);
    932     }
    933     template <typename StartIndices, typename StopIndices, typename Strides> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    934     TensorStridingSlicingOp<const StartIndices, const StopIndices, const Strides, Derived>
    935     stridedSlice(const StartIndices& startIndices, const StopIndices& stopIndices, const Strides& strides) {
    936       return TensorStridingSlicingOp<const StartIndices, const StopIndices, const Strides,
    937                                 Derived>(derived(), startIndices, stopIndices, strides);
    938     }
    939 
    940     template <DenseIndex DimId> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    941     const TensorChippingOp<DimId, const Derived>
    942     chip(const Index offset) const {
    943       return TensorChippingOp<DimId, const Derived>(derived(), offset, DimId);
    944     }
    945     template <Index DimId> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    946     TensorChippingOp<DimId, Derived>
    947     chip(const Index offset) {
    948       return TensorChippingOp<DimId, Derived>(derived(), offset, DimId);
    949     }
    950 
    951     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    952     const TensorChippingOp<Dynamic, const Derived>
    953     chip(const Index offset, const Index dim) const {
    954       return TensorChippingOp<Dynamic, const Derived>(derived(), offset, dim);
    955     }
    956     EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    957     TensorChippingOp<Dynamic, Derived>
    958     chip(const Index offset, const Index dim) {
    959       return TensorChippingOp<Dynamic, Derived>(derived(), offset, dim);
    960     }
    961 
    962     template <typename ReverseDimensions> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    963     const TensorReverseOp<const ReverseDimensions, const Derived>
    964     reverse(const ReverseDimensions& rev) const {
    965       return TensorReverseOp<const ReverseDimensions, const Derived>(derived(), rev);
    966     }
    967     template <typename ReverseDimensions> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    968     TensorReverseOp<const ReverseDimensions, Derived>
    969     reverse(const ReverseDimensions& rev) {
    970       return TensorReverseOp<const ReverseDimensions, Derived>(derived(), rev);
    971     }
    972 
    973     template <typename Shuffle> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    974     const TensorShufflingOp<const Shuffle, const Derived>
    975     shuffle(const Shuffle& shuffle) const {
    976       return TensorShufflingOp<const Shuffle, const Derived>(derived(), shuffle);
    977     }
    978     template <typename Shuffle> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    979     TensorShufflingOp<const Shuffle, Derived>
    980     shuffle(const Shuffle& shuffle) {
    981       return TensorShufflingOp<const Shuffle, Derived>(derived(), shuffle);
    982     }
    983 
    984     template <typename Strides> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    985     const TensorStridingOp<const Strides, const Derived>
    986     stride(const Strides& strides) const {
    987       return TensorStridingOp<const Strides, const Derived>(derived(), strides);
    988     }
    989     template <typename Strides> EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE
    990     TensorStridingOp<const Strides, Derived>
    991     stride(const Strides& strides) {
    992       return TensorStridingOp<const Strides, Derived>(derived(), strides);
    993     }
    994 
    995     // Select the device on which to evaluate the expression.
    996     template <typename DeviceType>
    997     TensorDevice<Derived, DeviceType> device(const DeviceType& device) {
    998       return TensorDevice<Derived, DeviceType>(device, derived());
    999     }
   1000 
   1001  protected:
   1002     EIGEN_DEVICE_FUNC
   1003     EIGEN_STRONG_INLINE Derived& derived() { return *static_cast<Derived*>(this); }
   1004     EIGEN_DEVICE_FUNC
   1005     EIGEN_STRONG_INLINE const Derived& derived() const { return *static_cast<const Derived*>(this); }
   1006 };
   1007 
   1008 } // end namespace Eigen
   1009 
   1010 #endif // EIGEN_CXX11_TENSOR_TENSOR_BASE_H
   1011