mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-06-04 18:54:00 +08:00
* Added a generic *redux* mini framework allowing custom redux operations
as well as partial redux (vertical or horizontal redux). Includes shortcuts for: sum, minCoeff and maxCoeff. There is no shortcut for the partial redux. * Added a generic *visitor* mini framework. A visitor is a custom object sequentially applied on each coefficient with knowledge of its value and coordinates. It is currentlly used to implement minCoeff(int*,int*) and maxCoeff(int*,int*). findBiggestCoeff is now a shortcut for "this->cwiseAbs().maxCoeff(i,j)" * Added coeff-wise min and max. * fixed an issue with ei_pow(int,int) and gcc < 4.3 or ICC
This commit is contained in:
parent
29184ad27d
commit
612350e3f8
@ -31,12 +31,14 @@ namespace Eigen {
|
|||||||
#include "src/Core/DiagonalMatrix.h"
|
#include "src/Core/DiagonalMatrix.h"
|
||||||
#include "src/Core/DiagonalCoeffs.h"
|
#include "src/Core/DiagonalCoeffs.h"
|
||||||
#include "src/Core/Identity.h"
|
#include "src/Core/Identity.h"
|
||||||
#include "src/Core/SumOfCoeffs.h"
|
#include "src/Core/Redux.h"
|
||||||
|
#include "src/Core/Visitor.h"
|
||||||
#include "src/Core/Fuzzy.h"
|
#include "src/Core/Fuzzy.h"
|
||||||
#include "src/Core/Map.h"
|
#include "src/Core/Map.h"
|
||||||
#include "src/Core/IO.h"
|
#include "src/Core/IO.h"
|
||||||
#include "src/Core/Swap.h"
|
#include "src/Core/Swap.h"
|
||||||
#include "src/Core/CommaInitializer.h"
|
#include "src/Core/CommaInitializer.h"
|
||||||
|
#include "src/Core/AssociativeFunctors.h"
|
||||||
#include "src/Core/EvalOMP.h"
|
#include "src/Core/EvalOMP.h"
|
||||||
|
|
||||||
} // namespace Eigen
|
} // namespace Eigen
|
||||||
|
64
Eigen/src/Core/AssociativeFunctors.h
Normal file
64
Eigen/src/Core/AssociativeFunctors.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// This file is part of Eigen, a lightweight C++ template library
|
||||||
|
// for linear algebra. Eigen itself is part of the KDE project.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||||
|
//
|
||||||
|
// Eigen is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 3 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Alternatively, you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of
|
||||||
|
// the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License and a copy of the GNU General Public License along with
|
||||||
|
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef EIGEN_ASSOCIATIVE_FUNCTORS_H
|
||||||
|
#define EIGEN_ASSOCIATIVE_FUNCTORS_H
|
||||||
|
|
||||||
|
/** \internal
|
||||||
|
* \brief Template functor to compute the sum of two scalars
|
||||||
|
*
|
||||||
|
* \sa class CwiseBinaryOp, MatrixBase::operator+, class PartialRedux, MatrixBase::sum()
|
||||||
|
*/
|
||||||
|
struct ei_scalar_sum_op EIGEN_EMPTY_STRUCT {
|
||||||
|
template<typename Scalar> Scalar operator() (const Scalar& a, const Scalar& b) const { return a + b; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \internal
|
||||||
|
* \brief Template functor to compute the product of two scalars
|
||||||
|
*
|
||||||
|
* \sa class CwiseBinaryOp, MatrixBase::cwiseProduct(), class PartialRedux, MatrixBase::redux()
|
||||||
|
*/
|
||||||
|
struct ei_scalar_product_op EIGEN_EMPTY_STRUCT {
|
||||||
|
template<typename Scalar> Scalar operator() (const Scalar& a, const Scalar& b) const { return a * b; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \internal
|
||||||
|
* \brief Template functor to compute the min of two scalars
|
||||||
|
*
|
||||||
|
* \sa class CwiseBinaryOp, MatrixBase::cwiseMin, class PartialRedux, MatrixBase::minCoeff()
|
||||||
|
*/
|
||||||
|
struct ei_scalar_min_op EIGEN_EMPTY_STRUCT {
|
||||||
|
template<typename Scalar> Scalar operator() (const Scalar& a, const Scalar& b) const { return ei_min(a, b); }
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \internal
|
||||||
|
* \brief Template functor to compute the max of two scalars
|
||||||
|
*
|
||||||
|
* \sa class CwiseBinaryOp, MatrixBase::cwiseMax, class PartialRedux, MatrixBase::maxCoeff()
|
||||||
|
*/
|
||||||
|
struct ei_scalar_max_op EIGEN_EMPTY_STRUCT {
|
||||||
|
template<typename Scalar> Scalar operator() (const Scalar& a, const Scalar& b) const { return ei_max(a, b); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // EIGEN_ASSOCIATIVE_FUNCTORS_H
|
@ -93,15 +93,6 @@ class CwiseBinaryOp : ei_no_assignment_operator,
|
|||||||
const BinaryOp m_functor;
|
const BinaryOp m_functor;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \internal
|
|
||||||
* \brief Template functor to compute the sum of two scalars
|
|
||||||
*
|
|
||||||
* \sa class CwiseBinaryOp, MatrixBase::operator+
|
|
||||||
*/
|
|
||||||
struct ei_scalar_sum_op EIGEN_EMPTY_STRUCT {
|
|
||||||
template<typename Scalar> Scalar operator() (const Scalar& a, const Scalar& b) const { return a + b; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \internal
|
/** \internal
|
||||||
* \brief Template functor to compute the difference of two scalars
|
* \brief Template functor to compute the difference of two scalars
|
||||||
*
|
*
|
||||||
@ -111,15 +102,6 @@ struct ei_scalar_difference_op EIGEN_EMPTY_STRUCT {
|
|||||||
template<typename Scalar> Scalar operator() (const Scalar& a, const Scalar& b) const { return a - b; }
|
template<typename Scalar> Scalar operator() (const Scalar& a, const Scalar& b) const { return a - b; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \internal
|
|
||||||
* \brief Template functor to compute the product of two scalars
|
|
||||||
*
|
|
||||||
* \sa class CwiseBinaryOp, MatrixBase::cwiseProduct()
|
|
||||||
*/
|
|
||||||
struct ei_scalar_product_op EIGEN_EMPTY_STRUCT {
|
|
||||||
template<typename Scalar> Scalar operator() (const Scalar& a, const Scalar& b) const { return a * b; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \internal
|
/** \internal
|
||||||
* \brief Template functor to compute the quotient of two scalars
|
* \brief Template functor to compute the quotient of two scalars
|
||||||
*
|
*
|
||||||
@ -203,6 +185,30 @@ MatrixBase<Derived>::cwiseQuotient(const MatrixBase<OtherDerived> &other) const
|
|||||||
return CwiseBinaryOp<ei_scalar_quotient_op, Derived, OtherDerived>(derived(), other.derived());
|
return CwiseBinaryOp<ei_scalar_quotient_op, Derived, OtherDerived>(derived(), other.derived());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \returns an expression of the coefficient-wise min of *this and \a other
|
||||||
|
*
|
||||||
|
* \sa class CwiseBinaryOp
|
||||||
|
*/
|
||||||
|
template<typename Derived>
|
||||||
|
template<typename OtherDerived>
|
||||||
|
const CwiseBinaryOp<ei_scalar_min_op, Derived, OtherDerived>
|
||||||
|
MatrixBase<Derived>::cwiseMin(const MatrixBase<OtherDerived> &other) const
|
||||||
|
{
|
||||||
|
return CwiseBinaryOp<ei_scalar_min_op, Derived, OtherDerived>(derived(), other.derived());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \returns an expression of the coefficient-wise max of *this and \a other
|
||||||
|
*
|
||||||
|
* \sa class CwiseBinaryOp
|
||||||
|
*/
|
||||||
|
template<typename Derived>
|
||||||
|
template<typename OtherDerived>
|
||||||
|
const CwiseBinaryOp<ei_scalar_max_op, Derived, OtherDerived>
|
||||||
|
MatrixBase<Derived>::cwiseMax(const MatrixBase<OtherDerived> &other) const
|
||||||
|
{
|
||||||
|
return CwiseBinaryOp<ei_scalar_max_op, Derived, OtherDerived>(derived(), other.derived());
|
||||||
|
}
|
||||||
|
|
||||||
/** \returns an expression of a custom coefficient-wise operator \a func of *this and \a other
|
/** \returns an expression of a custom coefficient-wise operator \a func of *this and \a other
|
||||||
*
|
*
|
||||||
* The template parameter \a CustomBinaryOp is the type of the functor
|
* The template parameter \a CustomBinaryOp is the type of the functor
|
||||||
|
@ -45,6 +45,7 @@ template<typename MatrixType> class Identity;
|
|||||||
template<typename MatrixType> class Map;
|
template<typename MatrixType> class Map;
|
||||||
template<typename Derived> class Eval;
|
template<typename Derived> class Eval;
|
||||||
template<typename Derived> class EvalOMP;
|
template<typename Derived> class EvalOMP;
|
||||||
|
template<int Direction, typename UnaryOp, typename MatrixType> class PartialRedux;
|
||||||
|
|
||||||
struct ei_scalar_sum_op;
|
struct ei_scalar_sum_op;
|
||||||
struct ei_scalar_difference_op;
|
struct ei_scalar_difference_op;
|
||||||
@ -62,6 +63,8 @@ struct ei_scalar_sin_op;
|
|||||||
template<typename Scalar> struct ei_scalar_pow_op;
|
template<typename Scalar> struct ei_scalar_pow_op;
|
||||||
template<typename NewType> struct ei_scalar_cast_op;
|
template<typename NewType> struct ei_scalar_cast_op;
|
||||||
template<typename Scalar> struct ei_scalar_multiple_op;
|
template<typename Scalar> struct ei_scalar_multiple_op;
|
||||||
|
struct ei_scalar_min_op;
|
||||||
|
struct ei_scalar_max_op;
|
||||||
|
|
||||||
template<typename T> struct ei_xpr_copy
|
template<typename T> struct ei_xpr_copy
|
||||||
{
|
{
|
||||||
|
@ -5,12 +5,12 @@
|
|||||||
//
|
//
|
||||||
// Eigen is free software; you can redistribute it and/or
|
// Eigen is free software; you can redistribute it and/or
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
// License as published by the Free Software Foundation; either
|
// License as published by the Free Software Foundation; either
|
||||||
// version 3 of the License, or (at your option) any later version.
|
// version 3 of the License, or (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Alternatively, you can redistribute it and/or
|
// Alternatively, you can redistribute it and/or
|
||||||
// modify it under the terms of the GNU General Public License as
|
// modify it under the terms of the GNU General Public License as
|
||||||
// published by the Free Software Foundation; either version 2 of
|
// published by the Free Software Foundation; either version 2 of
|
||||||
// the License, or (at your option) any later version.
|
// the License, or (at your option) any later version.
|
||||||
//
|
//
|
||||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
@ -18,7 +18,7 @@
|
|||||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
// License and a copy of the GNU General Public License along with
|
// License and a copy of the GNU General Public License along with
|
||||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
@ -40,7 +40,11 @@ inline int ei_exp(int) { assert(false); return 0; }
|
|||||||
inline int ei_log(int) { assert(false); return 0; }
|
inline int ei_log(int) { assert(false); return 0; }
|
||||||
inline int ei_sin(int) { assert(false); return 0; }
|
inline int ei_sin(int) { assert(false); return 0; }
|
||||||
inline int ei_cos(int) { assert(false); return 0; }
|
inline int ei_cos(int) { assert(false); return 0; }
|
||||||
|
#if (defined __ICC) || (defined __GNUC__ && (__GNUC__<4 || __GNUC_MINOR__<3))
|
||||||
|
inline int ei_pow(int x, int y) { return int(std::pow(double(x), y)); }
|
||||||
|
#else
|
||||||
inline int ei_pow(int x, int y) { return std::pow(x, y); }
|
inline int ei_pow(int x, int y) { return std::pow(x, y); }
|
||||||
|
#endif
|
||||||
|
|
||||||
template<> inline int ei_random(int a, int b)
|
template<> inline int ei_random(int a, int b)
|
||||||
{
|
{
|
||||||
|
@ -81,7 +81,7 @@ template<typename Derived> class MatrixBase
|
|||||||
/**< This is equal to the number of coefficients, i.e. the number of
|
/**< This is equal to the number of coefficients, i.e. the number of
|
||||||
* rows times the number of columns, or to \a Dynamic if this is not
|
* rows times the number of columns, or to \a Dynamic if this is not
|
||||||
* known at compile-time. \sa RowsAtCompileTime, ColsAtCompileTime */
|
* known at compile-time. \sa RowsAtCompileTime, ColsAtCompileTime */
|
||||||
|
|
||||||
MaxRowsAtCompileTime = ei_traits<Derived>::MaxRowsAtCompileTime,
|
MaxRowsAtCompileTime = ei_traits<Derived>::MaxRowsAtCompileTime,
|
||||||
/**< This value is equal to the maximum possible number of rows that this expression
|
/**< This value is equal to the maximum possible number of rows that this expression
|
||||||
* might have. If this expression might have an arbitrarily high number of rows,
|
* might have. If this expression might have an arbitrarily high number of rows,
|
||||||
@ -245,13 +245,6 @@ template<typename Derived> class MatrixBase
|
|||||||
Derived& operator*=(const MatrixBase<OtherDerived>& other);
|
Derived& operator*=(const MatrixBase<OtherDerived>& other);
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
/** \name Sums of coefficients
|
|
||||||
*/
|
|
||||||
//@{
|
|
||||||
Scalar sum() const;
|
|
||||||
Scalar trace() const;
|
|
||||||
//@}
|
|
||||||
|
|
||||||
/** \name Dot product and related notions
|
/** \name Dot product and related notions
|
||||||
* including vector norm, adjoint, transpose ...
|
* including vector norm, adjoint, transpose ...
|
||||||
*/
|
*/
|
||||||
@ -350,20 +343,7 @@ template<typename Derived> class MatrixBase
|
|||||||
* which has the biggest absolute value.
|
* which has the biggest absolute value.
|
||||||
*/
|
*/
|
||||||
void findBiggestCoeff(int *row, int *col) const
|
void findBiggestCoeff(int *row, int *col) const
|
||||||
{
|
{ (*this).cwiseAbs().maxCoeff(row, col); }
|
||||||
RealScalar biggest = 0;
|
|
||||||
for(int j = 0; j < cols(); j++)
|
|
||||||
for(int i = 0; i < rows(); i++)
|
|
||||||
{
|
|
||||||
RealScalar x = ei_abs(coeff(i,j));
|
|
||||||
if(x > biggest)
|
|
||||||
{
|
|
||||||
biggest = x;
|
|
||||||
*row = i;
|
|
||||||
*col = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
/// \name Special functions
|
/// \name Special functions
|
||||||
@ -396,6 +376,14 @@ template<typename Derived> class MatrixBase
|
|||||||
const CwiseBinaryOp<ei_scalar_quotient_op, Derived, OtherDerived>
|
const CwiseBinaryOp<ei_scalar_quotient_op, Derived, OtherDerived>
|
||||||
cwiseQuotient(const MatrixBase<OtherDerived> &other) const;
|
cwiseQuotient(const MatrixBase<OtherDerived> &other) const;
|
||||||
|
|
||||||
|
template<typename OtherDerived>
|
||||||
|
const CwiseBinaryOp<ei_scalar_min_op, Derived, OtherDerived>
|
||||||
|
cwiseMin(const MatrixBase<OtherDerived> &other) const;
|
||||||
|
|
||||||
|
template<typename OtherDerived>
|
||||||
|
const CwiseBinaryOp<ei_scalar_max_op, Derived, OtherDerived>
|
||||||
|
cwiseMax(const MatrixBase<OtherDerived> &other) const;
|
||||||
|
|
||||||
const CwiseUnaryOp<ei_scalar_abs_op, Derived> cwiseAbs() const;
|
const CwiseUnaryOp<ei_scalar_abs_op, Derived> cwiseAbs() const;
|
||||||
const CwiseUnaryOp<ei_scalar_abs2_op, Derived> cwiseAbs2() const;
|
const CwiseUnaryOp<ei_scalar_abs2_op, Derived> cwiseAbs2() const;
|
||||||
const CwiseUnaryOp<ei_scalar_sqrt_op, Derived> cwiseSqrt() const;
|
const CwiseUnaryOp<ei_scalar_sqrt_op, Derived> cwiseSqrt() const;
|
||||||
@ -414,6 +402,33 @@ template<typename Derived> class MatrixBase
|
|||||||
cwise(const MatrixBase<OtherDerived> &other, const CustomBinaryOp& func = CustomBinaryOp()) const;
|
cwise(const MatrixBase<OtherDerived> &other, const CustomBinaryOp& func = CustomBinaryOp()) const;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
/// \name Redux and visitor
|
||||||
|
//@{
|
||||||
|
Scalar sum() const;
|
||||||
|
Scalar trace() const;
|
||||||
|
|
||||||
|
typename ei_traits<Derived>::Scalar minCoeff() const;
|
||||||
|
typename ei_traits<Derived>::Scalar maxCoeff() const;
|
||||||
|
|
||||||
|
typename ei_traits<Derived>::Scalar minCoeff(int* row, int* col = 0) const;
|
||||||
|
typename ei_traits<Derived>::Scalar maxCoeff(int* row, int* col = 0) const;
|
||||||
|
|
||||||
|
template<typename BinaryOp>
|
||||||
|
const PartialRedux<Vertical, BinaryOp, Derived>
|
||||||
|
verticalRedux(const BinaryOp& func) const;
|
||||||
|
|
||||||
|
template<typename BinaryOp>
|
||||||
|
const PartialRedux<Horizontal, BinaryOp, Derived>
|
||||||
|
horizontalRedux(const BinaryOp& func) const;
|
||||||
|
|
||||||
|
template<typename BinaryOp>
|
||||||
|
typename ei_result_of<BinaryOp(typename ei_traits<Derived>::Scalar)>::type
|
||||||
|
redux(const BinaryOp& func) const;
|
||||||
|
|
||||||
|
template<typename Visitor>
|
||||||
|
void visit(Visitor& func) const;
|
||||||
|
//@}
|
||||||
|
|
||||||
/// \name Casting to the derived type
|
/// \name Casting to the derived type
|
||||||
//@{
|
//@{
|
||||||
const Derived& derived() const { return *static_cast<const Derived*>(this); }
|
const Derived& derived() const { return *static_cast<const Derived*>(this); }
|
||||||
|
232
Eigen/src/Core/Redux.h
Normal file
232
Eigen/src/Core/Redux.h
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
// This file is part of Eigen, a lightweight C++ template library
|
||||||
|
// for linear algebra. Eigen itself is part of the KDE project.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||||
|
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
||||||
|
//
|
||||||
|
// Eigen is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 3 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Alternatively, you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of
|
||||||
|
// the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License and a copy of the GNU General Public License along with
|
||||||
|
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef EIGEN_REDUX_H
|
||||||
|
#define EIGEN_REDUX_H
|
||||||
|
|
||||||
|
|
||||||
|
template<typename BinaryOp, typename Derived, int Start, int Length>
|
||||||
|
struct ei_redux_unroller
|
||||||
|
{
|
||||||
|
enum {
|
||||||
|
HalfLength = Length/2
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef typename ei_result_of<BinaryOp(typename Derived::Scalar)>::type Scalar;
|
||||||
|
|
||||||
|
static Scalar run(const Derived &mat, const BinaryOp& func)
|
||||||
|
{
|
||||||
|
return func(
|
||||||
|
ei_redux_unroller<BinaryOp, Derived, Start, HalfLength>::run(mat, func),
|
||||||
|
ei_redux_unroller<BinaryOp, Derived, Start+HalfLength, Length - HalfLength>::run(mat, func));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BinaryOp, typename Derived, int Start>
|
||||||
|
struct ei_redux_unroller<BinaryOp, Derived, Start, 1>
|
||||||
|
{
|
||||||
|
enum {
|
||||||
|
col = Start / Derived::RowsAtCompileTime,
|
||||||
|
row = Start % Derived::RowsAtCompileTime
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef typename ei_result_of<BinaryOp(typename Derived::Scalar)>::type Scalar;
|
||||||
|
|
||||||
|
static Scalar run(const Derived &mat, const BinaryOp &func)
|
||||||
|
{
|
||||||
|
return mat.coeff(row, col);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename BinaryOp, typename Derived, int Start>
|
||||||
|
struct ei_redux_unroller<BinaryOp, Derived, Start, Dynamic>
|
||||||
|
{
|
||||||
|
typedef typename ei_result_of<BinaryOp(typename Derived::Scalar)>::type Scalar;
|
||||||
|
static Scalar run(const Derived&, const BinaryOp&) { return Scalar(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** \class PartialRedux
|
||||||
|
*
|
||||||
|
* \brief Generic expression of a partially reduxed matrix
|
||||||
|
*
|
||||||
|
* \param Direction indicates the direction of the redux (Vertical or Horizontal)
|
||||||
|
* \param BinaryOp type of the binary functor implementing the operator (must be associative)
|
||||||
|
* \param MatrixType the type of the matrix we are applying the redux operation
|
||||||
|
*
|
||||||
|
* This class represents an expression of a partial redux operator of a matrix.
|
||||||
|
* It is the return type of MatrixBase::verticalRedux(), MatrixBase::horizontalRedux(),
|
||||||
|
* and most of the time this is the only way it is used.
|
||||||
|
*
|
||||||
|
* \sa class CwiseBinaryOp
|
||||||
|
*/
|
||||||
|
template<int Direction, typename BinaryOp, typename MatrixType>
|
||||||
|
struct ei_traits<PartialRedux<Direction, BinaryOp, MatrixType> >
|
||||||
|
{
|
||||||
|
typedef typename ei_result_of<
|
||||||
|
BinaryOp(typename MatrixType::Scalar)
|
||||||
|
>::type Scalar;
|
||||||
|
enum {
|
||||||
|
RowsAtCompileTime = Direction==Vertical ? 1 : MatrixType::RowsAtCompileTime,
|
||||||
|
ColsAtCompileTime = Direction==Horizontal ? 1 : MatrixType::ColsAtCompileTime,
|
||||||
|
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
|
||||||
|
MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<int Direction, typename BinaryOp, typename MatrixType>
|
||||||
|
class PartialRedux : ei_no_assignment_operator,
|
||||||
|
public MatrixBase<PartialRedux<Direction, BinaryOp, MatrixType> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
EIGEN_GENERIC_PUBLIC_INTERFACE(PartialRedux)
|
||||||
|
|
||||||
|
PartialRedux(const MatrixType& mat, const BinaryOp& func = BinaryOp())
|
||||||
|
: m_matrix(mat), m_functor(func) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
int _rows() const { return (Direction==Vertical ? 1 : m_matrix.rows()); }
|
||||||
|
int _cols() const { return (Direction==Horizontal ? 1 : m_matrix.cols()); }
|
||||||
|
|
||||||
|
Scalar _coeff(int i, int j) const
|
||||||
|
{
|
||||||
|
if (Direction==Vertical)
|
||||||
|
return this->col(j).redux(m_functor);
|
||||||
|
else
|
||||||
|
return this->row(i).redux(m_functor);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const typename MatrixType::XprCopy m_matrix;
|
||||||
|
const BinaryOp m_functor;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \returns a row vector expression of *this vertically reduxed by \a func
|
||||||
|
*
|
||||||
|
* The template parameter \a BinaryOp is the type of the functor
|
||||||
|
* of the custom redux operator. Note that func must be an associative operator.
|
||||||
|
*
|
||||||
|
* \sa class PartialRedux, MatrixBase::horizontalRedux()
|
||||||
|
*/
|
||||||
|
template<typename Derived>
|
||||||
|
template<typename BinaryOp>
|
||||||
|
const PartialRedux<Vertical, BinaryOp, Derived>
|
||||||
|
MatrixBase<Derived>::verticalRedux(const BinaryOp& func) const
|
||||||
|
{
|
||||||
|
return PartialRedux<Vertical, BinaryOp, Derived>(derived(), func);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \returns a row vector expression of *this horizontally reduxed by \a func
|
||||||
|
*
|
||||||
|
* The template parameter \a BinaryOp is the type of the functor
|
||||||
|
* of the custom redux operator. Note that func must be an associative operator.
|
||||||
|
*
|
||||||
|
* \sa class PartialRedux, MatrixBase::verticalRedux()
|
||||||
|
*/
|
||||||
|
template<typename Derived>
|
||||||
|
template<typename BinaryOp>
|
||||||
|
const PartialRedux<Horizontal, BinaryOp, Derived>
|
||||||
|
MatrixBase<Derived>::horizontalRedux(const BinaryOp& func) const
|
||||||
|
{
|
||||||
|
return PartialRedux<Horizontal, BinaryOp, Derived>(derived(), func);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** \returns the result of a full redux operation on the whole matrix or vector using \a func
|
||||||
|
*
|
||||||
|
* The template parameter \a BinaryOp is the type of the functor \a func which must be
|
||||||
|
* an assiociative operator. Both current STL and TR1 functor styles are handled.
|
||||||
|
*
|
||||||
|
* \sa MatrixBase::sum(), MatrixBase::minCoeff(), MatrixBase::maxCoeff(), MatrixBase::verticalRedux(), MatrixBase::horizontalRedux()
|
||||||
|
*/
|
||||||
|
template<typename Derived>
|
||||||
|
template<typename BinaryOp>
|
||||||
|
typename ei_result_of<BinaryOp(typename ei_traits<Derived>::Scalar)>::type
|
||||||
|
MatrixBase<Derived>::redux(const BinaryOp& func) const
|
||||||
|
{
|
||||||
|
if(EIGEN_UNROLLED_LOOPS
|
||||||
|
&& SizeAtCompileTime != Dynamic
|
||||||
|
&& SizeAtCompileTime <= EIGEN_UNROLLING_LIMIT)
|
||||||
|
return ei_redux_unroller<BinaryOp, Derived, 0,
|
||||||
|
(SizeAtCompileTime>0 && SizeAtCompileTime <= EIGEN_UNROLLING_LIMIT) ?
|
||||||
|
SizeAtCompileTime : Dynamic>::run(derived(), func);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Scalar res;
|
||||||
|
res = coeff(0,0);
|
||||||
|
for(int i = 1; i < rows(); i++)
|
||||||
|
res = func(res, coeff(i, 0));
|
||||||
|
for(int j = 1; j < cols(); j++)
|
||||||
|
for(int i = 0; i < rows(); i++)
|
||||||
|
res = func(res, coeff(i, j));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \returns the sum of all coefficients of *this
|
||||||
|
*
|
||||||
|
* \sa trace()
|
||||||
|
*/
|
||||||
|
template<typename Derived>
|
||||||
|
typename ei_traits<Derived>::Scalar
|
||||||
|
MatrixBase<Derived>::sum() const
|
||||||
|
{
|
||||||
|
return this->redux(Eigen::ei_scalar_sum_op());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \returns the trace of \c *this, i.e. the sum of the coefficients on the main diagonal.
|
||||||
|
*
|
||||||
|
* \c *this can be any matrix, not necessarily square.
|
||||||
|
*
|
||||||
|
* \sa diagonal(), sum()
|
||||||
|
*/
|
||||||
|
template<typename Derived>
|
||||||
|
typename ei_traits<Derived>::Scalar
|
||||||
|
MatrixBase<Derived>::trace() const
|
||||||
|
{
|
||||||
|
return diagonal().sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \returns the minimum of all coefficients of *this
|
||||||
|
*/
|
||||||
|
template<typename Derived>
|
||||||
|
typename ei_traits<Derived>::Scalar
|
||||||
|
MatrixBase<Derived>::minCoeff() const
|
||||||
|
{
|
||||||
|
return this->redux(Eigen::ei_scalar_min_op());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \returns the maximum of all coefficients of *this
|
||||||
|
*/
|
||||||
|
template<typename Derived>
|
||||||
|
typename ei_traits<Derived>::Scalar
|
||||||
|
MatrixBase<Derived>::maxCoeff() const
|
||||||
|
{
|
||||||
|
return this->redux(Eigen::ei_scalar_max_op());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // EIGEN_REDUX_H
|
@ -1,102 +0,0 @@
|
|||||||
// This file is part of Eigen, a lightweight C++ template library
|
|
||||||
// for linear algebra. Eigen itself is part of the KDE project.
|
|
||||||
//
|
|
||||||
// Copyright (C) 2006-2008 Benoit Jacob <jacob@math.jussieu.fr>
|
|
||||||
//
|
|
||||||
// Eigen is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 3 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Alternatively, you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU General Public License as
|
|
||||||
// published by the Free Software Foundation; either version 2 of
|
|
||||||
// the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License and a copy of the GNU General Public License along with
|
|
||||||
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#ifndef EIGEN_SUMOFCOEFFS_H
|
|
||||||
#define EIGEN_SUMOFCOEFFS_H
|
|
||||||
|
|
||||||
template<int Index, int Size, typename Derived>
|
|
||||||
struct ei_sumofcoeffs_unroller
|
|
||||||
{
|
|
||||||
static void run(const Derived &v1, typename Derived::Scalar &dot)
|
|
||||||
{
|
|
||||||
ei_sumofcoeffs_unroller<Index-1, Size, Derived>::run(v1, dot);
|
|
||||||
dot += v1.coeff(Index);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<int Size, typename Derived>
|
|
||||||
struct ei_sumofcoeffs_unroller<0, Size, Derived>
|
|
||||||
{
|
|
||||||
static void run(const Derived &v1, typename Derived::Scalar &dot)
|
|
||||||
{
|
|
||||||
dot = v1.coeff(0);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<int Index, typename Derived>
|
|
||||||
struct ei_sumofcoeffs_unroller<Index, Dynamic, Derived>
|
|
||||||
{
|
|
||||||
static void run(const Derived&, typename Derived::Scalar&) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// prevent buggy user code from causing an infinite recursion
|
|
||||||
template<int Index, typename Derived>
|
|
||||||
struct ei_sumofcoeffs_unroller<Index, 0, Derived>
|
|
||||||
{
|
|
||||||
static void run(const Derived&, typename Derived::Scalar&)
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** \returns the sum of all coefficients of *this
|
|
||||||
*
|
|
||||||
* \only_for_vectors
|
|
||||||
*
|
|
||||||
* \sa trace()
|
|
||||||
*/
|
|
||||||
template<typename Derived>
|
|
||||||
typename ei_traits<Derived>::Scalar
|
|
||||||
MatrixBase<Derived>::sum() const
|
|
||||||
{
|
|
||||||
assert(IsVectorAtCompileTime);
|
|
||||||
Scalar res;
|
|
||||||
if(EIGEN_UNROLLED_LOOPS
|
|
||||||
&& SizeAtCompileTime != Dynamic
|
|
||||||
&& SizeAtCompileTime <= EIGEN_UNROLLING_LIMIT)
|
|
||||||
ei_sumofcoeffs_unroller<SizeAtCompileTime-1,
|
|
||||||
SizeAtCompileTime <= EIGEN_UNROLLING_LIMIT ? SizeAtCompileTime : Dynamic,
|
|
||||||
Derived>
|
|
||||||
::run(derived(),res);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
res = coeff(0);
|
|
||||||
for(int i = 1; i < size(); i++)
|
|
||||||
res += coeff(i);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \returns the trace of \c *this, i.e. the sum of the coefficients on the main diagonal.
|
|
||||||
*
|
|
||||||
* \c *this can be any matrix, not necessarily square.
|
|
||||||
*
|
|
||||||
* \sa diagonal(), sum()
|
|
||||||
*/
|
|
||||||
template<typename Derived>
|
|
||||||
typename ei_traits<Derived>::Scalar
|
|
||||||
MatrixBase<Derived>::trace() const
|
|
||||||
{
|
|
||||||
return diagonal().sum();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // EIGEN_SUMOFCOEFFS_H
|
|
@ -120,6 +120,8 @@ const int RowMajor = 1;
|
|||||||
|
|
||||||
enum CornerType { TopLeft, TopRight, BottomLeft, BottomRight };
|
enum CornerType { TopLeft, TopRight, BottomLeft, BottomRight };
|
||||||
|
|
||||||
|
enum DirectionType { Vertical, Horizontal };
|
||||||
|
|
||||||
// just a workaround because GCC seems to not really like empty structs
|
// just a workaround because GCC seems to not really like empty structs
|
||||||
#ifdef __GNUG__
|
#ifdef __GNUG__
|
||||||
struct ei_empty_struct{char _ei_dummy_;};
|
struct ei_empty_struct{char _ei_dummy_;};
|
||||||
|
182
Eigen/src/Core/Visitor.h
Normal file
182
Eigen/src/Core/Visitor.h
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
// This file is part of Eigen, a lightweight C++ template library
|
||||||
|
// for linear algebra. Eigen itself is part of the KDE project.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
|
||||||
|
//
|
||||||
|
// Eigen is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 3 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Alternatively, you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License as
|
||||||
|
// published by the Free Software Foundation; either version 2 of
|
||||||
|
// the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License and a copy of the GNU General Public License along with
|
||||||
|
// Eigen. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef EIGEN_VISITOR_H
|
||||||
|
#define EIGEN_VISITOR_H
|
||||||
|
|
||||||
|
template<typename Visitor, typename Derived, int UnrollCount>
|
||||||
|
struct ei_visitor_unroller
|
||||||
|
{
|
||||||
|
enum {
|
||||||
|
col = (UnrollCount-1) / Derived::RowsAtCompileTime,
|
||||||
|
row = (UnrollCount-1) % Derived::RowsAtCompileTime
|
||||||
|
};
|
||||||
|
|
||||||
|
static void run(const Derived &mat, Visitor& visitor)
|
||||||
|
{
|
||||||
|
ei_visitor_unroller<Visitor, Derived, UnrollCount-1>::run(mat, visitor);
|
||||||
|
visitor(mat.coeff(row, col), row, col);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Visitor, typename Derived>
|
||||||
|
struct ei_visitor_unroller<Visitor, Derived, 1>
|
||||||
|
{
|
||||||
|
static void run(const Derived &mat, Visitor& visitor)
|
||||||
|
{
|
||||||
|
return visitor.init(mat.coeff(0, 0), 0, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Visitor, typename Derived>
|
||||||
|
struct ei_visitor_unroller<Visitor, Derived, Dynamic>
|
||||||
|
{
|
||||||
|
static void run(const Derived &mat, Visitor& visitor) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Applies the visitor \a visitor to the whole coefficients of the matrix or vector.
|
||||||
|
*
|
||||||
|
* The template parameter \a Visitor is the type of the visitor and provides the following interface:
|
||||||
|
* \code
|
||||||
|
* struct MyVisitor {
|
||||||
|
* // called for the first coefficient
|
||||||
|
* void init(const Scalar& value, int i, int j);
|
||||||
|
* // called for all other coefficients
|
||||||
|
* void operator() (const Scalar& value, int i, int j);
|
||||||
|
* };
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* \sa minCoeff(int*,int*), maxCoeff(int*,int*), MatrixBase::redux()
|
||||||
|
*/
|
||||||
|
template<typename Derived>
|
||||||
|
template<typename Visitor>
|
||||||
|
void MatrixBase<Derived>::visit(Visitor& visitor) const
|
||||||
|
{
|
||||||
|
if(EIGEN_UNROLLED_LOOPS
|
||||||
|
&& SizeAtCompileTime != Dynamic
|
||||||
|
&& SizeAtCompileTime <= EIGEN_UNROLLING_LIMIT)
|
||||||
|
return ei_visitor_unroller<Visitor, Derived,
|
||||||
|
(SizeAtCompileTime>0 && SizeAtCompileTime <= EIGEN_UNROLLING_LIMIT) ?
|
||||||
|
SizeAtCompileTime : Dynamic>::run(derived(), visitor);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Scalar res;
|
||||||
|
visitor.init(coeff(0,0), 0, 0);
|
||||||
|
for(int i = 1; i < rows(); i++)
|
||||||
|
visitor(res, coeff(i, 0), i, 0);
|
||||||
|
for(int j = 1; j < cols(); j++)
|
||||||
|
for(int i = 0; i < rows(); i++)
|
||||||
|
visitor(res, coeff(i, j), i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \internal
|
||||||
|
* \brief Base class to implement min and max visitors
|
||||||
|
*/
|
||||||
|
template <typename Scalar>
|
||||||
|
struct ei_coeff_visitor
|
||||||
|
{
|
||||||
|
int row, col;
|
||||||
|
Scalar res;
|
||||||
|
void init(const Scalar& value, int i, int j)
|
||||||
|
{
|
||||||
|
res = value;
|
||||||
|
row = i;
|
||||||
|
col = j;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \internal
|
||||||
|
* \brief Visitor computing the min coefficient with its value and coordinates
|
||||||
|
*
|
||||||
|
* \sa ei_coeff_visitor, ei_max_coeff_visitor, MatrixBase::minCoeff(int*, int*)
|
||||||
|
*/
|
||||||
|
template <typename Scalar>
|
||||||
|
struct ei_min_coeff_visitor : ei_coeff_visitor<Scalar>
|
||||||
|
{
|
||||||
|
void operator() (const Scalar& value, int i, int j)
|
||||||
|
{
|
||||||
|
if(value < this->res)
|
||||||
|
{
|
||||||
|
this->res = value;
|
||||||
|
this->row = i;
|
||||||
|
this->col = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \internal
|
||||||
|
* \brief Visitor computing the max coefficient with its value and coordinates
|
||||||
|
*
|
||||||
|
* \sa ei_coeff_visitor, ei_min_coeff_visitor, MatrixBase::maxCoeff(int*, int*)
|
||||||
|
*/
|
||||||
|
template <typename Scalar>
|
||||||
|
struct ei_max_coeff_visitor : ei_coeff_visitor<Scalar>
|
||||||
|
{
|
||||||
|
void operator() (const Scalar& value, int i, int j)
|
||||||
|
{
|
||||||
|
if(value > this->res)
|
||||||
|
{
|
||||||
|
this->res = value;
|
||||||
|
this->row = i;
|
||||||
|
this->col = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \returns the minimum of all coefficients of *this
|
||||||
|
* and puts in *row and *col its location.
|
||||||
|
*
|
||||||
|
* \sa MatrixBase::maxCoeff(int*,int*), MatrixBase::visitor(), MatrixBase::minCoeff()
|
||||||
|
*/
|
||||||
|
template<typename Derived>
|
||||||
|
typename ei_traits<Derived>::Scalar
|
||||||
|
MatrixBase<Derived>::minCoeff(int* row, int* col) const
|
||||||
|
{
|
||||||
|
ei_min_coeff_visitor<Scalar> minVisitor;
|
||||||
|
this->visit(minVisitor);
|
||||||
|
*row = minVisitor.row;
|
||||||
|
if (col) *col = minVisitor.col;
|
||||||
|
return minVisitor.res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \returns the maximum of all coefficients of *this
|
||||||
|
* and puts in *row and *col its location.
|
||||||
|
*
|
||||||
|
* \sa MatrixBase::minCoeff(int*,int*), MatrixBase::visitor(), MatrixBase::maxCoeff()
|
||||||
|
*/
|
||||||
|
template<typename Derived>
|
||||||
|
typename ei_traits<Derived>::Scalar
|
||||||
|
MatrixBase<Derived>::maxCoeff(int* row, int* col) const
|
||||||
|
{
|
||||||
|
ei_max_coeff_visitor<Scalar> maxVisitor;
|
||||||
|
this->visit(maxVisitor);
|
||||||
|
*row = maxVisitor.row;
|
||||||
|
if (col) *col = maxVisitor.col;
|
||||||
|
return maxVisitor.res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // EIGEN_VISITOR_H
|
Loading…
x
Reference in New Issue
Block a user