1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra. Eigen itself is part of the KDE project.
3 //
4 // Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
5 // Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
6 //
7 // Eigen is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU Lesser General Public
9 // License as published by the Free Software Foundation; either
10 // version 3 of the License, or (at your option) any later version.
11 //
12 // Alternatively, you can redistribute it and/or
13 // modify it under the terms of the GNU General Public License as
14 // published by the Free Software Foundation; either version 2 of
15 // the License, or (at your option) any later version.
16 //
17 // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU Lesser General Public
23 // License and a copy of the GNU General Public License along with
24 // Eigen. If not, see <http://www.gnu.org/licenses/>.
26 #ifndef EIGEN_FUZZY_H
27 #define EIGEN_FUZZY_H
29 #ifndef EIGEN_LEGACY_COMPARES
31 /** \returns \c true if \c *this is approximately equal to \a other, within the precision
32   * determined by \a prec.
33   *
34   * \note The fuzzy compares are done multiplicatively. Two vectors \f\$ v \f\$ and \f\$ w \f\$
35   * are considered to be approximately equal within precision \f\$ p \f\$ if
36   * \f[ \Vert v - w \Vert \leqslant p\,\min(\Vert v\Vert, \Vert w\Vert). \f]
37   * For matrices, the comparison is done using the Hilbert-Schmidt norm (aka Frobenius norm
38   * L2 norm).
39   *
40   * \note Because of the multiplicativeness of this comparison, one can't use this function
41   * to check whether \c *this is approximately equal to the zero matrix or vector.
42   * Indeed, \c isApprox(zero) returns false unless \c *this itself is exactly the zero matrix
43   * or vector. If you want to test whether \c *this is zero, use ei_isMuchSmallerThan(const
44   * RealScalar&, RealScalar) instead.
45   *
46   * \sa ei_isMuchSmallerThan(const RealScalar&, RealScalar) const
47   */
48 template<typename Derived>
49 template<typename OtherDerived>
50 bool MatrixBase<Derived>::isApprox(
51   const MatrixBase<OtherDerived>& other,
52   typename NumTraits<Scalar>::Real prec
53 ) const
54 {
55   const typename ei_nested<Derived,2>::type nested(derived());
56   const typename ei_nested<OtherDerived,2>::type otherNested(other.derived());
57   return (nested - otherNested).cwise().abs2().sum() <= prec * prec * std::min(nested.cwise().abs2().sum(), otherNested.cwise().abs2().sum());
58 }
60 /** \returns \c true if the norm of \c *this is much smaller than \a other,
61   * within the precision determined by \a prec.
62   *
63   * \note The fuzzy compares are done multiplicatively. A vector \f\$ v \f\$ is
64   * considered to be much smaller than \f\$ x \f\$ within precision \f\$ p \f\$ if
65   * \f[ \Vert v \Vert \leqslant p\,\vert x\vert. \f]
66   *
67   * For matrices, the comparison is done using the Hilbert-Schmidt norm. For this reason,
68   * the value of the reference scalar \a other should come from the Hilbert-Schmidt norm
69   * of a reference matrix of same dimensions.
70   *
71   * \sa isApprox(), isMuchSmallerThan(const MatrixBase<OtherDerived>&, RealScalar) const
72   */
73 template<typename Derived>
74 bool MatrixBase<Derived>::isMuchSmallerThan(
75   const typename NumTraits<Scalar>::Real& other,
76   typename NumTraits<Scalar>::Real prec
77 ) const
78 {
79   return cwise().abs2().sum() <= prec * prec * other * other;
80 }
82 /** \returns \c true if the norm of \c *this is much smaller than the norm of \a other,
83   * within the precision determined by \a prec.
84   *
85   * \note The fuzzy compares are done multiplicatively. A vector \f\$ v \f\$ is
86   * considered to be much smaller than a vector \f\$ w \f\$ within precision \f\$ p \f\$ if
87   * \f[ \Vert v \Vert \leqslant p\,\Vert w\Vert. \f]
88   * For matrices, the comparison is done using the Hilbert-Schmidt norm.
89   *
90   * \sa isApprox(), isMuchSmallerThan(const RealScalar&, RealScalar) const
91   */
92 template<typename Derived>
93 template<typename OtherDerived>
94 bool MatrixBase<Derived>::isMuchSmallerThan(
95   const MatrixBase<OtherDerived>& other,
96   typename NumTraits<Scalar>::Real prec
97 ) const
98 {
99   return this->cwise().abs2().sum() <= prec * prec * other.cwise().abs2().sum();
100 }
102 #else
104 template<typename Derived, typename OtherDerived=Derived, bool IsVector=Derived::IsVectorAtCompileTime>
105 struct ei_fuzzy_selector;
107 /** \returns \c true if \c *this is approximately equal to \a other, within the precision
108   * determined by \a prec.
109   *
110   * \note The fuzzy compares are done multiplicatively. Two vectors \f\$ v \f\$ and \f\$ w \f\$
111   * are considered to be approximately equal within precision \f\$ p \f\$ if
112   * \f[ \Vert v - w \Vert \leqslant p\,\min(\Vert v\Vert, \Vert w\Vert). \f]
113   * For matrices, the comparison is done on all columns.
114   *
115   * \note Because of the multiplicativeness of this comparison, one can't use this function
116   * to check whether \c *this is approximately equal to the zero matrix or vector.
117   * Indeed, \c isApprox(zero) returns false unless \c *this itself is exactly the zero matrix
118   * or vector. If you want to test whether \c *this is zero, use ei_isMuchSmallerThan(const
119   * RealScalar&, RealScalar) instead.
120   *
121   * \sa ei_isMuchSmallerThan(const RealScalar&, RealScalar) const
122   */
123 template<typename Derived>
124 template<typename OtherDerived>
125 bool MatrixBase<Derived>::isApprox(
126   const MatrixBase<OtherDerived>& other,
127   typename NumTraits<Scalar>::Real prec
128 ) const
129 {
130   return ei_fuzzy_selector<Derived,OtherDerived>::isApprox(derived(), other.derived(), prec);
131 }
133 /** \returns \c true if the norm of \c *this is much smaller than \a other,
134   * within the precision determined by \a prec.
135   *
136   * \note The fuzzy compares are done multiplicatively. A vector \f\$ v \f\$ is
137   * considered to be much smaller than \f\$ x \f\$ within precision \f\$ p \f\$ if
138   * \f[ \Vert v \Vert \leqslant p\,\vert x\vert. \f]
139   * For matrices, the comparison is done on all columns.
140   *
141   * \sa isApprox(), isMuchSmallerThan(const MatrixBase<OtherDerived>&, RealScalar) const
142   */
143 template<typename Derived>
144 bool MatrixBase<Derived>::isMuchSmallerThan(
145   const typename NumTraits<Scalar>::Real& other,
146   typename NumTraits<Scalar>::Real prec
147 ) const
148 {
149   return ei_fuzzy_selector<Derived>::isMuchSmallerThan(derived(), other, prec);
150 }
152 /** \returns \c true if the norm of \c *this is much smaller than the norm of \a other,
153   * within the precision determined by \a prec.
154   *
155   * \note The fuzzy compares are done multiplicatively. A vector \f\$ v \f\$ is
156   * considered to be much smaller than a vector \f\$ w \f\$ within precision \f\$ p \f\$ if
157   * \f[ \Vert v \Vert \leqslant p\,\Vert w\Vert. \f]
158   * For matrices, the comparison is done on all columns.
159   *
160   * \sa isApprox(), isMuchSmallerThan(const RealScalar&, RealScalar) const
161   */
162 template<typename Derived>
163 template<typename OtherDerived>
164 bool MatrixBase<Derived>::isMuchSmallerThan(
165   const MatrixBase<OtherDerived>& other,
166   typename NumTraits<Scalar>::Real prec
167 ) const
168 {
169   return ei_fuzzy_selector<Derived,OtherDerived>::isMuchSmallerThan(derived(), other.derived(), prec);
170 }
173 template<typename Derived, typename OtherDerived>
174 struct ei_fuzzy_selector<Derived,OtherDerived,true>
175 {
176   typedef typename Derived::RealScalar RealScalar;
177   static bool isApprox(const Derived& self, const OtherDerived& other, RealScalar prec)
178   {
179     EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived)
180     ei_assert(self.size() == other.size());
181     return((self - other).squaredNorm() <= std::min(self.squaredNorm(), other.squaredNorm()) * prec * prec);
182   }
183   static bool isMuchSmallerThan(const Derived& self, const RealScalar& other, RealScalar prec)
184   {
185     return(self.squaredNorm() <= ei_abs2(other * prec));
186   }
187   static bool isMuchSmallerThan(const Derived& self, const OtherDerived& other, RealScalar prec)
188   {
189     EIGEN_STATIC_ASSERT_SAME_VECTOR_SIZE(Derived,OtherDerived)
190     ei_assert(self.size() == other.size());
191     return(self.squaredNorm() <= other.squaredNorm() * prec * prec);
192   }
193 };
195 template<typename Derived, typename OtherDerived>
196 struct ei_fuzzy_selector<Derived,OtherDerived,false>
197 {
198   typedef typename Derived::RealScalar RealScalar;
199   static bool isApprox(const Derived& self, const OtherDerived& other, RealScalar prec)
200   {
201     EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived)
202     ei_assert(self.rows() == other.rows() && self.cols() == other.cols());
203     typename Derived::Nested nested(self);
204     typename OtherDerived::Nested otherNested(other);
205     for(int i = 0; i < self.cols(); ++i)
206       if((nested.col(i) - otherNested.col(i)).squaredNorm()
207           > std::min(nested.col(i).squaredNorm(), otherNested.col(i).squaredNorm()) * prec * prec)
208         return false;
209     return true;
210   }
211   static bool isMuchSmallerThan(const Derived& self, const RealScalar& other, RealScalar prec)
212   {
213     typename Derived::Nested nested(self);
214     for(int i = 0; i < self.cols(); ++i)
215       if(nested.col(i).squaredNorm() > ei_abs2(other * prec))
216         return false;
217     return true;
218   }
219   static bool isMuchSmallerThan(const Derived& self, const OtherDerived& other, RealScalar prec)
220   {
221     EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived)
222     ei_assert(self.rows() == other.rows() && self.cols() == other.cols());
223     typename Derived::Nested nested(self);
224     typename OtherDerived::Nested otherNested(other);
225     for(int i = 0; i < self.cols(); ++i)
226       if(nested.col(i).squaredNorm() > otherNested.col(i).squaredNorm() * prec * prec)
227         return false;
228     return true;
229   }
230 };
232 #endif
234 #endif // EIGEN_FUZZY_H