• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List

median_h.hh

00001 // Copyright (C) 2007, 2008, 2009 EPITA Research and Development Laboratory (LRDE)
00002 //
00003 // This file is part of Olena.
00004 //
00005 // Olena is free software: you can redistribute it and/or modify it under
00006 // the terms of the GNU General Public License as published by the Free
00007 // Software Foundation, version 2 of the License.
00008 //
00009 // Olena is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with Olena.  If not, see <http://www.gnu.org/licenses/>.
00016 //
00017 // As a special exception, you may use this file as part of a free
00018 // software project without restriction.  Specifically, if other files
00019 // instantiate templates or use macros or inline functions from this
00020 // file, or you compile this file and link it with other files to produce
00021 // an executable, this file does not by itself cause the resulting
00022 // executable to be covered by the GNU General Public License.  This
00023 // exception does not however invalidate any other reasons why the
00024 // executable file might be covered by the GNU General Public License.
00025 
00026 #ifndef MLN_ACCU_STAT_MEDIAN_H_HH
00027 # define MLN_ACCU_STAT_MEDIAN_H_HH
00028 
00032 
00033 # include <mln/accu/internal/base.hh>
00034 # include <mln/accu/histo.hh>
00035 # include <mln/value/set.hh>
00036 
00037 
00038 namespace mln
00039 {
00040 
00041   namespace accu
00042   {
00043 
00044     namespace stat
00045     {
00046 
00047       // Forward declaration.
00048       template <typename V>
00049       struct median_h;
00050 
00051     } // end of namespace mln::accu::stat
00052 
00053     namespace meta
00054     {
00055 
00056       namespace stat
00057       {
00058 
00060         struct median_h : public Meta_Accumulator< median_h >
00061         {
00062           template <typename V>
00063           struct with
00064           {
00065             typedef accu::stat::median_h<V> ret;
00066           };
00067         };
00068 
00069       } // end of namespace mln::accu::meta::stat
00070 
00071     } // end of namespace mln::accu::meta
00072 
00073     namespace stat
00074     {
00075 
00080       template <typename V>
00081       struct median_h : public mln::accu::internal::base< const V&, median_h<V> >
00082       {
00083         typedef V argument;
00084 
00085         median_h();
00086 
00089         void init();
00090         void   take(const argument& t);
00091         void   take(const median_h<V>& other);
00092         void untake(const argument& t);
00094 
00095         unsigned card() const { return h_.sum(); }
00096 
00098         const argument& to_result() const;
00099 
00100         const accu::histo<V>& histo() const;
00101 
00104         bool is_valid() const;
00105 
00106       protected:
00107 
00108         mutable accu::histo<V> h_;
00109         const value::set<V>& s_;        // derived from h_
00110 
00111         mutable unsigned sum_minus_, sum_plus_;
00112 
00113         mutable bool valid_;
00114         mutable unsigned i_;    // the median_h index
00115         mutable argument t_;    // the median_h value
00116 
00117         // Auxiliary methods
00118         void update_() const;
00119         void go_minus_() const;
00120         void go_plus_() const;
00121       };
00122 
00123 # ifndef MLN_INCLUDE_ONLY
00124 
00125       template <typename V>
00126       inline
00127       median_h<V>::median_h()
00128         : h_(),
00129           s_(h_.vset())
00130       {
00131         init();
00132       }
00133 
00134       template <typename V>
00135       inline
00136       void
00137       median_h<V>::take(const argument& t)
00138       {
00139         h_.take(t);
00140 
00141         if (t < t_)
00142           ++sum_minus_;
00143         else if (t > t_)
00144           ++sum_plus_;
00145 
00146         if (valid_)
00147           valid_ = false;
00148       }
00149 
00150       template <typename V>
00151       inline
00152       void
00153       median_h<V>::take(const median_h<V>& other)
00154       {
00155         // h_
00156         h_.take(other.h_);
00157 
00158         // sum_minus_
00159         for (unsigned i = 0; i < i_; ++i)
00160           sum_minus_ += other.h_[i];
00161 
00162         // sum_plus_
00163         for (unsigned i = i_ + 1; i < h_.nvalues(); ++i)
00164           sum_plus_ += other.h_[i];
00165 
00166         if (valid_)
00167           valid_ = false;
00168       }
00169 
00170       template <typename V>
00171       inline
00172       void
00173       median_h<V>::untake(const argument& t)
00174       {
00175         mln_precondition(h_(t) != 0);
00176         h_.untake(t);
00177 
00178         if (t < t_)
00179           --sum_minus_;
00180         else if (t > t_)
00181           --sum_plus_;
00182 
00183         if (valid_)
00184           valid_ = false;
00185       }
00186 
00187       template <typename V>
00188       inline
00189       void
00190       median_h<V>::update_() const
00191       {
00192         valid_ = true;
00193 
00194         if (h_.sum() == 0)
00195           return;
00196 
00197         if (2 * sum_minus_ > h_.sum())
00198           go_minus_();
00199         else
00200           if (2 * sum_plus_ > h_.sum())
00201             go_plus_();
00202           else
00203             if (h_[i_] == 0)
00204               {
00205                 // go to the heaviest side
00206                 if (sum_plus_ > sum_minus_)
00207                   go_plus_();
00208                 else
00209                   go_minus_(); // default when both sides are balanced
00210               }
00211       }
00212 
00213       template <typename V>
00214       inline
00215       void
00216       median_h<V>::go_minus_() const
00217       {
00218         do
00219           {
00220             sum_plus_ += h_[i_];
00221             do
00222               --i_;
00223             while (h_[i_] == 0);
00224             sum_minus_ -= h_[i_];
00225           }
00226         while (2 * sum_minus_ > h_.sum());
00227         t_ = s_[i_];
00228       }
00229 
00230       template <typename V>
00231       inline
00232       void
00233       median_h<V>::go_plus_() const
00234       {
00235         do
00236           {
00237             sum_minus_ += h_[i_];
00238             do
00239               ++i_;
00240             while (h_[i_] == 0);
00241             sum_plus_ -= h_[i_];
00242           }
00243         while (2 * sum_plus_ > h_.sum());
00244         t_ = s_[i_];
00245       }
00246 
00247       template <typename V>
00248       inline
00249       void
00250       median_h<V>::init()
00251       {
00252         h_.init();
00253         sum_minus_ = 0;
00254         sum_plus_ = 0;
00255         i_ = (s_.index_of(mln_max(argument))
00256               - s_.index_of(mln_min(argument))) / 2;
00257         t_ = s_[i_];
00258         valid_ = true;
00259       }
00260 
00261       template <typename V>
00262       inline
00263       const typename median_h<V>::argument&
00264       median_h<V>::to_result() const
00265       {
00266         if (! valid_)
00267           update_();
00268         return t_;
00269       }
00270 
00271       template <typename V>
00272       inline
00273       const accu::histo<V>&
00274       median_h<V>::histo() const
00275       {
00276         return h_;
00277       }
00278 
00279       template <typename V>
00280       inline
00281       bool
00282       median_h<V>::is_valid() const
00283       {
00284         return true;
00285       }
00286 
00287 # endif // ! MLN_INCLUDE_ONLY
00288 
00289     } // end of namespace mln::accu::stat
00290 
00291   } // end of namespace mln::accu
00292 
00293 } // end of namespace mln
00294 
00295 #endif // ! MLN_ACCU_STAT_MEDIAN_H_HH

Generated on Thu Sep 8 2011 18:32:07 for Milena (Olena) by  doxygen 1.7.1