$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
stats.hh
1 #ifndef STATS_HH_
2 # define STATS_HH_
3 
4 # include <vector>
5 # include <algorithm>
6 
7 # include <mln/util/array.hh>
8 
9 using namespace mln;
10 
11 //---------------------------------------------------------------------------
12 // compare_values
13 //---------------------------------------------------------------------------
14 
15 template< typename T >
17 {
18  bool operator() (const T& lhs,
19  const T& rhs)
20  {
21  return (lhs < rhs);
22  }
23 };
24 
25 
26 //---------------------------------------------------------------------------
27 // cluster_stats
28 //---------------------------------------------------------------------------
29 
30 template< typename T >
32 {
33 public:
35  : mean_needs_update_(false), median_needs_update_(false),
36  variance_needs_update_(false), std_needs_update_(false), size_(0)
37  {
38  }
39 
40  cluster_stats(const unsigned size)
41  : mean_needs_update_(false), median_needs_update_(false),
42  variance_needs_update_(false), std_needs_update_(false), size_(0)
43  {
44  data_.reserve(size);
45  }
46 
47  void reset()
48  {
49  std::vector< T >& data = data_.hook_std_vector_();
50  data.clear();
51 
52  size_ = 0;
53  needs_update();
54  }
55 
56  void take(const T& value)
57  {
58  if (not size_)
59  {
60  min_ = value;
61  max_ = value;
62  }
63  else
64  {
65  if (value < min_)
66  min_ = value;
67  else if (value > max_)
68  max_ = value;
69  }
70 
71  ++size_;
72  data_.append(value);
73  needs_update();
74  }
75 
76  T mean()
77  {
78  if (mean_needs_update_)
79  {
80  mean_ = 0;
81 
82  if (size_ > 0)
83  {
84  for (unsigned i = 0; i < size_; ++i)
85  mean_ += data_[i];
86 
87  mean_ /= size_;
88  }
89  mean_needs_update_ = false;
90  }
91 
92  return mean_;
93  }
94 
95  T median()
96  {
97  if (median_needs_update_)
98  {
99  median_ = 0;
100 
101  if (size_ > 0)
102  {
103  std::vector< T >& data = data_.hook_std_vector_();
104  std::sort(data.begin(), data.end(), compare_values< T >());
105 
106  median_ = data[(size_ - 1) >> 1];
107  }
108 
109  median_needs_update_ = false;
110  }
111 
112  return median_;
113  }
114 
115  T variance()
116  {
117  if (variance_needs_update_)
118  {
119  mean();
120  variance_ = 0;
121 
122  if (size_ > 0)
123  {
124  for (unsigned i = 0; i < size_; ++i)
125  {
126  const T tmp = mean_ - data_[i];
127 
128  variance_ += (tmp * tmp);
129  }
130 
131  variance_ /= size_;
132  std_ = sqrt(variance_);
133  }
134 
135  variance_needs_update_ = false;
136  std_needs_update_ = false;
137  }
138 
139  return variance_;
140  }
141 
142  T standard_deviation()
143  {
144  if (std_needs_update_)
145  variance();
146 
147  return std_;
148  }
149 
150  T min() { return (size_ > 0) ? min_ : 0; }
151  T max() { return (size_ > 0) ? max_ : 0; }
152 
153  void sort()
154  {
155  std::vector< T >& data = data_.hook_std_vector_();
156  std::sort(data.begin(), data.end(), compare_values< T >());
157  }
158 
159  unsigned nelements() { return size_; }
160 
161  T operator[] (const unsigned index)
162  {
163  return data_[index];
164  }
165 
166 private:
167  void needs_update()
168  {
169  mean_needs_update_ = true;
170  median_needs_update_ = true;
171  variance_needs_update_ = true;
172  std_needs_update_ = true;
173  }
174 
175 private:
176  bool mean_needs_update_ : 1;
177  bool median_needs_update_ : 1;
178  bool variance_needs_update_ : 1;
179  bool std_needs_update_ : 1;
180  T mean_;
181  T median_;
182  T min_;
183  T max_;
184  T variance_;
185  T std_;
186  unsigned size_;
187  util::array< T > data_;
188 };
189 
190 //---------------------------------------------------------------------------
191 // stats
192 //---------------------------------------------------------------------------
193 
194 template< typename T >
195 class stats
196 {
197 public:
198  stats()
199  : clusters_need_update_(true), data_sorted_(false)
200  {
201  }
202 
203  stats(const int size)
204  : clusters_need_update_(true), data_sorted_(false), data_(size)
205  {
206  }
207 
208  void reset()
209  {
210  data_.reset();
211  std::vector< cluster_stats< T > >& clusters = clusters_.hook_std_vector_();
212  clusters.clear();
213  data_sorted_ = false;
214  clusters_need_update_ = true;
215  }
216 
217  void take(const T& value)
218  {
219  data_.take(value);
220  clusters_need_update_ = true;
221  }
222 
223  T mean()
224  {
225  return data_.mean();
226  }
227 
228  T median()
229  {
230  return data_.median();
231  }
232 
233  T variance()
234  {
235  return data_.variance();
236  }
237 
238  T standard_deviation()
239  {
240  return data_.standard_deviation();
241  }
242 
243  T min() { return data_.min(); }
244  T max() { return data_.max(); }
245 
246  unsigned nelements() { return data_.nelements(); }
247 
248  util::array< cluster_stats< T > >& clusters()
249  {
250  if (clusters_need_update_)
251  {
252  compute_clusters();
253  clusters_need_update_ = false;
254  }
255 
256  return clusters_;
257  }
258 
259 private:
260  void compute_clusters()
261  {
262  std::vector< unsigned > clusters;
263  unsigned cluster_index = 1;
264 
265  clusters.reserve(data_.nelements());
266 
267  if (not data_sorted_)
268  {
269  data_.sort();
270  data_sorted_ = true;
271  }
272 
273  unsigned i = 0;
274  const unsigned nelements = data_.nelements();
275 
276  clusters.push_back(cluster_index);
277  const T std = data_.standard_deviation();
278 
279  for (i = 1; i < nelements - 1; ++i)
280  {
281  const T left_distance = data_[i] - data_[i - 1];
282  const T right_distance = data_[i + 1] - data_[i];
283 
284  if (not ((left_distance <= 1 || left_distance < right_distance)
285  && left_distance <= std))
286  ++cluster_index;
287 
288  clusters.push_back(cluster_index);
289  }
290 
291  if (nelements > 1)
292  {
293  if (data_[i] - data_[i - 1] > std)
294  ++cluster_index;
295  clusters.push_back(cluster_index);
296  }
297 
298  clusters_.clear();
299  clusters_.reserve(cluster_index);
300  cluster_index = 1;
301 
302  i = 0;
303  while (i < nelements)
304  {
305  unsigned tmp = i;
306 
307  while (tmp < nelements && clusters[tmp] == clusters[i])
308  ++tmp;
309 
310  cluster_stats< T > cluster(tmp - i);
311 
312  tmp = i;
313  while (tmp < nelements && clusters[tmp] == clusters[i])
314  {
315  cluster.take(data_[tmp]);
316  ++tmp;
317  }
318 
319  clusters_.append(cluster);
320 
321  i = tmp;
322  ++cluster_index;
323  }
324  }
325 
326 private:
327  bool clusters_need_update_ : 1;
328  bool data_sorted_ : 1;
329  cluster_stats< T > data_;
330  util::array< cluster_stats< T > > clusters_;
331 };
332 
333 #endif /* STATS_HH_ */