You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Median.hpp 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. ///-------------------------------------------------------------------------------------------------
  2. ///
  3. /// \file Median.hpp
  4. /// \brief All Median functions for array or matrix.
  5. /// \author Thibaut Monseigne (Inria).
  6. /// \version 1.0.
  7. /// \date 29/07/2020.
  8. /// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
  9. /// \remarks This algortihms is inspired by the plugin clean_rawdata in <a href="https://sccn.ucsd.edu/eeglab/index.php">EEGLAB</a> (<a href="https://github.com/sccn/clean_rawdata/blob/master/LICENSE">License</a>).
  10. ///
  11. ///-------------------------------------------------------------------------------------------------
  12. #pragma once
  13. #include <Eigen/Dense>
  14. #include <vector>
  15. #include "geometry/Metrics.hpp"
  16. namespace Geometry {
  17. //---------------------------------------------------------------------------
  18. //------------------------------ Matrix Median ------------------------------
  19. //---------------------------------------------------------------------------
  20. //-------------------------------------------------------------------------------------------------
  21. /// <summary> Find the median of stl vector. </summary>
  22. /// <typeparam name="T"> The type of the values (only arithmetic type). </typeparam>
  23. /// <param name="v"> the vector of values. </param>
  24. /// <returns> The median of vector. </returns>
  25. template <typename T, typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
  26. T Median(const std::vector<T>& v)
  27. {
  28. std::vector<T> tmp = v;
  29. const size_t n = tmp.size() / 2; // Where is the middle (if odd number of value the decimal part is floor by cast)
  30. std::stable_sort(tmp.begin(), tmp.end()); // We sort all because nth_element doesn't have same behaviour in Windows and Unix
  31. return (tmp.size() % 2 == 0) ? (tmp[n] + tmp[n - 1]) / 2 : tmp[n]; // For Even number of value we take the mean of the two middle value
  32. }
  33. //-------------------------------------------------------------------------------------------------
  34. //-------------------------------------------------------------------------------------------------
  35. /// <summary> Find the median of values of the Eigen Matrix. </summary>
  36. /// <param name="m"> the matrix. </param>
  37. /// <returns> The median of matrix. </returns>
  38. double Median(const Eigen::MatrixXd& m);
  39. //-------------------------------------------------------------------------------------------------
  40. //-------------------------------------------------------------------------------------------------
  41. /// <summary> Compute the median of vector of matrix with the Weiszfeld's algorithm. <br/>
  42. /// To compute this median, we start by computing the initial median of the dataset by taking each element of the matrices independently.
  43. /// That is to say that for the element at position i, j(a_i, j) of the matrices, we computes the median of the elements a_i, j of all the matrices of the dataset.
  44. /// We thus have an initial median for our dataset. <br/>
  45. /// Then, we refine our median by the iterative algorithm of Weiszfeld:
  46. /// - We remove the median in our dataset.
  47. /// - For each new matrices, we compute the norm.
  48. /// - We sum the the matrices in initial dataset (divided by their own norm) and we normalize the result by the sum of inverse norms.
  49. /// - We iterate this previous step until we have a difference between the old and new median is under an epsilon or that the number of iterations is above the limit.
  50. /// </summary>
  51. /// <param name="matrices"> Vector of Matrix. </param>
  52. /// <param name="median"> The computed median. </param>
  53. /// <param name="epsilon"> (Optional) The epsilon value to stop algorithm. </param>
  54. /// <param name="maxIter"> (Optional) The maximum iteration allowed to find best Median. </param>
  55. /// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
  56. /// <remarks> it's an iterative algorithm, so we have a limit of iterations and an epsilon value to consider the calculation as satisfactory. </remarks>
  57. bool MedianEuclidian(const std::vector<Eigen::MatrixXd>& matrices, Eigen::MatrixXd& median, const double epsilon = 0.0001, const size_t maxIter = 50);
  58. //-------------------------------------------------------------------------------------------------
  59. //-------------------------------------------------------------------------------------------------
  60. /// <summary> Compute the median of vector of matrix with the Riemman Barycentre. <br/>
  61. /// - Initialize the median with the euclidian mean of matrices.
  62. /// - Iterate until the stop criterion (<c>iteration</c> over <c>maxIter</c> or \f$\text{gain}\f$ under <c>epsilon</c>).
  63. /// - Compute the tangent space projection of each matrices with median as reference.
  64. /// - Compute the sum (\f$\mathcal{S}\f$) of euclidian distance of each tangent space projection. <br/>
  65. /// \f[ \delta_E=\sqrt{\sum_{i \in N}{x_i^2}} \quad \text{with } x_i \text{ the feature } i \text{ of the tangent space projection}\f]
  66. /// - Compare with previous sum and stop if \f$\text{gain} < \varepsilon\f$. <br/>
  67. /// \f[ \text{gain} = \left|\frac{\mathcal{S} - \mathcal{S}_\text{prev}}{\mathcal{S}_\text{prev}}\right| \f]
  68. /// - Compute Median of each feature \f$i\f$ of tangent space projection.
  69. /// - Transform this tangent space projection median to riemann space with previous median as reference and update the median by this new matrix.
  70. /// </summary>
  71. /// <param name="matrices"> Vector of Matrix. </param>
  72. /// <param name="median"> The computed median. </param>
  73. /// <param name="epsilon"> (Optional) The epsilon value to stop algorithm. </param>
  74. /// <param name="maxIter"> (Optional) The maximum iteration allowed to find best Median. </param>
  75. /// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
  76. bool MedianRiemann(const std::vector<Eigen::MatrixXd>& matrices, Eigen::MatrixXd& median, const double epsilon = 0.0001, const size_t maxIter = 50);
  77. //-------------------------------------------------------------------------------------------------
  78. //-------------------------------------------------------------------------------------------------
  79. /// <summary> Give the identity matrix has median. </summary>
  80. /// <param name="matrices"> Vector of Matrix. </param>
  81. /// <param name="median"> The computed median. </param>
  82. /// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
  83. bool MedianIdentity(const std::vector<Eigen::MatrixXd>& matrices, Eigen::MatrixXd& median);
  84. //-------------------------------------------------------------------------------------------------
  85. //-------------------------------------------------------------------------------------------------
  86. /// <summary> Compute the median of vector of matrix with the Weiszfeld's algorithm for Euclidian Metric and Riemman Barycentre. </summary>
  87. /// <param name="matrices"> Vector of Matrix. </param>
  88. /// <param name="median"> The computed median. </param>
  89. /// <param name="epsilon"> (Optional) The epsilon value to stop algorithm. </param>
  90. /// <param name="maxIter"> (Optional) The maximum iteration allowed to find best Median. </param>
  91. /// <param name="metric"> (Optional) THe metric to use. </param>
  92. /// <returns> <c>True</c> if it succeeds, <c>False</c> otherwise. </returns>
  93. /// <remarks> it's an iterative algorithm, so we have a limit of iterations and an epsilon value to consider the calculation as satisfactory. </remarks>
  94. bool Median(const std::vector<Eigen::MatrixXd>& matrices, Eigen::MatrixXd& median,
  95. const double epsilon = 0.0001, const size_t maxIter = 50, const EMetric& metric = EMetric::Euclidian);
  96. //-------------------------------------------------------------------------------------------------
  97. } // namespace Geometry