17#ifndef __math_median_h__
18#define __math_median_h__
34 inline bool not_a_number (X x) {
38 template <>
inline bool not_a_number (
float x) {
return std::isnan (x); }
39 template <>
inline bool not_a_number (
double x) {
return std::isnan (x); }
44 template <
class Container>
47 size_t num = list.size();
49 for (
size_t n = 0; n <
num; ++n) {
50 while (not_a_number (list[n]) && n <
num) {
58 return std::numeric_limits<typename Container::value_type>::quiet_NaN();
60 size_t middle =
num/2;
61 std::nth_element (list.begin(), list.begin()+middle, list.begin()+
num);
65 std::nth_element (list.begin(), list.begin()+middle, list.begin()+middle+1);
66 med_val = (med_val + list[middle])/2.0;
73 template <
class MatrixType = Eigen::Matrix<default_type, 3, Eigen::Dynamic>,
class VectorType = Eigen::Matrix<default_type, 3, 1>>
75 assert(X.cols() >= 2 &&
"cannot compute weiszfeld median for less than two points");
76 assert(X.rows() >= 2 &&
"weisfeld median for one dimensional data is not unique. did you mean the median?");
77 const size_t dimensionality = X.rows();
80 assert(
median.rows() >= 2);
81 assert(
median.rows() == X.rows());
82 median = X.transpose().colwise().mean();
85 size_t n = (X.colwise() -
median).colwise().squaredNorm().nonZeros();
87 median(0) += 10 * precision;
88 n = (X.colwise() -
median).colwise().squaredNorm().nonZeros();
91 bool convergence =
false;
96 Eigen::Matrix<default_type, Eigen::Dynamic, 1> s1;
97 s1.resize(dimensionality,1);
98 while ( !convergence && (i < numIter) ) {
103 for (
size_t j = 0; j < m; ++j){
104 norm = (X.col(j) -
median).norm();
105 s1 += X.col(j) / norm;
110 if (denum == 0.0 or std::isnan(denum)){
111 WARN (
"Could not compute geometric median!" );
117 convergence=(
abs(dist[i]-dist[i-2])<precision);
122 WARN (
"Weiszfeld's median algorithm did not converge after "+
str(numIter)+
" iterations");
MR::default_type value_type
bool median_weiszfeld(const MatrixType &X, VectorType &median, const size_t numIter=300, const default_type precision=0.00001)
Container::value_type median(Container &list)
double default_type
the default type used throughout MRtrix
constexpr std::enable_if< std::is_arithmetic< X >::value &&std::is_unsigned< X >::value, X >::type abs(X x)
std::string str(const T &value, int precision=0)