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

#ifndef EIGEN_DOT_H
#define EIGEN_DOT_H

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

LM's avatar
LM committed
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
namespace internal {

// helper function for dot(). The problem is that if we put that in the body of dot(), then upon calling dot
// with mismatched types, the compiler emits errors about failing to instantiate cwiseProduct BEFORE
// looking at the static assertions. Thus this is a trick to get better compile errors.
template<typename T, typename U,
// the NeedToTranspose condition here is taken straight from Assign.h
         bool NeedToTranspose = T::IsVectorAtCompileTime
                && U::IsVectorAtCompileTime
                && ((int(T::RowsAtCompileTime) == 1 && int(U::ColsAtCompileTime) == 1)
                      |  // FIXME | instead of || to please GCC 4.4.0 stupid warning "suggest parentheses around &&".
                         // revert to || as soon as not needed anymore.
                    (int(T::ColsAtCompileTime) == 1 && int(U::RowsAtCompileTime) == 1))
>
struct dot_nocheck
{
31 32 33 34 35
  typedef scalar_conj_product_op<typename traits<T>::Scalar,typename traits<U>::Scalar> conj_prod;
  typedef typename conj_prod::result_type ResScalar;
  EIGEN_DEVICE_FUNC
  EIGEN_STRONG_INLINE
  static ResScalar run(const MatrixBase<T>& a, const MatrixBase<U>& b)
LM's avatar
LM committed
36
  {
37
    return a.template binaryExpr<conj_prod>(b).sum();
LM's avatar
LM committed
38 39 40 41 42 43
  }
};

template<typename T, typename U>
struct dot_nocheck<T, U, true>
{
44 45 46 47 48
  typedef scalar_conj_product_op<typename traits<T>::Scalar,typename traits<U>::Scalar> conj_prod;
  typedef typename conj_prod::result_type ResScalar;
  EIGEN_DEVICE_FUNC
  EIGEN_STRONG_INLINE
  static ResScalar run(const MatrixBase<T>& a, const MatrixBase<U>& b)
LM's avatar
LM committed
49
  {
50
    return a.transpose().template binaryExpr<conj_prod>(b).sum();
LM's avatar
LM committed
51 52 53 54 55
  }
};

} // end namespace internal

56 57
/** \fn MatrixBase::dot
  * \returns the dot product of *this with other.
LM's avatar
LM committed
58 59 60 61 62 63 64 65 66 67 68
  *
  * \only_for_vectors
  *
  * \note If the scalar type is complex numbers, then this function returns the hermitian
  * (sesquilinear) dot product, conjugate-linear in the first variable and linear in the
  * second variable.
  *
  * \sa squaredNorm(), norm()
  */
template<typename Derived>
template<typename OtherDerived>
69 70 71
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE
typename ScalarBinaryOpTraits<typename internal::traits<Derived>::Scalar,typename internal::traits<OtherDerived>::Scalar>::ReturnType
LM's avatar
LM committed
72 73 74 75 76
MatrixBase<Derived>::dot(const MatrixBase<OtherDerived>& other) const
{
  EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived)
  EIGEN_STATIC_ASSERT_VECTOR_ONLY(OtherDerived)
  EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived)
77
#if !(defined(EIGEN_NO_STATIC_ASSERT) && defined(EIGEN_NO_DEBUG))
LM's avatar
LM committed
78 79
  typedef internal::scalar_conj_product_op<Scalar,typename OtherDerived::Scalar> func;
  EIGEN_CHECK_BINARY_COMPATIBILIY(func,Scalar,typename OtherDerived::Scalar);
80 81
#endif
  
LM's avatar
LM committed
82 83 84 85 86 87 88
  eigen_assert(size() == other.size());

  return internal::dot_nocheck<Derived,OtherDerived>::run(*this, other);
}

//---------- implementation of L2 norm and related functions ----------

Don Gagne's avatar
Don Gagne committed
89 90 91
/** \returns, for vectors, the squared \em l2 norm of \c *this, and for matrices the Frobenius norm.
  * In both cases, it consists in the sum of the square of all the matrix entries.
  * For vectors, this is also equals to the dot product of \c *this with itself.
LM's avatar
LM committed
92
  *
93
  * \sa dot(), norm(), lpNorm()
LM's avatar
LM committed
94 95 96 97
  */
template<typename Derived>
EIGEN_STRONG_INLINE typename NumTraits<typename internal::traits<Derived>::Scalar>::Real MatrixBase<Derived>::squaredNorm() const
{
Don Gagne's avatar
Don Gagne committed
98
  return numext::real((*this).cwiseAbs2().sum());
LM's avatar
LM committed
99 100
}

Don Gagne's avatar
Don Gagne committed
101 102 103
/** \returns, for vectors, the \em l2 norm of \c *this, and for matrices the Frobenius norm.
  * In both cases, it consists in the square root of the sum of the square of all the matrix entries.
  * For vectors, this is also equals to the square root of the dot product of \c *this with itself.
LM's avatar
LM committed
104
  *
105
  * \sa lpNorm(), dot(), squaredNorm()
LM's avatar
LM committed
106 107
  */
