Transpose.h 14.4 KB
Newer Older
LM's avatar
LM committed
1 2 3 4
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
5
// Copyright (C) 2009-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
LM's avatar
LM committed
6
//
Don Gagne's avatar
Don Gagne committed
7 8 9
// 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/.
LM's avatar
LM committed
10 11 12 13

#ifndef EIGEN_TRANSPOSE_H
#define EIGEN_TRANSPOSE_H

Don Gagne's avatar
Don Gagne committed
14 15
namespace Eigen { 

LM's avatar
LM committed
16 17
namespace internal {
template<typename MatrixType>
18
struct traits<Transpose<MatrixType> > : public traits<MatrixType>
LM's avatar
LM committed
19
{
20
  typedef typename ref_selector<MatrixType>::type MatrixTypeNested;
LM's avatar
LM committed
21 22 23 24 25 26 27
  typedef typename remove_reference<MatrixTypeNested>::type MatrixTypeNestedPlain;
  enum {
    RowsAtCompileTime = MatrixType::ColsAtCompileTime,
    ColsAtCompileTime = MatrixType::RowsAtCompileTime,
    MaxRowsAtCompileTime = MatrixType::MaxColsAtCompileTime,
    MaxColsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
    FlagsLvalueBit = is_lvalue<MatrixType>::value ? LvalueBit : 0,
28
    Flags0 = traits<MatrixTypeNestedPlain>::Flags & ~(LvalueBit | NestByRefBit),
LM's avatar
LM committed
29 30 31 32 33 34 35 36 37 38
    Flags1 = Flags0 | FlagsLvalueBit,
    Flags = Flags1 ^ RowMajorBit,
    InnerStrideAtCompileTime = inner_stride_at_compile_time<MatrixType>::ret,
    OuterStrideAtCompileTime = outer_stride_at_compile_time<MatrixType>::ret
  };
};
}

template<typename MatrixType, typename StorageKind> class TransposeImpl;

39 40 41 42 43 44 45 46 47 48 49 50 51
/** \class Transpose
  * \ingroup Core_Module
  *
  * \brief Expression of the transpose of a matrix
  *
  * \tparam MatrixType the type of the object of which we are taking the transpose
  *
  * This class represents an expression of the transpose of a matrix.
  * It is the return type of MatrixBase::transpose() and MatrixBase::adjoint()
  * and most of the time this is the only way it is used.
  *
  * \sa MatrixBase::transpose(), MatrixBase::adjoint()
  */
LM's avatar
LM committed
52 53 54 55 56
template<typename MatrixType> class Transpose
  : public TransposeImpl<MatrixType,typename internal::traits<MatrixType>::StorageKind>
{
  public:

57 58
    typedef typename internal::ref_selector<MatrixType>::non_const_type MatrixTypeNested;

LM's avatar
LM committed
59 60
    typedef typename TransposeImpl<MatrixType,typename internal::traits<MatrixType>::StorageKind>::Base Base;
    EIGEN_GENERIC_PUBLIC_INTERFACE(Transpose)
61
    typedef typename internal::remove_all<MatrixType>::type NestedExpression;
LM's avatar
LM committed
62

63 64
    EIGEN_DEVICE_FUNC
    explicit inline Transpose(MatrixType& matrix) : m_matrix(matrix) {}
LM's avatar
LM committed
65 66 67

    EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Transpose)

68 69
    EIGEN_DEVICE_FUNC inline Index rows() const { return m_matrix.cols(); }
    EIGEN_DEVICE_FUNC inline Index cols() const { return m_matrix.rows(); }
LM's avatar
LM committed
70 71

    /** \returns the nested expression */
72 73
    EIGEN_DEVICE_FUNC
    const typename internal::remove_all<MatrixTypeNested>::type&
LM's avatar
LM committed
74 75 76
    nestedExpression() const { return m_matrix; }

    /** \returns the nested expression */
77 78 79 80 81 82 83 84
    EIGEN_DEVICE_FUNC
    typename internal::remove_reference<MatrixTypeNested>::type&
    nestedExpression() { return m_matrix; }

    /** \internal */
    void resize(Index nrows, Index ncols) {
      m_matrix.resize(ncols,nrows);
    }
LM's avatar
LM committed
85 86

  protected:
87
    typename internal::ref_selector<MatrixType>::non_const_type m_matrix;
LM's avatar
LM committed
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
};

namespace internal {

template<typename MatrixType, bool HasDirectAccess = has_direct_access<MatrixType>::ret>
struct TransposeImpl_base
{
  typedef typename dense_xpr_base<Transpose<MatrixType> >::type type;
};

template<typename MatrixType>
struct TransposeImpl_base<MatrixType, false>
{
  typedef typename dense_xpr_base<Transpose<MatrixType> >::type type;
};

} // end namespace internal

