ConditionEstimator.h 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. // This file is part of Eigen, a lightweight C++ template library
  2. // for linear algebra.
  3. //
  4. // Copyright (C) 2016 Rasmus Munk Larsen (rmlarsen@google.com)
  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. #ifndef EIGEN_CONDITIONESTIMATOR_H
  10. #define EIGEN_CONDITIONESTIMATOR_H
  11. namespace Eigen {
  12. namespace internal {
  13. template <typename Vector, typename RealVector, bool IsComplex>
  14. struct rcond_compute_sign {
  15. static inline Vector run(const Vector& v) {
  16. const RealVector v_abs = v.cwiseAbs();
  17. return (v_abs.array() == static_cast<typename Vector::RealScalar>(0))
  18. .select(Vector::Ones(v.size()), v.cwiseQuotient(v_abs));
  19. }
  20. };
  21. // Partial specialization to avoid elementwise division for real vectors.
  22. template <typename Vector>
  23. struct rcond_compute_sign<Vector, Vector, false> {
  24. static inline Vector run(const Vector& v) {
  25. return (v.array() < static_cast<typename Vector::RealScalar>(0))
  26. .select(-Vector::Ones(v.size()), Vector::Ones(v.size()));
  27. }
  28. };
  29. /**
  30. * \returns an estimate of ||inv(matrix)||_1 given a decomposition of
  31. * \a matrix that implements .solve() and .adjoint().solve() methods.
  32. *
  33. * This function implements Algorithms 4.1 and 5.1 from
  34. * http://www.maths.manchester.ac.uk/~higham/narep/narep135.pdf
  35. * which also forms the basis for the condition number estimators in
  36. * LAPACK. Since at most 10 calls to the solve method of dec are
  37. * performed, the total cost is O(dims^2), as opposed to O(dims^3)
  38. * needed to compute the inverse matrix explicitly.
  39. *
  40. * The most common usage is in estimating the condition number
  41. * ||matrix||_1 * ||inv(matrix)||_1. The first term ||matrix||_1 can be
  42. * computed directly in O(n^2) operations.
  43. *
  44. * Supports the following decompositions: FullPivLU, PartialPivLU, LDLT, and
  45. * LLT.
  46. *
  47. * \sa FullPivLU, PartialPivLU, LDLT, LLT.
  48. */
  49. template <typename Decomposition>
  50. typename Decomposition::RealScalar rcond_invmatrix_L1_norm_estimate(const Decomposition& dec)
  51. {
  52. typedef typename Decomposition::MatrixType MatrixType;
  53. typedef typename Decomposition::Scalar Scalar;
  54. typedef typename Decomposition::RealScalar RealScalar;
  55. typedef typename internal::plain_col_type<MatrixType>::type Vector;
  56. typedef typename internal::plain_col_type<MatrixType, RealScalar>::type RealVector;
  57. const bool is_complex = (NumTraits<Scalar>::IsComplex != 0);
  58. eigen_assert(dec.rows() == dec.cols());
  59. const Index n = dec.rows();
  60. if (n == 0)
  61. return 0;
  62. // Disable Index to float conversion warning
  63. #ifdef __INTEL_COMPILER
  64. #pragma warning push
  65. #pragma warning ( disable : 2259 )
  66. #endif
  67. Vector v = dec.solve(Vector::Ones(n) / Scalar(n));
  68. #ifdef __INTEL_COMPILER
  69. #pragma warning pop
  70. #endif
  71. // lower_bound is a lower bound on
  72. // ||inv(matrix)||_1 = sup_v ||inv(matrix) v||_1 / ||v||_1
  73. // and is the objective maximized by the ("super-") gradient ascent
  74. // algorithm below.
  75. RealScalar lower_bound = v.template lpNorm<1>();
  76. if (n == 1)
  77. return lower_bound;
  78. // Gradient ascent algorithm follows: We know that the optimum is achieved at
  79. // one of the simplices v = e_i, so in each iteration we follow a
  80. // super-gradient to move towards the optimal one.
  81. RealScalar old_lower_bound = lower_bound;
  82. Vector sign_vector(n);
  83. Vector old_sign_vector;
  84. Index v_max_abs_index = -1;
  85. Index old_v_max_abs_index = v_max_abs_index;
  86. for (int k = 0; k < 4; ++k)
  87. {
  88. sign_vector = internal::rcond_compute_sign<Vector, RealVector, is_complex>::run(v);
  89. if (k > 0 && !is_complex && sign_vector == old_sign_vector) {
  90. // Break if the solution stagnated.
  91. break;
  92. }
  93. // v_max_abs_index = argmax |real( inv(matrix)^T * sign_vector )|
  94. v = dec.adjoint().solve(sign_vector);
  95. v.real().cwiseAbs().maxCoeff(&v_max_abs_index);
  96. if (v_max_abs_index == old_v_max_abs_index) {
  97. // Break if the solution stagnated.
  98. break;
  99. }
  100. // Move to the new simplex e_j, where j = v_max_abs_index.
  101. v = dec.solve(Vector::Unit(n, v_max_abs_index)); // v = inv(matrix) * e_j.
  102. lower_bound = v.template lpNorm<1>();
  103. if (lower_bound <= old_lower_bound) {
  104. // Break if the gradient step did not increase the lower_bound.
  105. break;
  106. }
  107. if (!is_complex) {
  108. old_sign_vector = sign_vector;
  109. }
  110. old_v_max_abs_index = v_max_abs_index;
  111. old_lower_bound = lower_bound;
  112. }
  113. // The following calculates an independent estimate of ||matrix||_1 by
  114. // multiplying matrix by a vector with entries of slowly increasing
  115. // magnitude and alternating sign:
  116. // v_i = (-1)^{i} (1 + (i / (dim-1))), i = 0,...,dim-1.
  117. // This improvement to Hager's algorithm above is due to Higham. It was
  118. // added to make the algorithm more robust in certain corner cases where
  119. // large elements in the matrix might otherwise escape detection due to
  120. // exact cancellation (especially when op and op_adjoint correspond to a
  121. // sequence of backsubstitutions and permutations), which could cause
  122. // Hager's algorithm to vastly underestimate ||matrix||_1.
  123. Scalar alternating_sign(RealScalar(1));
  124. for (Index i = 0; i < n; ++i) {
  125. // The static_cast is needed when Scalar is a complex and RealScalar implements expression templates
  126. v[i] = alternating_sign * static_cast<RealScalar>(RealScalar(1) + (RealScalar(i) / (RealScalar(n - 1))));
  127. alternating_sign = -alternating_sign;
  128. }
  129. v = dec.solve(v);
  130. const RealScalar alternate_lower_bound = (2 * v.template lpNorm<1>()) / (3 * RealScalar(n));
  131. return numext::maxi(lower_bound, alternate_lower_bound);
  132. }
  133. /** \brief Reciprocal condition number estimator.
  134. *
  135. * Computing a decomposition of a dense matrix takes O(n^3) operations, while
  136. * this method estimates the condition number quickly and reliably in O(n^2)
  137. * operations.
  138. *
  139. * \returns an estimate of the reciprocal condition number
  140. * (1 / (||matrix||_1 * ||inv(matrix)||_1)) of matrix, given ||matrix||_1 and
  141. * its decomposition. Supports the following decompositions: FullPivLU,
  142. * PartialPivLU, LDLT, and LLT.
  143. *
  144. * \sa FullPivLU, PartialPivLU, LDLT, LLT.
  145. */
  146. template <typename Decomposition>
  147. typename Decomposition::RealScalar
  148. rcond_estimate_helper(typename Decomposition::RealScalar matrix_norm, const Decomposition& dec)
  149. {
  150. typedef typename Decomposition::RealScalar RealScalar;
  151. eigen_assert(dec.rows() == dec.cols());
  152. if (dec.rows() == 0) return NumTraits<RealScalar>::infinity();
  153. if (matrix_norm == RealScalar(0)) return RealScalar(0);
  154. if (dec.rows() == 1) return RealScalar(1);
  155. const RealScalar inverse_matrix_norm = rcond_invmatrix_L1_norm_estimate(dec);
  156. return (inverse_matrix_norm == RealScalar(0) ? RealScalar(0)
  157. : (RealScalar(1) / inverse_matrix_norm) / matrix_norm);
  158. }
  159. } // namespace internal
  160. } // namespace Eigen
  161. #endif