template<typename Derived>
108
EIGEN_STRONG_INLINE typename NumTraits<typename internal::traits<Derived>::Scalar>::Real MatrixBase<Derived>::norm() const
LM's avatar
LM committed
109
{
110
  return numext::sqrt(squaredNorm());
LM's avatar
LM committed
111 112
}

113 114 115 116
/** \returns an expression of the quotient of \c *this by its own norm.
  *
  * \warning If the input vector is too small (i.e., this->norm()==0),
  *          then this function returns a copy of the input.
LM's avatar
LM committed
117 118 119 120 121 122
  *
  * \only_for_vectors
  *
  * \sa norm(), normalize()
  */
template<typename Derived>
123
EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::PlainObject
LM's avatar
LM committed
124 125
MatrixBase<Derived>::normalized() const
{
126
  typedef typename internal::nested_eval<Derived,2>::type _Nested;
LM's avatar
LM committed
127
  _Nested n(derived());
128 129 130 131 132 133
  RealScalar z = n.squaredNorm();
  // NOTE: after extensive benchmarking, this conditional does not impact performance, at least on recent x86 CPU
  if(z>RealScalar(0))
    return n / numext::sqrt(z);
  else
    return n;
LM's avatar
LM committed
134 135 136 137 138 139
}

/** Normalizes the vector, i.e. divides it by its own norm.
  *
  * \only_for_vectors
  *
140 141
  * \warning If the input vector is too small (i.e., this->norm()==0), then \c *this is left unchanged.
  *
LM's avatar
LM committed
142 143 144
  * \sa norm(), normalized()
  */
template<typename Derived>
145
EIGEN_STRONG_INLINE void MatrixBase<Derived>::normalize()
LM's avatar
LM committed
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 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
  RealScalar z = squaredNorm();
  // NOTE: after extensive benchmarking, this conditional does not impact performance, at least on recent x86 CPU
  if(z>RealScalar(0))
    derived() /= numext::sqrt(z);
}

/** \returns an expression of the quotient of \c *this by its own norm while avoiding underflow and overflow.
  *
  * \only_for_vectors
  *
  * This method is analogue to the normalized() method, but it reduces the risk of
  * underflow and overflow when computing the norm.
  *
  * \warning If the input vector is too small (i.e., this->norm()==0),
  *          then this function returns a copy of the input.
  *
  * \sa stableNorm(), stableNormalize(), normalized()
  */
template<typename Derived>
EIGEN_STRONG_INLINE const typename MatrixBase<Derived>::PlainObject
MatrixBase<Derived>::stableNormalized() const
{
  typedef typename internal::nested_eval<Derived,3>::type _Nested;
  _Nested n(derived());
  RealScalar w = n.cwiseAbs().maxCoeff();
  RealScalar z = (n/w).squaredNorm();
  if(z>RealScalar(0))
    return n / (numext::sqrt(z)*w);
  else
    return n;
}

/** Normalizes the vector while avoid underflow and overflow
  *
  * \only_for_vectors
  *
  * This method is analogue to the normalize() method, but it reduces the risk of
  * underflow and overflow when computing the norm.
  *
  * \warning If the input vector is too small (i.e., this->norm()==0), then \c *this is left unchanged.
  *
  * \sa stableNorm(), stableNormalized(), normalize()
  */
template<typename Derived>
EIGEN_STRONG_INLINE void MatrixBase<Derived>::stableNormalize()
{
  RealScalar w = cwiseAbs().maxCoeff();
  RealScalar z = (derived()/w).squaredNorm();
  if(z>RealScalar(0))
    derived() /= numext::sqrt(z)*w;
LM's avatar
LM committed
197 198 199 200 201 202 203 204 205 206
}

//---------- implementation of other norms ----------

namespace internal {

template<typename Derived, int p>
struct lpNorm_selector
{
  typedef typename NumTraits<typename traits<Derived>::Scalar>::Real RealScalar;
207
  EIGEN_DEVICE_FUNC
Don Gagne's avatar
Don Gagne committed
208
  static inline RealScalar run(const MatrixBase<Derived>& m)
LM's avatar
LM committed
209
  {
210
    EIGEN_USING_STD_MATH(pow)
LM's avatar
LM committed
211 212 213 214 215 216 217
    return pow(m.cwiseAbs().array().pow(p).sum(), RealScalar(1)/p);
  }
};

template<typename Derived>
struct lpNorm_selector<Derived, 1>
{
218
  EIGEN_DEVICE_FUNC
Don Gagne's avatar
Don Gagne committed
219
  static inline typename NumTraits<typename traits<Derived>::Scalar>::Real run(const MatrixBase<Derived>& m)
LM's avatar
LM committed
220 221 222 223 224 225 226 227
  {
    return m.cwiseAbs().sum();
  }
};

template<typename Derived>
struct lpNorm_selector<Derived, 2>
{
228
  EIGEN_DEVICE_FUNC
Don Gagne's avatar
Don Gagne committed
229
  static inline typename NumTraits<typename traits<Derived>::Scalar>::Real run(const MatrixBase<Derived>& m)
LM's avatar
LM committed
230 231 232 233 234 235 236 237
  {
    return m.norm();
  }
};

template<typename Derived>
struct lpNorm_selector<Derived, Infinity>
{
238 239 240
  typedef typename NumTraits<typename traits<Derived>::Scalar>::Real RealScalar;
  EIGEN_DEVICE_FUNC
  static inline RealScalar run(const MatrixBase<Derived>& m)
LM's avatar
LM committed
241
  {
242 243
    if(Derived::SizeAtCompileTime==0 || (Derived::SizeAtCompileTime==Dynamic && m.size()==0))
      return RealScalar(0);
LM's avatar
LM committed
244 245 246 247 248 249
    return m.cwiseAbs().maxCoeff();
  }
};

} // end namespace internal