106 107 108 109 110 111 112 113 114
// Generic API dispatcher
template<typename XprType, typename StorageKind>
class TransposeImpl
  : public internal::generic_xpr_base<Transpose<XprType> >::type
{
public:
  typedef typename internal::generic_xpr_base<Transpose<XprType> >::type Base;
};

LM's avatar
LM committed
115 116 117 118 119 120
template<typename MatrixType> class TransposeImpl<MatrixType,Dense>
  : public internal::TransposeImpl_base<MatrixType>::type
{
  public:

    typedef typename internal::TransposeImpl_base<MatrixType>::type Base;
121
    using Base::coeffRef;
LM's avatar
LM committed
122
    EIGEN_DENSE_PUBLIC_INTERFACE(Transpose<MatrixType>)
Don Gagne's avatar
Don Gagne committed
123
    EIGEN_INHERIT_ASSIGNMENT_OPERATORS(TransposeImpl)
LM's avatar
LM committed
124

125 126
    EIGEN_DEVICE_FUNC inline Index innerStride() const { return derived().nestedExpression().innerStride(); }
    EIGEN_DEVICE_FUNC inline Index outerStride() const { return derived().nestedExpression().outerStride(); }
LM's avatar
LM committed
127 128 129 130 131 132 133

    typedef typename internal::conditional<
                       internal::is_lvalue<MatrixType>::value,
                       Scalar,
                       const Scalar
                     >::type ScalarWithConstIfNotLvalue;

134 135
    EIGEN_DEVICE_FUNC inline ScalarWithConstIfNotLvalue* data() { return derived().nestedExpression().data(); }
    EIGEN_DEVICE_FUNC inline const Scalar* data() const { return derived().nestedExpression().data(); }
LM's avatar
LM committed
136

137 138
    // FIXME: shall we keep the const version of coeffRef?
    EIGEN_DEVICE_FUNC
Don Gagne's avatar
Don Gagne committed
139
    inline const Scalar& coeffRef(Index rowId, Index colId) const
LM's avatar
LM committed
140
    {
Don Gagne's avatar
Don Gagne committed
141
      return derived().nestedExpression().coeffRef(colId, rowId);
LM's avatar
LM committed
142 143
    }

144
    EIGEN_DEVICE_FUNC
LM's avatar
LM committed
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
    inline const Scalar& coeffRef(Index index) const
    {
      return derived().nestedExpression().coeffRef(index);
    }
};

/** \returns an expression of the transpose of *this.
  *
  * Example: \include MatrixBase_transpose.cpp
  * Output: \verbinclude MatrixBase_transpose.out
  *
  * \warning If you want to replace a matrix by its own transpose, do \b NOT do this:
  * \code
  * m = m.transpose(); // bug!!! caused by aliasing effect
  * \endcode
  * Instead, use the transposeInPlace() method:
  * \code
  * m.transposeInPlace();
  * \endcode
  * which gives Eigen good opportunities for optimization, or alternatively you can also do:
  * \code
  * m = m.transpose().eval();
  * \endcode
  *
  * \sa transposeInPlace(), adjoint() */
template<typename Derived>
inline Transpose<Derived>
DenseBase<Derived>::transpose()
{
174
  return TransposeReturnType(derived());
LM's avatar
LM committed
175 176 177 178 179 180 181 182
}

/** This is the const version of transpose().
  *
  * Make sure you read the warning for transpose() !
  *
  * \sa transposeInPlace(), adjoint() */
template<typename Derived>
Don Gagne's avatar
Don Gagne committed
183
inline typename DenseBase<Derived>::ConstTransposeReturnType
LM's avatar
LM committed
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
DenseBase<Derived>::transpose() const
{
  return ConstTransposeReturnType(derived());
}

/** \returns an expression of the adjoint (i.e. conjugate transpose) of *this.
  *
  * Example: \include MatrixBase_adjoint.cpp
  * Output: \verbinclude MatrixBase_adjoint.out
  *
  * \warning If you want to replace a matrix by its own adjoint, do \b NOT do this:
  * \code
  * m = m.adjoint(); // bug!!! caused by aliasing effect
  * \endcode
  * Instead, use the adjointInPlace() method:
  * \code
  * m.adjointInPlace();
  * \endcode
  * which gives Eigen good opportunities for optimization, or alternatively you can also do:
  * \code
  * m = m.adjoint().eval();
  * \endcode
  *
  * \sa adjointInPlace(), transpose(), conjugate(), class Transpose, class internal::scalar_conjugate_op */
template<typename Derived>
inline const typename MatrixBase<Derived>::AdjointReturnType
MatrixBase<Derived>::adjoint() const
{
212
  return AdjointReturnType(this->transpose());
LM's avatar
LM committed
213 214 215 216 217 218 219 220 221
}

