17

Is there a function in Eigen to compare vectors (matrices) using both relative and absolute tolerance aka numpy.allclose? Standard isApprox fails if one of the vectors is very close to zero.

DikobrAz
  • 3,557
  • 4
  • 35
  • 53

2 Answers2

21

There is no built-in function implementing numpy.allclose, but you easily write one yourself if that's really what you need. However, I'd rather suggest the use of isMuchSmallerThan with reference value:

(a-b).isMuchSmallerThan(ref)

where ref is a representative non zero for your problem.

EDIT: for reference here is a possible implementation of allclose:

template<typename DerivedA, typename DerivedB>
bool allclose(const Eigen::DenseBase<DerivedA>& a,
              const Eigen::DenseBase<DerivedB>& b,
              const typename DerivedA::RealScalar& rtol
                  = Eigen::NumTraits<typename DerivedA::RealScalar>::dummy_precision(),
              const typename DerivedA::RealScalar& atol
                  = Eigen::NumTraits<typename DerivedA::RealScalar>::epsilon())
{
  return ((a.derived() - b.derived()).array().abs()
          <= (atol + rtol * b.derived().array().abs())).all();
}
ggael
  • 28,425
  • 2
  • 65
  • 71
  • isMuchSmallerThan can be used for absolute comparison, i.e. (a-b).isMuchSmallerThan(1.0, atol) is equivalent to np.allclose(a, b, 0.0, atol), so to mimic np.allclose we have to do something like this: (a-b).isMuchSmallerThan(1.0, atol) || a.isApprox(b, rtol). Am I correct? – DikobrAz Feb 24 '13 at 13:38
  • 5
    Not exactly because isMuchSmallerThan and isApprox are based on the L2 matrix norm and not element-wise comparisons (infinite norm). – ggael Feb 24 '13 at 16:46
  • It's probably worth mentioning that this, like numpy's `allclose`, is not symmetric, and `b` is expected to be a reference value. If you need a symmetric comparison, multiply `rtol` by `a.derived().array().abs().max(b.derived().array().abs())` instead. – ɲeuroburɳ Aug 31 '21 at 14:51
  • For Quaternions which have a `coeffs()` method to get at the matrix and where negatives are equivelent: `auto e{ atol + rtol * b.coeffs().derived().array().abs() }; return ((a.coeffs().derived() - b.coeffs().derived()).array().abs() <= e).all() || ((a.coeffs().derived() + b.coeffs().derived()).array().abs() <= e).all();` – mheyman Mar 12 '23 at 17:52
4

There is also isApprox function which was not working for me. I am just using ( expect - res).norm() < some small number.

nnrales
  • 1,481
  • 1
  • 17
  • 26