Milena (Olena)  User documentation 2.0a Id
 All Classes Namespaces Functions Variables Typedefs Enumerator Groups Pages
median_alt.hh
1 // Copyright (C) 2007, 2008, 2009 EPITA Research and Development
2 // Laboratory (LRDE)
3 //
4 // This file is part of Olena.
5 //
6 // Olena is free software: you can redistribute it and/or modify it under
7 // the terms of the GNU General Public License as published by the Free
8 // Software Foundation, version 2 of the License.
9 //
10 // Olena is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Olena. If not, see <http://www.gnu.org/licenses/>.
17 //
18 // As a special exception, you may use this file as part of a free
19 // software project without restriction. Specifically, if other files
20 // instantiate templates or use macros or inline functions from this
21 // file, or you compile this file and link it with other files to produce
22 // an executable, this file does not by itself cause the resulting
23 // executable to be covered by the GNU General Public License. This
24 // exception does not however invalidate any other reasons why the
25 // executable file might be covered by the GNU General Public License.
26 
27 #ifndef MLN_ACCU_STAT_MEDIAN_ALT_HH
28 # define MLN_ACCU_STAT_MEDIAN_ALT_HH
29 
33 
34 # include <mln/accu/internal/base.hh>
35 # include <mln/accu/histo.hh>
36 
37 
38 namespace mln
39 {
40 
41  namespace accu
42  {
43 
44  namespace stat
45  {
46 
47 
52  //
53  template <typename S>
54  struct median_alt : public mln::accu::internal::base< const mln_value(S)&, median_alt<S> >
55  {
56  typedef mln_value(S) argument;
57 
58  median_alt(const Value_Set<S>& s);
59 
62  void take(const argument& t);
63  void untake(const argument& t);
64  void init();
66 
68  const argument& to_result() const;
69 
72  bool is_valid() const;
73 
74  // FIXME: remove
75  void debug__() const
76  {
77  std::cout << " i = " << i_
78  << " t = " << t_
79  << " s = " << sum_minus_ << " ; " << h_[i_] << " ; " << sum_plus_ << " = " << h_.sum()
80  << std::endl;
81  }
82 
83  protected:
84 
85  histo<S> h_;
87  const S& s_;
88 
89  unsigned sum_minus_, sum_plus_;
90 
92  unsigned i_;
94  argument t_;
95 
96  // Auxiliary methods
97  void go_minus_();
98  void go_plus_();
99  };
100 
101  template <typename T>
102  struct median_alt_on : public median_alt< value::set<T> >
103  {
104  median_alt_on()
105  : median_alt< value::set<T> >(value::set<T>::the())
106  {
107  }
108  };
109 
110  } // end of mln::accu::stat
111 
112 
113  namespace meta
114  {
115 
116  namespace stat
117  {
118 
120 
121  template <typename T>
122  struct median_alt : public Meta_Accumulator< median_alt<T> >
123  {
124  median_alt(const Value_Set<T>& s_) : s(s_) {}
125 
126  struct with
127  {
128  typedef accu::stat::median_alt<T> ret;
129  };
130 
131  Value_Set<T> s;
132  };
133 
134  } // end of namespace mln::accu::meta::stat
135 
136  } // end of namespace mln::accu::meta
137 
138 
139  template <typename T>
141  {
142  stat::median_alt<T> a(m.s);
143  return a;
144  }
145 
146 
147 # ifndef MLN_INCLUDE_ONLY
148 
149  namespace stat
150  {
151 
152  template <typename S>
153  inline
154  median_alt<S>::median_alt(const Value_Set<S>& s)
155  : h_(s),
156  s_(h_.vset())
157  {
158  init();
159  }
160 
161 
162  template <typename S>
163  inline
164  void
165  median_alt<S>::take(const argument& t)
166  {
167  // update h_
168  h_.take(t);
169 
170  // particular case:
171  // current state was initialization
172  if (h_[i_] == 0)
173  {
174  // std::cout << "init!" << std::endl;
175  i_ = s_.index_of(t);
176  t_ = t;
177  return;
178  }
179 
180  // particular case:
181  // the median does not change
182  if (t == t_)
183  {
184  // std::cout << "no change!" << std::endl;
185  return;
186  }
187 
188  // general case:
189 
190  if (t < t_)
191  {
192  ++sum_minus_;
193  if (2 * sum_minus_ > h_.sum())
194  go_minus_();
195  }
196  else
197  // t > t_
198  {
199  ++sum_plus_;
200  if (2 * sum_plus_ > h_.sum())
201  go_plus_();
202  }
203  }
204 
205 
206  template <typename S>
207  inline
208  void
209  median_alt<S>::untake(const argument& t)
210  {
211  mln_precondition(h_(t) != 0);
212 
213  // update h_
214  h_.untake(t);
215 
216  // particular case:
217  // the only value has been removed
218  if (h_.sum() == 0)
219  {
220  init();
221  return;
222  }
223 
224  // general case:
225  if (t < t_)
226  {
227  --sum_minus_;
228  if (2 * sum_plus_ > h_.sum())
229  go_plus_();
230  }
231  else if (t > t_)
232  {
233  --sum_plus_;
234  if (2 * sum_minus_ > h_.sum())
235  go_minus_();
236  }
237  else
238  // t == t_
239  {
240  if (h_[i_] == 0)
241  {
242  // go to the heaviest side
243  if (sum_plus_ > sum_minus_)
244  go_plus_();
245  else
246  go_minus_(); // default when both sides are balanced
247  }
248  else
249  {
250  if (2 * sum_plus_ > h_.sum())
251  go_plus_();
252  else if (2 * sum_minus_ > h_.sum())
253  go_minus_();
254  // else no change
255  }
256  }
257  }
258 
259  template <typename S>
260  inline
261  void
262  median_alt<S>::init()
263  {
264  h_.init();
265  sum_minus_ = 0;
266  sum_plus_ = 0;
267  i_ = (mln_max(argument) - mln_min(argument)) / 2;
268  t_ = s_[i_];
269  }
270 
271  template <typename S>
272  inline
273  const typename median_alt<S>::argument&
275  {
276  return t_;
277  }
278 
279  template <typename S>
280  inline
281  bool
283  {
284  return true;
285  }
286 
287  template <typename S>
288  inline
289  void
291  {
292  do
293  {
294  sum_plus_ += h_[i_];
295  do
296  --i_;
297  while (h_[i_] == 0);
298  sum_minus_ -= h_[i_];
299  }
300  while (2 * sum_minus_ > h_.sum());
301  t_ = s_[i_];
302  }
303 
304 
305  template <typename S>
306  inline
307  void
308  median_alt<S>::go_plus_()
309  {
310  do
311  {
312  sum_minus_ += h_[i_];
313  do
314  ++i_;
315  while (h_[i_] == 0);
316  sum_plus_ -= h_[i_];
317  }
318  while (2 * sum_plus_ > h_.sum());
319  t_ = s_[i_];
320  }
321 
322  template <typename S>
323  inline
324  std::ostream& operator<<(std::ostream& ostr, const median_alt<S>& m)
325  {
326  m.debug__();
327  return ostr << m.to_result();
328  }
329 
330  } // end of namespace mln::accu::stat
331 
332 # endif // ! MLN_INCLUDE_ONLY
333 
334  } // end of namespace mln::accu
335 
336 } // end of namespace mln
337 
338 
339 #endif // ! MLN_ACCU_STAT_MEDIAN_ALT_HH