/***************************************************************************
* "in place" transpose implementation
***************************************************************************/

namespace internal {

template<typename MatrixType,
222 223 224 225
  bool IsSquare = (MatrixType::RowsAtCompileTime == MatrixType::ColsAtCompileTime) && MatrixType::RowsAtCompileTime!=Dynamic,
  bool MatchPacketSize =
        (int(MatrixType::RowsAtCompileTime) == int(internal::packet_traits<typename MatrixType::Scalar>::size))
    &&  (internal::evaluator<MatrixType>::Flags&PacketAccessBit) >
LM's avatar
LM committed
226 227 228
struct inplace_transpose_selector;

template<typename MatrixType>
229
struct inplace_transpose_selector<MatrixType,true,false> { // square matrix
LM's avatar
LM committed
230
  static void run(MatrixType& m) {
Don Gagne's avatar
Don Gagne committed
231
    m.matrix().template triangularView<StrictlyUpper>().swap(m.matrix().transpose());
LM's avatar
LM committed
232 233 234
  }
};

235
// TODO: vectorized path is currently limited to LargestPacketSize x LargestPacketSize cases only.
LM's avatar
LM committed
236
template<typename MatrixType>
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
struct inplace_transpose_selector<MatrixType,true,true> { // PacketSize x PacketSize
  static void run(MatrixType& m) {
    typedef typename MatrixType::Scalar Scalar;
    typedef typename internal::packet_traits<typename MatrixType::Scalar>::type Packet;
    const Index PacketSize = internal::packet_traits<Scalar>::size;
    const Index Alignment = internal::evaluator<MatrixType>::Alignment;
    PacketBlock<Packet> A;
    for (Index i=0; i<PacketSize; ++i)
      A.packet[i] = m.template packetByOuterInner<Alignment>(i,0);
    internal::ptranspose(A);
    for (Index i=0; i<PacketSize; ++i)
      m.template writePacket<Alignment>(m.rowIndexByOuterInner(i,0), m.colIndexByOuterInner(i,0), A.packet[i]);
  }
};

template<typename MatrixType,bool MatchPacketSize>
struct inplace_transpose_selector<MatrixType,false,MatchPacketSize> { // non square matrix
LM's avatar
LM committed
254 255
  static void run(MatrixType& m) {
    if (m.rows()==m.cols())
Don Gagne's avatar
Don Gagne committed
256
      m.matrix().template triangularView<StrictlyUpper>().swap(m.matrix().transpose());
LM's avatar
LM committed
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
    else
      m = m.transpose().eval();
  }
};

} // end namespace internal

/** This is the "in place" version of transpose(): it replaces \c *this by its own transpose.
  * Thus, doing
  * \code
  * m.transposeInPlace();
  * \endcode
  * has the same effect on m as doing
  * \code
  * m = m.transpose().eval();
  * \endcode
  * and is faster and also safer because in the latter line of code, forgetting the eval() results
Don Gagne's avatar
Don Gagne committed
274
  * in a bug caused by \ref TopicAliasing "aliasing".
LM's avatar
LM committed
275 276 277 278
  *
  * Notice however that this method is only useful if you want to replace a matrix by its own transpose.
  * If you just need the transpose of a matrix, use transpose().
  *
279 280
  * \note if the matrix is not square, then \c *this must be a resizable matrix. 
  * This excludes (non-square) fixed-size matrices, block-expressions and maps.
LM's avatar
LM committed
281 282 283 284 285
  *
  * \sa transpose(), adjoint(), adjointInPlace() */
template<typename Derived>
inline void DenseBase<Derived>::transposeInPlace()
{
Don Gagne's avatar
Don Gagne committed
286 287
  eigen_assert((rows() == cols() || (RowsAtCompileTime == Dynamic && ColsAtCompileTime == Dynamic))
               && "transposeInPlace() called on a non-square non-resizable matrix");
LM's avatar
LM committed
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
  internal::inplace_transpose_selector<Derived>::run(derived());
}

/***************************************************************************
* "in place" adjoint implementation
***************************************************************************/

/** This is the "in place" version of adjoint(): it replaces \c *this by its own transpose.
  * Thus, doing
  * \code
  * m.adjointInPlace();
  * \endcode
  * has the same effect on m as doing
  * \code
  * m = m.adjoint().eval();
  * \endcode
  * and is faster and also safer because in the latter line of code, forgetting the eval() results
  * in a bug caused by aliasing.
  *
  * Notice however that this method is only useful if you want to replace a matrix by its own adjoint.
  * If you just need the adjoint of a matrix, use adjoint().
  *
  * \note if the matrix is not square, then \c *this must be a resizable matrix.
311
  * This excludes (non-square) fixed-size matrices, block-expressions and maps.
LM's avatar
LM committed
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
  *
  * \sa transpose(), adjoint(), transposeInPlace() */
