queso-0.55.0
InfoTheory.C
Go to the documentation of this file.
1 //-----------------------------------------------------------------------bl-
2 //--------------------------------------------------------------------------
3 //
4 // QUESO - a library to support the Quantification of Uncertainty
5 // for Estimation, Simulation and Optimization
6 //
7 // Copyright (C) 2008-2015 The PECOS Development Team
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the Version 2.1 GNU Lesser General
11 // Public License as published by the Free Software Foundation.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc. 51 Franklin Street, Fifth Floor,
21 // Boston, MA 02110-1301 USA
22 //
23 //-----------------------------------------------------------------------el-
24 
25 #include <queso/InfoTheory.h>
26 
27 #include <queso/Defines.h>
28 #include <gsl/gsl_sf_psi.h> // todo: take specificity of gsl_, i.e., make it general (gsl or boost or etc)
29 
30 #ifdef QUESO_HAS_ANN
31 
32 namespace QUESO {
33 
34 //*****************************************************
35 // Function: distANN_XY
36 //*****************************************************
37 void distANN_XY( const ANNpointArray dataX, const ANNpointArray dataY,
38  double* distsXY,
39  unsigned int dimX, unsigned int dimY,
40  unsigned int xN, unsigned int yN,
41  unsigned int k, double eps )
42 {
43 
44  ANNkd_tree* kdTree;
45  ANNdistArray nnDist;
46  ANNidxArray nnIdx;
47 
48  // Allocate memory
49  nnIdx = new ANNidx[ k+1 ];
50  nnDist = new ANNdist[ k+1 ];
51  kdTree = new ANNkd_tree( dataY, yN, dimY );
52 
53  // Get the distances to all the points
54  for( unsigned int i = 0; i < xN ; i++ )
55  {
56  kdTree->annkSearch( dataX[ i ], k+1, nnIdx, nnDist, eps );
57 
58  double my_dist = nnDist[ k ];
59 
60  // check to see if the dist is zero (query point same as the kNN)
61  // if so find the next k that gives the next positive distance
62  if( my_dist == 0.0 )
63  {
64  ANNdistArray nnDist_tmp = new ANNdist[ yN ];
65  ANNidxArray nnIdx_tmp = new ANNidx[ yN ];
66  kdTree->annkSearch( dataX[ i ], yN, nnIdx_tmp, nnDist_tmp, eps );
67 
68  for( unsigned int my_k = k + 1; my_k < yN; ++my_k )
69  if( nnDist_tmp[ my_k ] > 0.0 )
70  {
71  my_dist = nnDist_tmp[ my_k ];
72  break;
73  }
74  delete [] nnIdx_tmp;
75  delete [] nnDist_tmp;
76  }
77 
78  distsXY[ i ] = my_dist;
79  }
80 
81  // Deallocate memory
82  delete [] nnIdx;
83  delete [] nnDist;
84  delete kdTree;
85  annClose();
86 
87  return;
88 }
89 
90 //*****************************************************
91 // Function: normalizeANN_XY
92 // (used by Mutual Information - marginal normalization
93 // it does not destroy the correlations)
94 //*****************************************************
95 void normalizeANN_XY( ANNpointArray dataXY, unsigned int dimXY,
96  ANNpointArray dataX, unsigned int dimX,
97  ANNpointArray dataY, unsigned int dimY,
98  unsigned int N )
99 {
100 
101  ANNpoint meanXY, stdXY;
102 
103  meanXY = annAllocPt(dimXY); // is init with 0
104  stdXY = annAllocPt(dimXY); // is init with 0
105 
106  // get mean
107  for( unsigned int i = 0; i < N; i++ ) {
108  for( unsigned int j = 0; j < dimX; j++ ) {
109  meanXY[ j ] += dataXY[ i ][ j ];
110  }
111  for( unsigned int j = 0; j < dimY; j++ ) {
112  meanXY[ dimX + j ] += dataXY[ i ][ dimX + j ];
113  }
114  }
115  for( unsigned int j = 0; j < dimXY; j++ ) {
116  meanXY[ j ] = meanXY[ j ] / (double)N;
117  }
118 
119  // get standard deviation
120  for( unsigned int i = 0; i < N; i++ ) {
121  for( unsigned int j = 0; j < dimXY; j++ ) {
122  stdXY[ j ] += pow( dataXY[ i ][ j ] - meanXY[ j ], 2.0 );
123  }
124  }
125  for( unsigned int j = 0; j < dimXY; j++ ) {
126  stdXY[ j ] = sqrt( stdXY[ j ] / ((double)N-1.0) );
127  }
128 
129  /*
130  std::cout << "Mean RV - ";
131  annPrintPt( meanXY, dimXY, std::cout );
132  std::cout << std::endl << "Std RV - ";
133  annPrintPt( stdXY, dimXY, std::cout );
134  std::cout << std::endl;
135  */
136 
137  // get normalized points and populate marginals
138  for( unsigned int i = 0; i < N; i++ ) {
139  // normalize joint
140  for( unsigned int j = 0; j < dimXY; j++ ) {
141  dataXY[ i ][ j ] = ( dataXY[ i ][ j ] - meanXY[ j ] ) / stdXY[ j ];
142  }
143 
144  // populate marginals
145  for( unsigned int j = 0; j < dimX; j++ ) {
146  dataX[ i ][ j ] = dataXY[ i ][ j ];
147  }
148  for( unsigned int j = 0; j < dimY; j++ ) {
149  dataY[ i ][ j ] = dataXY[ i ][ dimX + j ];
150  }
151  }
152 
153 }
154 
155 //*****************************************************
156 // Function: computeMI_ANN
157 //*****************************************************
158 double computeMI_ANN( ANNpointArray dataXY,
159  unsigned int dimX, unsigned int dimY,
160  unsigned int k, unsigned int N, double eps )
161 {
162 
163  ANNpointArray dataX, dataY;
164  double* distsXY;
165  double MI_est;
166  ANNkd_tree* kdTreeX;
167  ANNkd_tree* kdTreeY;
168 
169  unsigned int dimXY = dimX + dimY;
170 
171  // Allocate memory
172  dataX = annAllocPts(N,dimX);
173  dataY = annAllocPts(N,dimY);
174  distsXY = new double[N];
175 
176  // Normalize data and populate the marginals dataX, dataY
177  normalizeANN_XY( dataXY, dimXY, dataX, dimX, dataY, dimY, N);
178 
179  // Get distance to knn for each point
180  kdTreeX = new ANNkd_tree( dataX, N, dimX );
181  kdTreeY = new ANNkd_tree( dataY, N, dimY );
182  distANN_XY( dataXY, dataXY, distsXY, dimXY, dimXY, N, N, k, eps );
183 
184  // Compute mutual information
185  double marginal_contrib = 0.0;
186  for( unsigned int i = 0; i < N; i++ ) {
187  // get the number of points within a specified radius
188  int no_pts_X = kdTreeX->annkFRSearch( dataX[ i ], distsXY[ i ], 0, NULL, NULL, eps);
189  int no_pts_Y = kdTreeY->annkFRSearch( dataY[ i ], distsXY[ i ], 0, NULL, NULL, eps);
190  // digamma evaluations
191  marginal_contrib += gsl_sf_psi_int( no_pts_X+1 ) + gsl_sf_psi_int( no_pts_Y+1 );
192  }
193  MI_est = gsl_sf_psi_int( k ) + gsl_sf_psi_int( N ) - marginal_contrib / (double)N;
194 
195  // Deallocate memory
196  delete kdTreeX;
197  delete kdTreeY;
198  delete [] distsXY;
199  annDeallocPts( dataX );
200  annDeallocPts( dataY );
201 
202  return MI_est;
203 
204 }
205 
206 //*****************************************************
207 // Function: estimateMI_ANN (using a joint)
208 // (Mutual Information)
209 //*****************************************************
210 template<template <class P_V, class P_M> class RV, class P_V, class P_M>
211 double estimateMI_ANN( const RV<P_V,P_M>& jointRV,
212  const unsigned int xDimSel[], unsigned int dimX,
213  const unsigned int yDimSel[], unsigned int dimY,
214  unsigned int k, unsigned int N, double eps )
215 {
216  ANNpointArray dataXY;
217  double MI_est;
218 
219  unsigned int dimXY = dimX + dimY;
220 
221  // Allocate memory
222  dataXY = annAllocPts(N,dimXY);
223 
224  // Copy samples in ANN data structure
225  P_V smpRV( jointRV.imageSet().vectorSpace().zeroVector() );
226  for( unsigned int i = 0; i < N; i++ ) {
227  // get a sample from the distribution
228  jointRV.realizer().realization( smpRV );
229 
230  // copy the vector values in the ANN data structure
231  for( unsigned int j = 0; j < dimX; j++ ) {
232  dataXY[ i ][ j ] = smpRV[ xDimSel[j] ];
233  }
234  for( unsigned int j = 0; j < dimY; j++ ) {
235  dataXY[ i ][ dimX + j ] = smpRV[ yDimSel[j] ];
236  }
237  // annPrintPt( dataXY[i], dimXY, std::cout ); std::cout << std::endl;
238  }
239 
240  MI_est = computeMI_ANN( dataXY,
241  dimX, dimY,
242  k, N, eps );
243 
244  // Deallocate memory
245  annDeallocPts( dataXY );
246 
247  return MI_est;
248 }
249 
250 //*****************************************************
251 // Function: estimateMI_ANN (using two seperate RVs)
252 // (Mutual Information)
253 //*****************************************************
254 template<class P_V, class P_M,
255  template <class P_V, class P_M> class RV_1,
256  template <class P_V, class P_M> class RV_2>
257 double estimateMI_ANN( const RV_1<P_V,P_M>& xRV,
258  const RV_2<P_V,P_M>& yRV,
259  const unsigned int xDimSel[], unsigned int dimX,
260  const unsigned int yDimSel[], unsigned int dimY,
261  unsigned int k, unsigned int N, double eps )
262 {
263  ANNpointArray dataXY;
264  double MI_est;
265 
266  unsigned int dimXY = dimX + dimY;
267 
268  // Allocate memory
269  dataXY = annAllocPts(N,dimXY);
270 
271  // Copy samples in ANN data structure
272  P_V smpRV_x( xRV.imageSet().vectorSpace().zeroVector() );
273  P_V smpRV_y( yRV.imageSet().vectorSpace().zeroVector() );
274 
275  for( unsigned int i = 0; i < N; i++ ) {
276  // get a sample from the distribution
277  xRV.realizer().realization( smpRV_x );
278  yRV.realizer().realization( smpRV_y );
279 
280  // copy the vector values in the ANN data structure
281  for( unsigned int j = 0; j < dimX; j++ ) {
282  dataXY[ i ][ j ] = smpRV_x[ xDimSel[j] ];
283  }
284  for( unsigned int j = 0; j < dimY; j++ ) {
285  dataXY[ i ][ dimX + j ] = smpRV_y[ yDimSel[j] ];
286  }
287  // annPrintPt( dataXY[i], dimXY, std::cout ); std::cout << std::endl;
288  }
289 
290  MI_est = computeMI_ANN( dataXY,
291  dimX, dimY,
292  k, N, eps );
293 
294  // Deallocate memory
295  annDeallocPts( dataXY );
296 
297  return MI_est;
298 }
299 
300 //*****************************************************
301 // Function: estimateKL_ANN
302 // (Kullback-Leibler divergence)
303 //*****************************************************
304 template <class P_V, class P_M,
305  template <class P_V, class P_M> class RV_1,
306  template <class P_V, class P_M> class RV_2>
307 double estimateKL_ANN( RV_1<P_V,P_M>& xRV,
308  RV_2<P_V,P_M>& yRV,
309  unsigned int xDimSel[], unsigned int dimX,
310  unsigned int yDimSel[], unsigned int dimY,
311  unsigned int xN, unsigned int yN,
312  unsigned int k, double eps )
313 {
314  ANNpointArray dataX;
315  ANNpointArray dataY;
316  double* distsX;
317  double* distsXY;
318  double KL_est;
319 
320  // sanity check
321  if( dimX != dimY ) {
322  queso_error_msg("Error-KL: the dimensions should agree");
323  }
324 
325  // Allocate memory
326  dataX = annAllocPts( xN, dimX );
327  dataY = annAllocPts( yN, dimY );
328  distsX = new double[xN];
329  distsXY = new double[xN];
330 
331  // Copy X samples in ANN data structure
332  P_V xSmpRV( xRV.imageSet().vectorSpace().zeroVector() );
333  for( unsigned int i = 0; i < xN; i++ ) {
334  // get a sample from the distribution
335  xRV.realizer().realization( xSmpRV );
336  // copy the vector values in the ANN data structure
337  for( unsigned int j = 0; j < dimX; j++ ) {
338  dataX[ i ][ j ] = xSmpRV[ xDimSel[j] ];
339  }
340  }
341 
342  // Copy Y samples in ANN data structure
343  P_V ySmpRV( yRV.imageSet().vectorSpace().zeroVector() );
344  for( unsigned int i = 0; i < yN; i++ ) {
345  // get a sample from the distribution
346  yRV.realizer().realization( ySmpRV );
347  // copy the vector values in the ANN data structure
348  for( unsigned int j = 0; j < dimY; j++ ) {
349  dataY[ i ][ j ] = ySmpRV[ yDimSel[j] ];
350  }
351  }
352 
353  // Get distance to knn for each point
354  distANN_XY( dataX, dataX, distsX, dimX, dimX, xN, xN, k+1, eps ); // k+1 because the 1st nn is itself
355  distANN_XY( dataX, dataY, distsXY, dimX, dimY, xN, yN, k, eps );
356 
357  // Compute KL-divergence estimate
358  double sum_log_ratio = 0.0;
359  for( unsigned int i = 0; i < xN; i++ )
360  {
361  sum_log_ratio += log( distsXY[i] / distsX[i] );
362  }
363  KL_est = (double)dimX/(double)xN * sum_log_ratio + log( (double)yN / ((double)xN-1.0 ) );
364 
365  // Deallocate memory
366  annDeallocPts( dataX );
367  annDeallocPts( dataY );
368  delete [] distsX;
369  delete [] distsXY;
370 
371  return KL_est;
372 }
373 
374 
375 //*****************************************************
376 // Function: estimateCE_ANN
377 // (Cross Entropy)
378 //*****************************************************
379 template <class P_V, class P_M,
380  template <class P_V, class P_M> class RV_1,
381  template <class P_V, class P_M> class RV_2>
382 double estimateCE_ANN( RV_1<P_V,P_M>& xRV,
383  RV_2<P_V,P_M>& yRV,
384  unsigned int xDimSel[], unsigned int dimX,
385  unsigned int yDimSel[], unsigned int dimY,
386  unsigned int xN, unsigned int yN,
387  unsigned int k, double eps )
388 {
389  ANNpointArray dataX;
390  ANNpointArray dataY;
391  double* distsXY;
392  double CE_est;
393  ANNkd_tree* kdTree;
394 
395  // sanity check
396  if( dimX != dimY ) {
397  queso_error_msg("Error-CE: the dimensions should agree");
398  }
399 
400  // Allocate memory
401  dataX = annAllocPts( xN, dimX );
402  dataY = annAllocPts( yN, dimY );
403  distsXY = new double[xN];
404  kdTree = new ANNkd_tree( dataY, yN, dimY );
405 
406  // Copy X samples in ANN data structure
407  P_V xSmpRV( xRV.imageSet().vectorSpace().zeroVector() );
408  for( unsigned int i = 0; i < xN; i++ ) {
409  // get a sample from the distribution
410  xRV.realizer().realization( xSmpRV );
411  // copy the vector values in the ANN data structure
412  for( unsigned int j = 0; j < dimX; j++ ) {
413  dataX[ i ][ j ] = xSmpRV[ xDimSel[j] ];
414  }
415  }
416 
417  // Copy Y samples in ANN data structure
418  P_V ySmpRV( yRV.imageSet().vectorSpace().zeroVector() );
419  for( unsigned int i = 0; i < yN; i++ ) {
420  // get a sample from the distribution
421  yRV.realizer().realization( ySmpRV );
422  // copy the vector values in the ANN data structure
423  for( unsigned int j = 0; j < dimY; j++ ) {
424  dataY[ i ][ j ] = ySmpRV[ yDimSel[j] ];
425  }
426  }
427 
428  // Get distance to knn for each point
429  distANN_XY( dataX, dataY, distsXY, dimX, dimY, xN, yN, k, eps );
430  kdTree = new ANNkd_tree( dataY, yN, dimY );
431 
432  // Compute cross entropy estimate
433  double sum_log = 0.0;
434  for( unsigned int i = 0; i < xN; i++ )
435  {
436  sum_log += log( distsXY[i] );
437  }
438  CE_est = (double)dimX/(double)xN * sum_log + log( (double)yN ) - gsl_sf_psi_int( k );
439 
440  // Deallocate memory
441  annDeallocPts( dataX );
442  annDeallocPts( dataY );
443  delete [] distsXY;
444 
445  return CE_est;
446 }
447 
448 } // End namespace QUESO
449 
450 #endif // QUESO_HAS_ANN
DLL_API void annDeallocPts(ANNpointArray &pa)
Definition: ANN.cpp:133
#define queso_error_msg(msg)
Definition: asserts.h:47
ANNidx * ANNidxArray
Definition: ANN.h:378
double eps
Definition: ann_sample.cpp:55
ANNcoord * ANNpoint
Definition: ANN.h:375
double ANNdist
Definition: ANN.h:159
int k
Definition: ann_sample.cpp:53
int annkFRSearch(ANNpoint q, ANNdist sqRad, int k, ANNidxArray nn_idx=NULL, ANNdistArray dd=NULL, double eps=0.0)
ANNdist * ANNdistArray
Definition: ANN.h:377
void annkSearch(ANNpoint q, int k, ANNidxArray nn_idx, ANNdistArray dd, double eps=0.0)
Definition: kd_search.cpp:89
DLL_API ANNpointArray annAllocPts(int n, int dim)
Definition: ANN.cpp:117
DLL_API ANNpoint annAllocPt(int dim, ANNcoord c=0)
Definition: ANN.cpp:110
ANNpoint * ANNpointArray
Definition: ANN.h:376
DLL_API void annClose()
Definition: kd_tree.cpp:221
int ANNidx
Definition: ANN.h:175

Generated on Fri Jun 17 2016 14:17:41 for queso-0.55.0 by  doxygen 1.8.5