1 // This is mul/mbl/mbl_histogram.cxx
2 #include <iostream>
3 #include <cmath>
4 #include "mbl_histogram.h"
5 //:
6 // \file
7 // \brief Simple object to build histogram from supplied data.
8 // \author Tim Cootes
9 
10 #ifdef _MSC_VER
11 #  include "vcl_msvc_warnings.h"
12 #endif
13 #include <cassert>
14 #include "vsl/vsl_vector_io.h"
15 
mbl_histogram()16 mbl_histogram::mbl_histogram()
17 {
18   clear();
19 }
20 
21 // Construct with given number of bins over given range
mbl_histogram(double x_lo,double x_hi,int n_bins)22 mbl_histogram::mbl_histogram(double x_lo, double x_hi, int n_bins)
23 {
24   set_bins(x_lo,x_hi,n_bins);
25 }
26 
27 //: Define number and size of bins
set_bins(double xlo,double xhi,int n_bins)28 void mbl_histogram::set_bins(double xlo, double xhi, int n_bins)
29 {
30   assert(n_bins>0);
31   assert(xhi>xlo);
32 
33   bins_.resize(n_bins+1);
34   freq_.resize(n_bins);
35 
36   double dx = (xhi-xlo)/n_bins;
37   for (int i=0;i<=n_bins;++i) bins_[i]=xlo+i*dx;
38   clear();
39 }
40 
clear()41 void mbl_histogram::clear()
42 {
43   n_obs_ = 0;
44   n_below_ = 0;
45   n_above_ = 0;
46   for (int & i : freq_) i=0;
47 }
48 
obs(double v)49 void mbl_histogram::obs(double v)
50 {
51   n_obs_++;
52   if (v<bins_[0])
53   {
54     n_below_++;
55     return;
56   }
57 
58   int n = freq_.size();
59 
60   for (int i=1;i<=n;++i)
61   {
62     if (v<bins_[i])
63     {
64       freq_[i-1]++;
65       return;
66     }
67   }
68 
69   // Not in any bin
70   n_above_++;
71 }
72 
73 
74 const double MAX_ERROR = 1.0e-8;
75 
76 //: Test for equality
operator ==(const mbl_histogram & s) const77 bool mbl_histogram::operator==(const mbl_histogram& s) const
78 {
79   if (s.n_bins()!=n_bins()) return false;
80   if (s.n_obs_ != n_obs_) return false;
81   if (s.n_below_!=n_below_) return false;
82   if (s.n_above_!=n_above_) return false;
83 
84   int n = n_bins();
85   for (int i=0;i<n;++i)
86     if (s.freq_[i]!=freq_[i]) return false;
87   for (int i=0;i<=n;++i)
88     if (std::fabs(s.bins_[i]-bins_[i])>MAX_ERROR) return false;
89 
90   return true;
91 }
92 
93 //: Version number for I/O
version_no() const94 short mbl_histogram::version_no() const
95 {
96   return 1;
97 }
98 
b_write(vsl_b_ostream & bfs) const99 void mbl_histogram::b_write(vsl_b_ostream& bfs) const
100 {
101   vsl_b_write(bfs,version_no());
102   vsl_b_write(bfs,n_obs_);
103   vsl_b_write(bfs,n_below_);
104   vsl_b_write(bfs,n_above_);
105   vsl_b_write(bfs,bins_);
106   vsl_b_write(bfs,freq_);
107 }
108 
b_read(vsl_b_istream & bfs)109 void mbl_histogram::b_read(vsl_b_istream& bfs)
110 {
111   if (!bfs) return;
112 
113   short file_version_no;
114   vsl_b_read(bfs,file_version_no);
115 
116   switch (file_version_no)
117   {
118    case 1:
119     vsl_b_read(bfs,n_obs_);
120     vsl_b_read(bfs,n_below_);
121     vsl_b_read(bfs,n_above_);
122     vsl_b_read(bfs,bins_);
123     vsl_b_read(bfs,freq_);
124     break;
125    default:
126     std::cerr << "I/O ERROR: mbl_histogram::b_read(vsl_b_istream&)\n"
127              << "           Unknown version number "<< file_version_no << '\n';
128     bfs.is().clear(std::ios::badbit); // Set an unrecoverable IO error on stream
129     return;
130   }
131 }
132 
print_summary(std::ostream & os) const133 void mbl_histogram::print_summary(std::ostream& os) const
134 {
135   os << "mbl_histogram: ";
136   if (n_bins()==0) { os<< "No bins defined."; return; }
137 
138   int n = n_bins();
139 
140   if (n_obs_==0)
141     os << "No samples.";
142   else
143   {
144     os << n_obs_ << " observations.\n"
145        << "    < "<<bins_[0]<<"   "<<n_below_<<'\n';
146     for (int i=0;i<n;++i)
147       os<<"  ["<<bins_[i]<<','<<bins_[i+1]<<")  "<<freq_[i]<<'\n';
148     os << "   >= "<<bins_[n]<<"   "<<n_above_<<'\n';
149   }
150 }
151 
152 //: Write out histogram probabilities to a named file
153 //  Format: (bin-centre) prob     (one per line)
154 // \return true if successful
write_probabilities(const char * path)155 bool mbl_histogram::write_probabilities(const char* path)
156 {
157   int n = n_bins();
158   if (n==0) return false;
159 
160   std::ofstream ofs(path);
161   if (!ofs) return false;
162   for (int i=0;i<n_bins();++i)
163   {
164     double dx=std::fabs(bins_[i+1]-bins_[i]);
165     ofs<<0.5*(bins_[i]+bins_[i+1])<<"  "<<double(freq_[i])/(dx*n_obs_)<<'\n';
166   }
167   ofs.close();
168   return true;
169 }
170 
171 //: Write out cumulative probability distribution to a named file
172 //  Format: (bin-centre) sum_prob     (one per line)
173 // \return true if successful
write_cdf(const char * path)174 bool mbl_histogram::write_cdf(const char* path)
175 {
176   int n = n_bins();
177   if (n==0) return false;
178 
179   std::ofstream ofs(path);
180   if (!ofs) return false;
181   int sum=n_below_;
182   for (int i=0;i<n_bins();++i)
183   {
184     sum+=freq_[i];
185     ofs<<0.5*(bins_[i]+bins_[i+1])<<"  "<<double(sum)/n_obs_<<'\n';
186   }
187   ofs.close();
188   return true;
189 }
190 
operator <<(std::ostream & os,const mbl_histogram & histo)191 std::ostream& operator<<(std::ostream& os, const mbl_histogram& histo)
192 {
193   histo.print_summary(os);
194   return os;
195 }
196 
197   //: Stream output operator for class reference
vsl_print_summary(std::ostream & os,const mbl_histogram & histo)198 void vsl_print_summary(std::ostream& os,const mbl_histogram& histo)
199 {
200   histo.print_summary(os);
201 }
202 
203   //: Binary file stream output operator for class reference
vsl_b_write(vsl_b_ostream & bfs,const mbl_histogram & h)204 void vsl_b_write(vsl_b_ostream& bfs, const mbl_histogram& h)
205 {
206   h.b_write(bfs);
207 }
208 
209   //: Binary file stream input operator for class reference
vsl_b_read(vsl_b_istream & bfs,mbl_histogram & h)210 void vsl_b_read(vsl_b_istream& bfs, mbl_histogram& h)
211 {
212   h.b_read(bfs);
213 }
214