Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
MonteCarloTransform.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 #include <MathAlgo/MonteCarloTransform.hh>
26 #include <MathAlgo/SVD.hh>
27 #include <MathAlgo/Lapack.hh>
28 #include <Base/Common/CompareFloatingPoint.hh>
29 #include <Base/Debug/Exception.hh>
30 #include <Base/Math/Matrix.hh>
31 
32 #include <fstream>
33 
34 using namespace BIAS;
35 using namespace std;
36 
39  : UncertaintyTransformBase(), NumSamplesPerDimension_(100),
40  UseQuasiRandomNumbers_(true), uniformDistribution_(false)
41 {
42  NewDebugLevel("D_MCT_SAMPLES");
43  NewDebugLevel("D_MCT_WRITE_SRC_SAMPLES");
44  NewDebugLevel("D_MCT_WRITE_DST_SAMPLES");
45  NewDebugLevel("D_MCT_NUM_SAMPLES");
46  NewDebugLevel("D_MCT_EIGENVALVEC");
47  //AddDebugLevel("D_MCT_SAMPLES");
48 }
49 
50 
53 {}
54 
55 
57 Transform(const Vector<double>& src_mean,
58  const Matrix<double>& src_cov,
59  std::vector<Vector<double> >& dst_samples) const
60 {
61  int res = 0;
62  vector<Vector<double> > src_samples;
63  const int num = GetSamples_(src_mean, src_cov, src_samples);
64  dst_samples.resize(num);
65 #ifdef BIAS_DEBUG
66  ofstream of;
67  if (DebugLevelIsSet("D_MCT_WRITE_DST_SAMPLES")){
68  of.open("dst_samples.txt");
69  }
70 #endif
71 #ifdef WRITE_DST_SAMPLES
72  ofstream off("dst_samples_p4.txt");
73 #endif
74  int num_errs = 0;
75  for (int i=0; i<num; i++){
76  if ((res = Transform_(src_samples[i], dst_samples[i-num_errs]))!=0){
77  //BIASERR("error transforming "<<src_samples[i]<<" error code: "<<res);
78  num_errs++;
79  continue;
80  }
81 #ifdef BIAS_DEBUG
82  if (DebugLevelIsSet("D_MCT_WRITE_DST_SAMPLES") && res==0){
83  of << setw(5) << i << "\t";
84  for (unsigned d=0; d<dst_samples[i-num_errs].Size(); d++){
85  of << dst_samples[i-num_errs][d] <<"\t";
86  }
87  of << endl;
88  }
89 #endif
90 #ifdef WRITE_DST_SAMPLES
91  if (res==0){
92  off << setw(5) << i << "\t";
93  for (unsigned d=0; d<dst_samples[i-num_errs].Size(); d++){
94  off << dst_samples[i-num_errs][d] <<"\t";
95  }
96  off << endl;
97  }
98 #endif
99  }
100 
101  if (num_errs!=0){
102  BCDOUT(D_MCT_NUM_SAMPLES, num_errs<<" errors in transform functions, "
103  "using less samples ("<<num-num_errs<<")\n");
104  dst_samples.resize(num-num_errs);
105  }
106 #ifdef BIAS_DEBUG
107  if (DebugLevelIsSet("D_MCT_WRITE_DST_SAMPLES")){
108  of.close();
109  }
110 #endif
111 #ifdef WRITE_DST_SAMPLES
112  off.close();
113 #endif
114  return (num_errs==0)?(0):(-num_errs);
115 }
116 
117 
119 Transform(const Vector<double>& src_mean, const Matrix<double>& src_cov,
120  Vector<double>& dst_mean, Matrix<double>& dst_cov) const
121 {
122  if (src_cov.IsZero(numeric_limits<double>::epsilon())){
123  Transform_(src_mean, dst_mean);
124  const int dim = dst_mean.Size();
125  dst_cov.newsize(dim, dim);
126  dst_cov.SetZero();
127  } else {
128  vector<Vector<double> > dst_samples;
129  int res = Transform(src_mean, src_cov, dst_samples);
130  if (res!=0){
131  BIASERR("error transforming samples. error code: "<<res);
132  //return res;
133  }
134  const int num = (int)dst_samples.size();
135  BIASASSERT(num>0);
136  const int dim = (int)dst_samples[0].Size();
137  dst_cov = Matrix<double>(dim, dim, MatrixZero);
138  dst_mean.newsize(dim);
139  dst_mean.SetZero();
140 
141  for (int i=0; i<num; i++){
142  dst_mean += dst_samples[i];
143  }
144  BIASASSERT(num>0);
145  dst_mean /= (double)num;
146 #ifdef BIAS_DEBUG
147  // transform returned 0, so results MUST NOT contain any invalid numbers!
148  for (int d=0; d<dim; d++) {
149  INFNANCHECK(dst_mean[d]);
150  }
151 #endif
152 
153  BIASASSERT(num>1);
154  Vector<double> diff;
155  for (int i=0; i<num; i++){
156  diff = dst_samples[i] - dst_mean;
157  dst_cov += diff.OuterProduct(diff);
158  }
159  dst_cov /= (double)(num-1);
160 #ifdef BIAS_DEBUG
161  // now we check finally whether cov is valid
162  for (int row=0; row<dst_cov.num_rows(); row++) {
163  for (int col=0; col<dst_cov.num_cols(); col++) {
164  INFNANCHECK(dst_cov[row][col]);
165  }
166  }
167 #endif
168  }
169  return 0;
170 }
171 
172 //#define MC_NORMALIZE
174 GetSamples_(const Vector<double>& src_mean,
175  const Matrix<double>& src_cov,
176  vector<Vector<double> >& src_samples) const
177 {
178  static BIAS::Random randomizer;
179  Vector<double> eigenval;
180  vector<Vector<double> > eigenvec;
181  int res;
182 #ifdef MC_NORMALIZE
183  double factor = src_cov.Trace();
184  Matrix<double> scaled_cov = src_cov / factor;
185  res = Upper_symmetric_eigenvalue_solve(scaled_cov, eigenval, eigenvec);
186 #else
187  res = Upper_symmetric_eigenvalue_solve(src_cov, eigenval, eigenvec);
188 #endif
189  if (res!=0){
190  BIASERR("error computing eigenvalues: "<<res);
191  return -1;
192  }
193  BCDOUT(D_MCT_EIGENVALVEC, "eignevalues: "<<eigenval<<endl);
194 
195  const int dim = (int)src_mean.Size();
196 #ifdef BIAS_DEBUG
197  //cout << "cov: "<<src_cov<<endl;
198 #endif
199  for (int d=0; d<dim; d++){
200  BCDOUT(D_MCT_EIGENVALVEC, d<<": "<<eigenvec[d]<<endl);
201  // cope with numerical inaccuracies, covariance matrices must have
202  // eignevalues >=0
203  if (eigenval[d]<0.0 && eigenval[d]>-1e-22){
204  BCDOUT(D_MCT_EIGENVALVEC, "["<<d<<"] numerical inaccurate eigenvalue: "
205  <<eigenval[d]<<endl<< "corresp eigenvec.NormL2(): "
206  <<eigenvec[d].NormL2()<<endl);
207  eigenval[d] = 0.0;
208  }
209 #ifdef BIAS_DEBUG
210  if (eigenval[d]<0.0) {
211  cout << "["<<d<<"] illegal eigenvalue: "<<eigenval[d]<<endl;
212  cout << "corresp eigenvec: "<<eigenvec[d]<<endl;
213  }
214 #endif
215  BIASASSERT(eigenval[d]>=0.0);
216 #ifdef MC_NORMALIZE
217  eigenval[d] *= factor;
218 #endif
219  eigenval[d] = sqrt(eigenval[d]);
220 #ifdef BIAS_DEBUG
221  if (Equal(eigenvec[d].NormL2(), 0.0)) {
222  cout << "illegal eigenvector: "<<eigenvec[d]<<endl;}
223 #endif
224  BIASASSERT(!Equal(eigenvec[d].NormL2(), 0.0));
225  eigenvec[d] /= eigenvec[d].NormL2();
226  }
227 
228 #ifdef BIAS_DEBUG
229  //cout << "src_cov: "<<src_cov<<endl;
230  ofstream of;
231  if (DebugLevelIsSet("D_MCT_WRITE_SRC_SAMPLES")){
232  of.open("src_samples.txt");
233  }
234 #endif
235  double r;
236  const int num = NumSamplesPerDimension_ * dim;
237  cout << "using: "<<num<<" samples\n";
238  vector<Vector<double> > quasi_std_normal_distr;
239  vector<double> normal_distr;
240 
241 
243  if (uniformDistribution_) {
244  BIASWARNONCE("uniform-distribution sampling is experimental"
245  ", multi-dim. case needs verification");
246 
247  BIAS::Vector<double> themin(dim, -1.0 * sqrt(3.0)),
248  themax(dim, sqrt(3.0));
249  res = randomizer.GetQuasiUniformDistributed(dim, themin, themax, num,
250  quasi_std_normal_distr);
251  BIASASSERT(res==0);
252  } else {
253  res = randomizer.GetQuasiNormalDistributed(dim, num, quasi_std_normal_distr);
254  BIASASSERT(res==0);
255  }
256 #ifdef BIAS_DEBUG
257  // evaluate statistics of chosen samples:
258  Vector<double> testmean;
259  Matrix<double> testcov;
260  randomizer.GetMeanAndCovariance(quasi_std_normal_distr,
261  testmean, testcov);
262  BCDOUT(D_MCT_NUM_SAMPLES,"QuasiRandom with mean zero and cov=id computed "
263  <<testmean<<" and "<<testcov);
264 #endif
265  } else {
267  randomizer.GetUniformDistributed(-1.0 * sqrt(3.0), sqrt(3.0),
268  num*dim, normal_distr);
269  } else {
270  randomizer.GetNormalDistributed(0.0, 1.0, num*dim, normal_distr);
271  }
272 #ifdef BIAS_DEBUG
273  // evaluate statistics of chosen samples:
274  double testmean;
275  double testcov;
276  randomizer.GetMeanAndCovariance(normal_distr, testmean, testcov);
277  BCDOUT(D_MCT_NUM_SAMPLES,"Random with mean zero and cov=id computed "
278  <<testmean<<" and "<<testcov);
279 #endif
280  }
281 
282  int jj=0;
283  Vector<double> zero(dim, 0.0);
284  src_samples.resize(num, zero);
285  for (int i=0; i<num; i++){
286  for (int d=0; d<dim; d++){
287 
289  r = quasi_std_normal_distr[i][d] * eigenval[d];
290  } else {
291  //r = randomizer_.GetNormalDistributedGSL(0.0, eigenval[d]);
292  r = normal_distr[jj++]*eigenval[d];
293  }
294 /*
295 #ifdef BIAS_DEBUG
296  // sanity checks
297  if (src_samples[i].NormL2()>1e8){
298  BIASERR("before adding vec: ["<<i<<"] "<<src_samples[i]<<" d = "<<d);
299  BIASABORT;
300  }
301 #endif
302 */
303  src_samples[i] += r * eigenvec[d];
304 /*
305 #ifdef BIAS_DEBUG
306  if (src_samples[i].NormL2()>1e8){
307  BIASERR("before adding mean: random number "<<r<<" "<<eigenval[d]
308  <<" "<<eigenvec[d]<<" "<<src_samples[i]);
309  BIASABORT;
310  }
311 #endif
312 */
313  }
314 
315  src_samples[i] += src_mean;
316 /*
317 #ifdef BIAS_DEBUG
318  if (src_samples[i].NormL2()>1e8){
319  BIASERR("after adding mean: "<<src_samples[i]<<" "<<src_mean);
320  BIASABORT;
321  }
322 #endif
323 */
324 
325 #ifdef BIAS_DEBUG
326  if (DebugLevelIsSet("D_MCT_WRITE_SRC_SAMPLES")){
327  for (int d=0; d<dim; d++){
328  of << src_samples[i][d] <<"\t";
329  }
330  of << endl;
331  }
332 #endif
333  BCDOUT(D_MCT_NUM_SAMPLES, "x"<<flush);
334  }
335 #ifdef BIAS_DEBUG
336  if (DebugLevelIsSet("D_MCT_WRITE_SRC_SAMPLES")){
337  of.close();
338  }
339 #endif
340  BCDOUT(D_MCT_NUM_SAMPLES, "\nusing "<<num<<" src_samples\n");
341 /*
342 #ifdef BIAS_DEBUG
343  cout << "checking first two moments of distribution of "<<num<<" samples\n";
344  // compute covariance and mean from samples, they should coincide with
345  // src_mean and src_cov
346  Vector<double> check_mean(dim, 0.0), diff;
347  Matrix<double> check_cov(dim, dim, MatrixZero);
348  for (int i=0; i<num; i++){
349  //cout << i<<": "<<src_samples[i]<<endl;
350  check_mean += src_samples[i];
351  }
352  check_mean /= (double)num;
353 
354  for (int i=0; i<num; i++){
355  diff = src_samples[i] - check_mean;
356  check_cov += diff.OuterProduct(diff);
357  }
358  check_cov /= (double)(num-1);
359 
360  diff = src_mean-check_mean;
361  cout << "src_mean: "<<src_mean<<"\ncheck_mean: "<<check_mean
362  << "diff: "<<diff<<"\t norm: "<<diff.NormL2()<<endl;
363  cout << "src_cov: "<<src_cov
364  << "check_cov: "<<check_cov<<endl
365  << "src_cov - check_cov: "<<src_cov-check_cov<<endl;
366 #endif
367 */
368  return num;
369 }
370 
372 Skew(const std::vector<Vector<double> >& dst_samples,
373  double skewnness) const
374 {
375  BIASERR("unfinished");
376  BIASABORT;
377 }
bool IsZero(double eps=0.0) const
Checks if the matrix is a null matrix.
Definition: Matrix.cpp:638
Subscript num_cols() const
Definition: cmat.h:320
virtual int Transform_(const Vector< double > &src, Vector< double > &dst) const =0
implements a point transformation
int GetQuasiUniformDistributed(const int dim, const Vector< double > &min, const Vector< double > &max, Vector< double > &res)
On subsequent calls returns a Sobol&#39; sequence of quasi random numbers &#39;uniformly distributed&#39; in a N-...
Definition: Random.cpp:300
Matrix< T > & newsize(Subscript M, Subscript N)
Definition: cmat.h:269
unsigned int Size() const
length of the vector
Definition: Vector.hh:143
double GetUniformDistributed(const double min, const double max)
on succesive calls return uniform distributed random variable between min and max ...
Definition: Random.hh:84
void SetZero()
equivalent to matrix call
Definition: Vector.hh:156
bool DebugLevelIsSet(const long int lv) const
Definition: Debug.hh:341
Vector< T > & newsize(Subscript N)
Definition: vec.h:220
void Skew(const std::vector< Vector< double > > &dst_samples, double skewnness) const
Matrix< T > OuterProduct(const Vector< T > &v) const
outer product, constructs a matrix.
Definition: Vector.cpp:99
void SetZero()
Sets all values to zero.
Definition: Matrix.hh:856
int GetSamples_(const Vector< double > &src_mean, const Matrix< double > &src_cov, std::vector< Vector< double > > &src_samples) const
computes src_mean.Size()* NumSamplesPerDimension_ samples drawn from multidiemsional normal distribut...
long int NewDebugLevel(const std::string &name)
creates a new debuglevel
Definition: Debug.hh:474
bool Equal(const T left, const T right, const T eps)
comparison function for floating point values See http://www.boost.org/libs/test/doc/components/test_...
base class for all uncertainty transforms
T Trace() const
Definition: Matrix.hh:903
Subscript num_rows() const
Definition: cmat.h:319
double GetNormalDistributed(const double mean, const double sigma)
on succesive calls return normal distributed random variable with mean and standard deviation sigma ...
Definition: Random.hh:71
int Transform(const Vector< double > &src_mean, const Matrix< double > &src_cov, Vector< double > &dst_mean, Matrix< double > &dst_cov) const
computes the Monte Carlo approximation of the transformations of the mean and the associated covarian...
BIAS::Vector< double > Upper_symmetric_eigenvalue_solve(const BIAS::Matrix< double > &A)
Solve symmetric eigenvalue problem (eigenvalues only)
Definition: Lapack.cpp:438
class for producing random numbers from different distributions
Definition: Random.hh:51
void GetMeanAndCovariance(const std::vector< double > &samples, double &mean, double &covariance) const
check-function to compute mean and cov from samples
Definition: Random.cpp:706
bool uniformDistribution_
set to true if you want to sample uniform instead of gauss
int GetQuasiNormalDistributed(const int dim, Vector< double > &res)
On subsequent calls returns a Sobol&#39; sequence of quasi random numbers &#39;normal distributed&#39; with mean ...
Definition: Random.cpp:396