contrib/mul/mbl/mbl_select_n_from_m.cxx
Go to the documentation of this file.
00001 //:
00002 // \file
00003 // \brief A class which returns an N element subset of the integers [0..M-1]
00004 // \author Tim Cootes
00005 
00006 #include "mbl_select_n_from_m.h"
00007 #include <vcl_cassert.h>
00008 #include <vcl_iostream.h>
00009 
00010 mbl_select_n_from_m::mbl_select_n_from_m()
00011  : n_(0), m_(0), is_done_(false), use_random_(false)
00012 {
00013   random_.reseed(123746);
00014 }
00015 
00016 mbl_select_n_from_m::mbl_select_n_from_m(unsigned int new_n, unsigned int new_m)
00017  : n_(new_n), m_(new_m), is_done_(false), use_random_(false)
00018 {
00019   set_n_m(new_n,new_m);
00020   random_.reseed(123746);
00021 }
00022 
00023 //: Reseed randomiser
00024 void mbl_select_n_from_m::reseed(long s)
00025 {
00026   random_.reseed(s);
00027 }
00028 
00029   // member functions
00030 
00031 void mbl_select_n_from_m::set_n_m(unsigned int new_n, unsigned int new_m)
00032 {
00033   if (new_n>new_m)
00034   {
00035     vcl_cerr<<"mbl_select_n_from_m::set_n_m(): Warning: N>M: nothing selected\n"
00036             <<"N="<<new_n<<"  M="<<new_m<<vcl_endl;
00037     is_done_ = true;
00038   }
00039 
00040   n_=new_n;
00041   m_=new_m;
00042   index_.resize(n_);
00043   reset();
00044 }
00045 
00046 void mbl_select_n_from_m::use_random(bool flag)
00047 {
00048   use_random_=flag;
00049 
00050   if (use_random_)
00051     random_.choose_n_from_m(index_,not_index_,n_,m_);
00052   else
00053     reset();
00054 }
00055 
00056 bool mbl_select_n_from_m::reset()
00057 {
00058   is_done_ = (n_>m_);
00059 
00060   if (is_done_)
00061     return false;
00062 
00063   if (use_random_)
00064   {
00065     random_.choose_n_from_m(index_,not_index_,n_,m_);
00066     return true;
00067   }
00068 
00069   for (unsigned int i=0;i<n_;++i)
00070     index_[i]=i;
00071 
00072   return true;
00073 }
00074 
00075 bool mbl_select_n_from_m::next()
00076 {
00077   if (is_done_) return false;
00078 
00079   if (use_random_)
00080   {
00081     random_.choose_n_from_m(index_,not_index_,n_,m_);
00082     return true;
00083   }
00084 
00085   // quick return if possible; ensures n_-1 >= 0 further down (which is used!)
00086   if (n_==m_ || n_ == 0) { is_done_=true; return false; }
00087 
00088   int* index_data = &index_[0];
00089   index_data[n_-1]++;  // Increment counter
00090 
00091   // Increment previous digit if current one has tripped over limit
00092   unsigned int low_trip_digit = n_;  // Lowest digit which has tripped
00093   int start_index=0;                 // index to start digits when trip occurs
00094   for (unsigned int j=n_-1;j>0;--j)
00095   {
00096     // index_[j] has range j..m-n+j
00097     if (index_data[j]>int(m_-n_+j))
00098     {
00099       index_data[j-1]++;
00100       low_trip_digit=j;
00101       start_index=index_data[j-1]+1;
00102       // Start one above previous digit value
00103     }
00104   }
00105 
00106   if (index_data[0]>int(m_-n_))
00107   {
00108     reset(); // to ensure valid data in index_
00109     is_done_=true;
00110     return false;
00111   }
00112   else
00113   if (low_trip_digit<n_)
00114   {
00115     // Reset those above
00116     for (unsigned int i=low_trip_digit;i<n_;i++)
00117     {
00118       index_data[i]=start_index;
00119       start_index++;
00120     }
00121   }
00122 
00123   return true;
00124 }
00125 
00126 const vcl_vector<int>& mbl_select_n_from_m::subset() const
00127 {
00128   assert (!is_done_);
00129   return index_;
00130 }
00131 
00132 const vcl_vector<int>& mbl_select_n_from_m::complement()
00133 {
00134   if (use_random_)
00135     return not_index_;
00136     // not_index_ calculated during call to next();
00137 
00138   assert (!is_done_);
00139   if (not_index_.size()!=m_-n_) not_index_.resize(m_-n_);
00140 
00141   // Fill not_index_ with values in range 0..m-1 not in index_
00142   // Use fact that index_[i+1]>index_[i]
00143   unsigned int j=0;  //index in not_index_ array
00144   unsigned int k=0;
00145   for (unsigned int i=0;i<n_;i++)
00146   {
00147     unsigned int ind_i = index_[i];
00148     while (k<ind_i)
00149     {
00150       not_index_[j]=k;
00151       j++;
00152       k++;
00153     }
00154     ++k;
00155   }
00156 
00157   // Fill out end of array
00158   while (k<m_)
00159   {
00160     not_index_[j]=k;
00161     j++;
00162     k++;
00163   }
00164 
00165   return not_index_;
00166 }