template<typename Derived>
inline void MatrixBase<Derived>::adjointInPlace()
{
  derived() = adjoint().eval();
}

#ifndef EIGEN_NO_DEBUG

// The following is to detect aliasing problems in most common cases.

namespace internal {

template<bool DestIsTransposed, typename OtherDerived>
struct check_transpose_aliasing_compile_time_selector
{
Don Gagne's avatar
Don Gagne committed
329
  enum { ret = bool(blas_traits<OtherDerived>::IsTransposed) != DestIsTransposed };
LM's avatar
LM committed
330 331 332 333 334
};

template<bool DestIsTransposed, typename BinOp, typename DerivedA, typename DerivedB>
struct check_transpose_aliasing_compile_time_selector<DestIsTransposed,CwiseBinaryOp<BinOp,DerivedA,DerivedB> >
{
Don Gagne's avatar
Don Gagne committed
335 336
  enum { ret =    bool(blas_traits<DerivedA>::IsTransposed) != DestIsTransposed
               || bool(blas_traits<DerivedB>::IsTransposed) != DestIsTransposed
LM's avatar
LM committed
337 338 339 340 341 342 343 344
  };
};

template<typename Scalar, bool DestIsTransposed, typename OtherDerived>
struct check_transpose_aliasing_run_time_selector
{
  static bool run(const Scalar* dest, const OtherDerived& src)
  {
Don Gagne's avatar
Don Gagne committed
345
    return (bool(blas_traits<OtherDerived>::IsTransposed) != DestIsTransposed) && (dest!=0 && dest==(const Scalar*)extract_data(src));
LM's avatar
LM committed
346 347 348 349 350 351 352 353
  }
};

template<typename Scalar, bool DestIsTransposed, typename BinOp, typename DerivedA, typename DerivedB>
struct check_transpose_aliasing_run_time_selector<Scalar,DestIsTransposed,CwiseBinaryOp<BinOp,DerivedA,DerivedB> >
{
  static bool run(const Scalar* dest, const CwiseBinaryOp<BinOp,DerivedA,DerivedB>& src)
  {
Don Gagne's avatar
Don Gagne committed
354 355
    return ((blas_traits<DerivedA>::IsTransposed != DestIsTransposed) && (dest!=0 && dest==(const Scalar*)extract_data(src.lhs())))
        || ((blas_traits<DerivedB>::IsTransposed != DestIsTransposed) && (dest!=0 && dest==(const Scalar*)extract_data(src.rhs())));
LM's avatar
LM committed
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
  }
};

// the following selector, checkTransposeAliasing_impl, based on MightHaveTransposeAliasing,
// is because when the condition controlling the assert is known at compile time, ICC emits a warning.
// This is actually a good warning: in expressions that don't have any transposing, the condition is
// known at compile time to be false, and using that, we can avoid generating the code of the assert again
// and again for all these expressions that don't need it.

template<typename Derived, typename OtherDerived,
         bool MightHaveTransposeAliasing
                 = check_transpose_aliasing_compile_time_selector
                     <blas_traits<Derived>::IsTransposed,OtherDerived>::ret
        >
struct checkTransposeAliasing_impl
{
    static void run(const Derived& dst, const OtherDerived& other)
    {
        eigen_assert((!check_transpose_aliasing_run_time_selector
                      <typename Derived::Scalar,blas_traits<Derived>::IsTransposed,OtherDerived>
                      ::run(extract_data(dst), other))
Don Gagne's avatar
Don Gagne committed
377
          && "aliasing detected during transposition, use transposeInPlace() "
LM's avatar
LM committed
378 379 380 381 382 383 384 385 386 387 388 389 390
             "or evaluate the rhs into a temporary using .eval()");

    }
};

template<typename Derived, typename OtherDerived>
struct checkTransposeAliasing_impl<Derived, OtherDerived, false>
{
    static void run(const Derived&, const OtherDerived&)
    {
    }
};

391 392
template<typename Dst, typename Src>
void check_for_aliasing(const Dst &dst, const Src &src)
LM's avatar
LM committed
393
{
394
  internal::checkTransposeAliasing_impl<Dst, Src>::run(dst, src);
LM's avatar
LM committed
395
}
396 397 398 399

} // end namespace internal

#endif // EIGEN_NO_DEBUG
LM's avatar
LM committed
400

Don Gagne's avatar
Don Gagne committed
401 402
} // end namespace Eigen

LM's avatar
LM committed
403
#endif // EIGEN_TRANSPOSE_H