250 251 252 253 254 255 256
/** \returns the \b coefficient-wise \f$ \ell^p \f$ norm of \c *this, that is, returns the p-th root of the sum of the p-th powers of the absolute values
  *          of the coefficients of \c *this. If \a p is the special value \a Eigen::Infinity, this function returns the \f$ \ell^\infty \f$
  *          norm, that is the maximum of the absolute values of the coefficients of \c *this.
  *
  * In all cases, if \c *this is empty, then the value 0 is returned.
  *
  * \note For matrices, this function does not compute the <a href="https://en.wikipedia.org/wiki/Operator_norm">operator-norm</a>. That is, if \c *this is a matrix, then its coefficients are interpreted as a 1D vector. Nonetheless, you can easily compute the 1-norm and \f$\infty\f$-norm matrix operator norms using \link TutorialReductionsVisitorsBroadcastingReductionsNorm partial reductions \endlink.
LM's avatar
LM committed
257 258 259 260 261
  *
  * \sa norm()
  */
template<typename Derived>
template<int p>
262
#ifndef EIGEN_PARSED_BY_DOXYGEN
LM's avatar
LM committed
263
inline typename NumTraits<typename internal::traits<Derived>::Scalar>::Real
264 265 266
#else
MatrixBase<Derived>::RealScalar
#endif
LM's avatar
LM committed
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
MatrixBase<Derived>::lpNorm() const
{
  return internal::lpNorm_selector<Derived, p>::run(*this);
}

//---------- implementation of isOrthogonal / isUnitary ----------

/** \returns true if *this is approximately orthogonal to \a other,
  *          within the precision given by \a prec.
  *
  * Example: \include MatrixBase_isOrthogonal.cpp
  * Output: \verbinclude MatrixBase_isOrthogonal.out
  */
template<typename Derived>
template<typename OtherDerived>
bool MatrixBase<Derived>::isOrthogonal
Don Gagne's avatar
Don Gagne committed
283
(const MatrixBase<OtherDerived>& other, const RealScalar& prec) const
LM's avatar
LM committed
284
{
285 286
  typename internal::nested_eval<Derived,2>::type nested(derived());
  typename internal::nested_eval<OtherDerived,2>::type otherNested(other.derived());
Don Gagne's avatar
Don Gagne committed
287
  return numext::abs2(nested.dot(otherNested)) <= prec * prec * nested.squaredNorm() * otherNested.squaredNorm();
LM's avatar
LM committed
288 289 290 291 292 293 294 295 296 297 298 299 300 301
}

/** \returns true if *this is approximately an unitary matrix,
  *          within the precision given by \a prec. In the case where the \a Scalar
  *          type is real numbers, a unitary matrix is an orthogonal matrix, whence the name.
  *
  * \note This can be used to check whether a family of vectors forms an orthonormal basis.
  *       Indeed, \c m.isUnitary() returns true if and only if the columns (equivalently, the rows) of m form an
  *       orthonormal basis.
  *
  * Example: \include MatrixBase_isUnitary.cpp
  * Output: \verbinclude MatrixBase_isUnitary.out
  */
template<typename Derived>
Don Gagne's avatar
Don Gagne committed
302
bool MatrixBase<Derived>::isUnitary(const RealScalar& prec) const
LM's avatar
LM committed
303
{
304
  typename internal::nested_eval<Derived,1>::type self(derived());
LM's avatar
LM committed
305 306
  for(Index i = 0; i < cols(); ++i)
  {
307
    if(!internal::isApprox(self.col(i).squaredNorm(), static_cast<RealScalar>(1), prec))
LM's avatar
LM committed
308 309
      return false;
    for(Index j = 0; j < i; ++j)
310
      if(!internal::isMuchSmallerThan(self.col(i).dot(self.col(j)), static_cast<Scalar>(1), prec))
LM's avatar
LM committed
311 312 313 314 315
        return false;
  }
  return true;
}

Don Gagne's avatar
Don Gagne committed
316 317
} // end namespace Eigen

LM's avatar
LM committed
318
#endif // EIGEN_DOT_H