1 // This file is part of Eigen, a lightweight C++ template library 2 // for linear algebra. 3 // 4 // Copyright (C) 2008 Gael Guennebaud <[email protected]> 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_VISITOR_H 11 #define EIGEN_VISITOR_H 12 13 namespace Eigen { 14 15 namespace internal { 16 17 template<typename Visitor, typename Derived, int UnrollCount> 18 struct visitor_impl 19 { 20 enum { 21 col = (UnrollCount-1) / Derived::RowsAtCompileTime, 22 row = (UnrollCount-1) % Derived::RowsAtCompileTime 23 }; 24 25 EIGEN_DEVICE_FUNC runvisitor_impl26 static inline void run(const Derived &mat, Visitor& visitor) 27 { 28 visitor_impl<Visitor, Derived, UnrollCount-1>::run(mat, visitor); 29 visitor(mat.coeff(row, col), row, col); 30 } 31 }; 32 33 template<typename Visitor, typename Derived> 34 struct visitor_impl<Visitor, Derived, 1> 35 { 36 EIGEN_DEVICE_FUNC 37 static inline void run(const Derived &mat, Visitor& visitor) 38 { 39 return visitor.init(mat.coeff(0, 0), 0, 0); 40 } 41 }; 42 43 // This specialization enables visitors on empty matrices at compile-time 44 template<typename Visitor, typename Derived> 45 struct visitor_impl<Visitor, Derived, 0> { 46 EIGEN_DEVICE_FUNC 47 static inline void run(const Derived &/*mat*/, Visitor& /*visitor*/) 48 {} 49 }; 50 51 template<typename Visitor, typename Derived> 52 struct visitor_impl<Visitor, Derived, Dynamic> 53 { 54 EIGEN_DEVICE_FUNC 55 static inline void run(const Derived& mat, Visitor& visitor) 56 { 57 visitor.init(mat.coeff(0,0), 0, 0); 58 for(Index i = 1; i < mat.rows(); ++i) 59 visitor(mat.coeff(i, 0), i, 0); 60 for(Index j = 1; j < mat.cols(); ++j) 61 for(Index i = 0; i < mat.rows(); ++i) 62 visitor(mat.coeff(i, j), i, j); 63 } 64 }; 65 66 // evaluator adaptor 67 template<typename XprType> 68 class visitor_evaluator 69 { 70 public: 71 EIGEN_DEVICE_FUNC 72 explicit visitor_evaluator(const XprType &xpr) : m_evaluator(xpr), m_xpr(xpr) {} 73 74 typedef typename XprType::Scalar Scalar; 75 typedef typename XprType::CoeffReturnType CoeffReturnType; 76 77 enum { 78 RowsAtCompileTime = XprType::RowsAtCompileTime, 79 CoeffReadCost = internal::evaluator<XprType>::CoeffReadCost 80 }; 81 82 EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index rows() const EIGEN_NOEXCEPT { return m_xpr.rows(); } 83 EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index cols() const EIGEN_NOEXCEPT { return m_xpr.cols(); } 84 EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR Index size() const EIGEN_NOEXCEPT { return m_xpr.size(); } 85 86 EIGEN_DEVICE_FUNC CoeffReturnType coeff(Index row, Index col) const 87 { return m_evaluator.coeff(row, col); } 88 89 protected: 90 internal::evaluator<XprType> m_evaluator; 91 const XprType &m_xpr; 92 }; 93 } // end namespace internal 94 95 /** Applies the visitor \a visitor to the whole coefficients of the matrix or vector. 96 * 97 * The template parameter \a Visitor is the type of the visitor and provides the following interface: 98 * \code 99 * struct MyVisitor { 100 * // called for the first coefficient 101 * void init(const Scalar& value, Index i, Index j); 102 * // called for all other coefficients 103 * void operator() (const Scalar& value, Index i, Index j); 104 * }; 105 * \endcode 106 * 107 * \note compared to one or two \em for \em loops, visitors offer automatic 108 * unrolling for small fixed size matrix. 109 * 110 * \note if the matrix is empty, then the visitor is left unchanged. 111 * 112 * \sa minCoeff(Index*,Index*), maxCoeff(Index*,Index*), DenseBase::redux() 113 */ 114 template<typename Derived> 115 template<typename Visitor> 116 EIGEN_DEVICE_FUNC 117 void DenseBase<Derived>::visit(Visitor& visitor) const 118 { 119 if(size()==0) 120 return; 121 122 typedef typename internal::visitor_evaluator<Derived> ThisEvaluator; 123 ThisEvaluator thisEval(derived()); 124 125 enum { 126 unroll = SizeAtCompileTime != Dynamic 127 && SizeAtCompileTime * int(ThisEvaluator::CoeffReadCost) + (SizeAtCompileTime-1) * int(internal::functor_traits<Visitor>::Cost) <= EIGEN_UNROLLING_LIMIT 128 }; 129 return internal::visitor_impl<Visitor, ThisEvaluator, unroll ? int(SizeAtCompileTime) : Dynamic>::run(thisEval, visitor); 130 } 131 132 namespace internal { 133 134 /** \internal 135 * \brief Base class to implement min and max visitors 136 */ 137 template <typename Derived> 138 struct coeff_visitor 139 { 140 // default initialization to avoid countless invalid maybe-uninitialized warnings by gcc 141 EIGEN_DEVICE_FUNC 142 coeff_visitor() : row(-1), col(-1), res(0) {} 143 typedef typename Derived::Scalar Scalar; 144 Index row, col; 145 Scalar res; 146 EIGEN_DEVICE_FUNC 147 inline void init(const Scalar& value, Index i, Index j) 148 { 149 res = value; 150 row = i; 151 col = j; 152 } 153 }; 154 155 /** \internal 156 * \brief Visitor computing the min coefficient with its value and coordinates 157 * 158 * \sa DenseBase::minCoeff(Index*, Index*) 159 */ 160 template <typename Derived, int NaNPropagation> 161 struct min_coeff_visitor : coeff_visitor<Derived> 162 { 163 typedef typename Derived::Scalar Scalar; 164 EIGEN_DEVICE_FUNC 165 void operator() (const Scalar& value, Index i, Index j) 166 { 167 if(value < this->res) 168 { 169 this->res = value; 170 this->row = i; 171 this->col = j; 172 } 173 } 174 }; 175 176 template <typename Derived> 177 struct min_coeff_visitor<Derived, PropagateNumbers> : coeff_visitor<Derived> 178 { 179 typedef typename Derived::Scalar Scalar; 180 EIGEN_DEVICE_FUNC 181 void operator() (const Scalar& value, Index i, Index j) 182 { 183 if((numext::isnan)(this->res) || (!(numext::isnan)(value) && value < this->res)) 184 { 185 this->res = value; 186 this->row = i; 187 this->col = j; 188 } 189 } 190 }; 191 192 template <typename Derived> 193 struct min_coeff_visitor<Derived, PropagateNaN> : coeff_visitor<Derived> 194 { 195 typedef typename Derived::Scalar Scalar; 196 EIGEN_DEVICE_FUNC 197 void operator() (const Scalar& value, Index i, Index j) 198 { 199 if((numext::isnan)(value) || value < this->res) 200 { 201 this->res = value; 202 this->row = i; 203 this->col = j; 204 } 205 } 206 }; 207 208 template<typename Scalar, int NaNPropagation> 209 struct functor_traits<min_coeff_visitor<Scalar, NaNPropagation> > { 210 enum { 211 Cost = NumTraits<Scalar>::AddCost 212 }; 213 }; 214 215 /** \internal 216 * \brief Visitor computing the max coefficient with its value and coordinates 217 * 218 * \sa DenseBase::maxCoeff(Index*, Index*) 219 */ 220 template <typename Derived, int NaNPropagation> 221 struct max_coeff_visitor : coeff_visitor<Derived> 222 { 223 typedef typename Derived::Scalar Scalar; 224 EIGEN_DEVICE_FUNC 225 void operator() (const Scalar& value, Index i, Index j) 226 { 227 if(value > this->res) 228 { 229 this->res = value; 230 this->row = i; 231 this->col = j; 232 } 233 } 234 }; 235 236 template <typename Derived> 237 struct max_coeff_visitor<Derived, PropagateNumbers> : coeff_visitor<Derived> 238 { 239 typedef typename Derived::Scalar Scalar; 240 EIGEN_DEVICE_FUNC 241 void operator() (const Scalar& value, Index i, Index j) 242 { 243 if((numext::isnan)(this->res) || (!(numext::isnan)(value) && value > this->res)) 244 { 245 this->res = value; 246 this->row = i; 247 this->col = j; 248 } 249 } 250 }; 251 252 template <typename Derived> 253 struct max_coeff_visitor<Derived, PropagateNaN> : coeff_visitor<Derived> 254 { 255 typedef typename Derived::Scalar Scalar; 256 EIGEN_DEVICE_FUNC 257 void operator() (const Scalar& value, Index i, Index j) 258 { 259 if((numext::isnan)(value) || value > this->res) 260 { 261 this->res = value; 262 this->row = i; 263 this->col = j; 264 } 265 } 266 }; 267 268 template<typename Scalar, int NaNPropagation> 269 struct functor_traits<max_coeff_visitor<Scalar, NaNPropagation> > { 270 enum { 271 Cost = NumTraits<Scalar>::AddCost 272 }; 273 }; 274 275 } // end namespace internal 276 277 /** \fn DenseBase<Derived>::minCoeff(IndexType* rowId, IndexType* colId) const 278 * \returns the minimum of all coefficients of *this and puts in *row and *col its location. 279 * 280 * In case \c *this contains NaN, NaNPropagation determines the behavior: 281 * NaNPropagation == PropagateFast : undefined 282 * NaNPropagation == PropagateNaN : result is NaN 283 * NaNPropagation == PropagateNumbers : result is maximum of elements that are not NaN 284 * \warning the matrix must be not empty, otherwise an assertion is triggered. 285 * 286 * \sa DenseBase::minCoeff(Index*), DenseBase::maxCoeff(Index*,Index*), DenseBase::visit(), DenseBase::minCoeff() 287 */ 288 template<typename Derived> 289 template<int NaNPropagation, typename IndexType> 290 EIGEN_DEVICE_FUNC 291 typename internal::traits<Derived>::Scalar 292 DenseBase<Derived>::minCoeff(IndexType* rowId, IndexType* colId) const 293 { 294 eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix"); 295 296 internal::min_coeff_visitor<Derived, NaNPropagation> minVisitor; 297 this->visit(minVisitor); 298 *rowId = minVisitor.row; 299 if (colId) *colId = minVisitor.col; 300 return minVisitor.res; 301 } 302 303 /** \returns the minimum of all coefficients of *this and puts in *index its location. 304 * 305 * In case \c *this contains NaN, NaNPropagation determines the behavior: 306 * NaNPropagation == PropagateFast : undefined 307 * NaNPropagation == PropagateNaN : result is NaN 308 * NaNPropagation == PropagateNumbers : result is maximum of elements that are not NaN 309 * \warning the matrix must be not empty, otherwise an assertion is triggered. 310 * 311 * \sa DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::maxCoeff(IndexType*,IndexType*), DenseBase::visit(), DenseBase::minCoeff() 312 */ 313 template<typename Derived> 314 template<int NaNPropagation, typename IndexType> 315 EIGEN_DEVICE_FUNC 316 typename internal::traits<Derived>::Scalar 317 DenseBase<Derived>::minCoeff(IndexType* index) const 318 { 319 eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix"); 320 321 EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) 322 internal::min_coeff_visitor<Derived, NaNPropagation> minVisitor; 323 this->visit(minVisitor); 324 *index = IndexType((RowsAtCompileTime==1) ? minVisitor.col : minVisitor.row); 325 return minVisitor.res; 326 } 327 328 /** \fn DenseBase<Derived>::maxCoeff(IndexType* rowId, IndexType* colId) const 329 * \returns the maximum of all coefficients of *this and puts in *row and *col its location. 330 * 331 * In case \c *this contains NaN, NaNPropagation determines the behavior: 332 * NaNPropagation == PropagateFast : undefined 333 * NaNPropagation == PropagateNaN : result is NaN 334 * NaNPropagation == PropagateNumbers : result is maximum of elements that are not NaN 335 * \warning the matrix must be not empty, otherwise an assertion is triggered. 336 * 337 * \sa DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::visit(), DenseBase::maxCoeff() 338 */ 339 template<typename Derived> 340 template<int NaNPropagation, typename IndexType> 341 EIGEN_DEVICE_FUNC 342 typename internal::traits<Derived>::Scalar 343 DenseBase<Derived>::maxCoeff(IndexType* rowPtr, IndexType* colPtr) const 344 { 345 eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix"); 346 347 internal::max_coeff_visitor<Derived, NaNPropagation> maxVisitor; 348 this->visit(maxVisitor); 349 *rowPtr = maxVisitor.row; 350 if (colPtr) *colPtr = maxVisitor.col; 351 return maxVisitor.res; 352 } 353 354 /** \returns the maximum of all coefficients of *this and puts in *index its location. 355 * 356 * In case \c *this contains NaN, NaNPropagation determines the behavior: 357 * NaNPropagation == PropagateFast : undefined 358 * NaNPropagation == PropagateNaN : result is NaN 359 * NaNPropagation == PropagateNumbers : result is maximum of elements that are not NaN 360 * \warning the matrix must be not empty, otherwise an assertion is triggered. 361 * 362 * \sa DenseBase::maxCoeff(IndexType*,IndexType*), DenseBase::minCoeff(IndexType*,IndexType*), DenseBase::visitor(), DenseBase::maxCoeff() 363 */ 364 template<typename Derived> 365 template<int NaNPropagation, typename IndexType> 366 EIGEN_DEVICE_FUNC 367 typename internal::traits<Derived>::Scalar 368 DenseBase<Derived>::maxCoeff(IndexType* index) const 369 { 370 eigen_assert(this->rows()>0 && this->cols()>0 && "you are using an empty matrix"); 371 372 EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) 373 internal::max_coeff_visitor<Derived, NaNPropagation> maxVisitor; 374 this->visit(maxVisitor); 375 *index = (RowsAtCompileTime==1) ? maxVisitor.col : maxVisitor.row; 376 return maxVisitor.res; 377 } 378 379 } // end namespace Eigen 380 381 #endif // EIGEN_VISITOR_H 382