Drake
eigen_matrix_compare.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <Eigen/Dense>
4 #include <cmath>
5 
6 namespace drake {
7 namespace util {
8 
10 
24 template <typename DerivedA, typename DerivedB>
25 bool CompareMatrices(const Eigen::MatrixBase<DerivedA>& m1,
26  const Eigen::MatrixBase<DerivedB>& m2,
27  double tolerance,
28  MatrixCompareType compare_type,
29  std::string* explanation = nullptr) {
30  bool result = true;
31 
32  if (m1.rows() != m2.rows() || m1.cols() != m2.cols()) {
33  if (explanation != nullptr) {
34  std::stringstream msg;
35  msg << "Matrix size mismatch: (" << m1.rows() << " x " << m1.cols()
36  << " vs. " << m2.rows() << " x " << m2.rows() << ")";
37  *explanation = msg.str();
38  }
39  result = false;
40  }
41 
42  for (int ii = 0; result && ii < m1.rows(); ii++) {
43  for (int jj = 0; result && jj < m1.cols(); jj++) {
44  // First handle the corner cases of positive infinity, negative infinity,
45  // and NaN
46  bool both_positive_infinity =
47  m1(ii, jj) == std::numeric_limits<double>::infinity() &&
48  m2(ii, jj) == std::numeric_limits<double>::infinity();
49 
50  bool both_negative_infinity =
51  m1(ii, jj) == -std::numeric_limits<double>::infinity() &&
52  m2(ii, jj) == -std::numeric_limits<double>::infinity();
53 
54  bool both_nan = std::isnan(m1(ii, jj)) && std::isnan(m2(ii, jj));
55 
56  if (both_positive_infinity || both_negative_infinity || both_nan)
57  continue;
58 
59  // Check for case where one value is NaN and the other is not
60  if ((std::isnan(m1(ii, jj)) && !std::isnan(m2(ii, jj))) ||
61  (!std::isnan(m1(ii, jj)) && std::isnan(m2(ii, jj)))) {
62  if (explanation != nullptr) {
63  std::stringstream msg;
64  msg << "NaN missmatch at (" << ii << ", " << jj << "):\nm1 =\n"
65  << m1 << "\nm2 =\n"
66  << m2;
67  *explanation = msg.str();
68  }
69  result = false;
70  continue;
71  }
72 
73  // Determine whether the difference between the two matrices is less than
74  // the tolerance.
75  double delta = std::abs(m1(ii, jj) - m2(ii, jj));
76 
77  if (compare_type == MatrixCompareType::absolute) {
78  // Perform comparison using absolute tolerance.
79 
80  if (delta > tolerance) {
81  if (explanation != nullptr) {
82  std::stringstream msg;
83  msg << "Values at (" << ii << ", " << jj
84  << ") exceed tolerance: " << m1(ii, jj) << " vs. " << m2(ii, jj)
85  << ", diff = " << delta << ", tolerance = " << tolerance
86  << "\nm1 =\n"
87  << m1 << "\nm2 =\n"
88  << m2 << "\ndelta=\n"
89  << (m1 - m2);
90 
91  *explanation = msg.str();
92  }
93  result = false;
94  }
95  } else {
96  // Perform comparison using relative tolerance, see:
97  // http://realtimecollisiondetection.net/blog/?p=89
98  double max_value = std::max(std::abs(m1(ii, jj)), std::abs(m2(ii, jj)));
99  double relative_tolerance = tolerance * std::max(1.0, max_value);
100 
101  if (delta > relative_tolerance) {
102  if (explanation != nullptr) {
103  std::stringstream msg;
104  msg << "Values at (" << ii << ", " << jj
105  << ") exceed tolerance: " << m1(ii, jj) << " vs. " << m2(ii, jj)
106  << ", diff = " << delta << ", tolerance = " << tolerance
107  << ", relative tolerance = " << relative_tolerance << "\nm1 =\n"
108  << m1 << "\nm2 =\n"
109  << m2 << "\ndelta=\n"
110  << (m1 - m2);
111 
112  *explanation = msg.str();
113  }
114  result = false;
115  }
116  }
117  }
118  }
119 
120  return result;
121 }
122 
123 } // namespace util
124 } // namespace drake
Definition: eigen_matrix_compare.h:9
Definition: constants.h:3
FunctionalForm abs(FunctionalForm const &x)
Definition: functional_form.cc:183
Definition: eigen_matrix_compare.h:9
std::vector< Number > result
Definition: IpoptSolver.cpp:170
MatrixCompareType
Definition: eigen_matrix_compare.h:9
bool CompareMatrices(const Eigen::MatrixBase< DerivedA > &m1, const Eigen::MatrixBase< DerivedB > &m2, double tolerance, MatrixCompareType compare_type, std::string *explanation=nullptr)
Compares two matrices to determine whether they are equal to within a certain threshold.
Definition: eigen_matrix_compare.h:25