Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

MathFunctions.H

Go to the documentation of this file.
00001 /*!@file Util/MathFunctions.H Miscellaneous math functions */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003   //
00005 // by the University of Southern California (USC) and the iLab at USC.  //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Util/MathFunctions.H $
00035 // $Id: MathFunctions.H 11721 2009-09-18 17:17:24Z lior $
00036 //
00037 
00038 #ifndef MATHFUNCTIONS_H_DEFINED
00039 #define MATHFUNCTIONS_H_DEFINED
00040 
00041 #include "Util/Assert.H"
00042 #include "Util/FastMathFunctions.H"
00043 #include "Util/Promotions.H"
00044 #include "rutz/compat_cmath.h" // for M_PI, M_E if not present in <cmath>
00045 
00046 #include <algorithm> // for std::swap()
00047 #include <cmath>
00048 
00049 //! Miscellaneous math functions
00050 
00051 // ######################################################################
00052 /*! @Precomputed Constants 128 bits IEEE quad */
00053 /*! Each constant is 128 bits IEEE quad. On a 64 bit system,
00054   a double is 128 bits. Thus, each number is a double on a modern system
00055 
00056   # define M_El                2.7182818284590452353602874713526625L
00057 
00058   is given for the value of 'e'. We follow this standard.
00059 
00060   Note:
00061 */
00062 //@{
00063 #define D_PI               3.1415926535897932384626433832795029
00064 //! e
00065 #define D_E                2.7182818284590452353602874713526625
00066 //! Log Root of 2 Pi
00067 #define D_LOG_SQRT_2_PI    0.9189385332046727417803297364056176
00068 //! Root of 2*Pi
00069 #define D_SQRT_2_PI        2.5066282746310002416123552393401041
00070 //! Root of Pi
00071 #define D_SQRT_PI          1.7724538509055160272981674833411451
00072 //! Root of 2 DEFINED in cmath as M_SQRT2, but is not 128 bit
00073 #define D_SQRT_2           1.4142135623730950488016887242096981
00074 //! Natural Log of 2*Pi
00075 #define D_LOG_2_PI         1.8378770664093454835606594728112353
00076 //! Natural Log of Pi
00077 #define D_LOG_PI           1.1447298858494001741434273513530587
00078 //! Natural Log of 2 DEFINED in cmath as M_LN2, but is not 128 bit
00079 #define D_LOG_2            0.6931471805599453094172321214581766
00080 //! Natural Log of sqrt of 2
00081 #define D_LOG_SQRT_2       0.3465735902799726547086160607290883
00082 //! 2*Pi
00083 #define D_2_PI             6.2831853071795862319959269370883703
00084 //! The Euler-Mascheroni Constant (Not the same as e)
00085 #define D_EULER_GAMMA      0.5772156649015328606065120900824024
00086 //! Number of radians in one degree
00087 #define D_DEGREE           0.0174532925199432957692369076848861
00088 //! The golden ratio
00089 #define D_GOLDEN_RATIO     1.6180339887498948482045868343656381
00090 //! Catalan's Constant
00091 #define D_CATALAN          0.9159655941772190150546035149323841
00092 //! Glaisher-Kinkelin Constant
00093 #define D_GLAISHER         1.2824271291006226368753425688697917
00094 //! Khinchin's Constant
00095 #define D_KHINCHIN         2.6854520010653064453097148354817956
00096 //! Ramanujan-Soldner's Constant
00097 #define D_SOLDNER          1.4513692348833810502839684858920274
00098 //! Apery's Constant
00099 #define D_APERY            1.2020569031595942853997381615114499
00100 //! Gauss-Kuzmin-Wirsing constant
00101 #define D_GAUSS_KUZMAN     0.3036630028987326585974481219015562
00102 //! Fransén-Robinson constant
00103 #define D_FRANSEN          2.8077702420285193652215011865577729
00104 //! Sierpin'ski's constant
00105 #define D_SERPINSKY        2.5849817595792532170658935873831711
00106 //! Mills' constant
00107 #define D_MILL             1.3063778838630806904686144926026057
00108 //! Omega constant
00109 #define D_OMEGA            0.5671432904097838729999686622103555
00110 //! Golomb-Dickman constant
00111 #define D_GOLOMB_DICKMAN   0.6243299885435508709929363831008372
00112 
00113 // ######################################################################
00114 /*! @Precomputed Constants 256 Bit*/
00115 /*! Each constant is 256 bits, This makes it a double long floating point on any modern 64 bit
00116   CPU.
00117 */
00118 //@{
00119 //! Pi
00120 #define L_PI            3.14159265358979323846264338327950288419716939937510582097494459230781L // ... 640628620899862803482534
00121 //! e
00122 #define L_E             2.71828182845904523536028747135266249775724709369995957496696762772407L // ... 663035354759457138
00123 //! Log Root of 2 Pi
00124 #define L_LOG_SQRT_2_PI 0.91893853320467274178032973640561763986139747363778341281715154048276L
00125 //! Root of 2*Pi
00126 #define L_SQRT_2_PI     2.50662827463100050241576528481104525300698674060993831662992357634229L
00127 //! Root of Pi
00128 #define L_SQRT_PI       1.77245385090551602729816748334114518279754945612238712821380778985291L
00129 //! Root of 2 DEFINED in cmath as M_SQRT2, but is not > 128 bit
00130 #define L_SQRT_2        1.41421356237309514547462185873882845044136047363281250000000000000000L
00131 //! Natural Log of 2*Pi
00132 #define L_LOG_2_PI      1.83787706640934548356065947281123527972279494727556682563430308096553L
00133 //! Natural Log of Pi
00134 #define L_LOG_PI        1.14472988584940017414342735135305871164729481291531157151362307147214L
00135 //! Natural Log of 2 DEFINED in cmath as M_LN2, but is not > 128 bit
00136 #define L_LOG_2         0.69314718055994528622676398299518041312694549560546875000000000000000L
00137 //! 2*Pi
00138 #define L_2_PI          6.28318530717958647692528676655900576839433879875021164194988918461560L
00139 //! Number of radians in one degree
00140 #define L_DEGREE        0.01745329251994329576923690768488612713442871888541725456097191440171L // ... 009114603449443682
00141 //! The Euler-Mascheroni Constant (Not the same as e)
00142 #define L_EULER_GAMMA   0.57721566490153286060651209008240243104215933593992359880576723488486L
00143 //! The golden ratio
00144 #define L_GOLDEN_RATIO  1.61803398874989484820458683436563811772030917980576286213544862270526L // ... 046281890244970721
00145 //! Catalan's Constant
00146 #define L_CATALAN       0.91596559417721901505460351493238411077414937428167213426649811962176L // ... 301977625476947936
00147 //! Glaisher-Kinkelin Constant
00148 #define L_GLAISHER      1.28242712910062263687534256886979172776768892732500119206374002174040L // ... 630885882646112974
00149 //! Khinchin's Constant
00150 #define L_KHINCHIN      2.68545200106530644530971483548179569382038229399446295305115234555721L // ... 885953715200280114
00151 //@}
00152 
00153 // ######################################################################
00154 /*! @name Basic numerical operations */
00155 //@{
00156 
00157 //! Returns -1 if \a x is negative, or 1 if \a x is positve.
00158 template <class T>
00159 inline int signOf(const T& x);
00160 
00161 //! Returns the square of \a x.
00162 template <class T>
00163 inline T squareOf(const T& x);
00164 
00165 //! Returns the number closest to \a val and between \a bound1 and \a bound2.
00166 /*! The bounds may be specified in either order (i.e., either (lo, hi) or
00167   (hi, lo). */
00168 template <class T, class T2>
00169 inline T clampValue(const T& val, const T2& bound1, const T2& bound2);
00170 
00171 //@}
00172 
00173 // ######################################################################
00174 /*! @name Numerical range and finiteness testing */
00175 //@{
00176 
00177 //! Function to check for finite value
00178 bool isFinite(const byte& arg);
00179 
00180 //! Function to check for finite value
00181 bool isFinite(const int16& arg);
00182 
00183 //! Function to check for finite value
00184 bool isFinite(const int32& arg);
00185 
00186 //! Function to check for finite value
00187 bool isFinite(const float& arg);
00188 
00189 //! Function to check for finite value
00190 bool isFinite(const double& arg);
00191 
00192 //@}
00193 
00194 // ######################################################################
00195 /*! @name Random number generation */
00196 //@{
00197 
00198 //! Initialize random seeds from pseudo-random sources (e.g. time(), getpid())
00199 void initRandomNumbers();
00200 
00201 //! Initialize random seeds with zero, to produce deterministic pseudo-random sequences
00202 void initRandomNumbersZero();
00203 
00204 //! Generate a random double in [0.0,1.0)
00205 /*! This is a thin wrapper around drand48() or rand(), depending on
00206     which is available on the build platform. */
00207 double randomDouble();
00208 
00209 //! Generate a random double from a normal distribution with mean zero and standard deviation s
00210 /*! This function call randomDouble() 12 times to sample from normal distribution  */
00211 double randomDoubleFromNormal(const double s);
00212 
00213 //! Generate a random integer in [0,n] (i.e., including n)
00214 /*! This is a thin wrapper around lrand48() or rand(), depending on
00215     which is available on the build platform. */
00216 int randomUpToIncluding(const int n);
00217 
00218 //! Generate a random integer in [0,n) (i.e., not including n)
00219 /*! This is a thin wrapper around lrand48() or rand(), depending on
00220     which is available on the build platform. */
00221 int randomUpToNotIncluding(const int n);
00222 
00223 //! Randomly shuffle given array
00224 template <class T> inline
00225 void randShuffle(T* array, const uint size);
00226 
00227 //! Random number generator from Numerical Recipes in C book
00228 /*! Long period >2x10^18 random number generator of L Ecuyer with
00229     Bays-Durham shuffle. Return a uniform deviate in the interval
00230     (0,1).  Call with int variable as argument set to a negative
00231     value, and don't change this variable between calls unless you
00232     want to reseed the generator. You can get ain initial seed using
00233     the function getIdum() */
00234 double ran2(int& idum);
00235 
00236 //! Get a random seed for ran2
00237 /*! If useRandom is true, a random negative number will be return,
00238   otherwise a negative number that is always the same will be
00239   returned. */
00240 int getIdum(const bool useRandom = true);
00241 
00242 //! Randomly distributed Gaussian deviate with zero mean and unit variance
00243 double gasdev(int& idum);
00244 
00245 //! Randomly distributed Exponential deviate
00246 double expdev(int& idum);
00247 
00248 //@}
00249 
00250 // ######################################################################
00251 /*! @name Special math functions with iterative implementations */
00252 //@{
00253 
00254 //! Compute probability of drawing a value k from a Poisson of mean mu
00255 double poisson(const unsigned int k, const double mu);
00256 
00257 //! Compute log of Gamma
00258 double lngamma(double x);
00259 
00260 //! Compute the psi (derivarive of log of gamma) function (requires x > 0.0)
00261 double psi(const double x);
00262 
00263 
00264 //@}
00265 
00266 // ######################################################################
00267 /*! @name Scalar math functions corresponding with Pixel math functions in Pixels.h */
00268 //@{
00269 
00270 template <class T> inline T maxmerge(T A, const T B)
00271 {
00272   if (A < B) A = B;
00273   return A;
00274 }
00275 
00276 // ######################################################################
00277 template <class T> inline T minmerge(T A, const T B)
00278 {
00279   if (A > B) A = B;
00280   return A;
00281 }
00282 
00283 // ######################################################################
00284 //! Secant
00285 template <class T> inline T sec(T A)
00286 {
00287   return clamped_convert<T>(1.0/cos(A));
00288 }
00289 
00290 // ######################################################################
00291 //! Cosecant
00292 template <class T> inline T cosec(T A)
00293 {
00294   return clamped_convert<T>(1.0/sin(A));
00295 }
00296 
00297 // ######################################################################
00298 //! Cotangent
00299 template <class T> inline T cotan(T A)
00300 {
00301   return clamped_convert<T>(1.0/tan(A));
00302 }
00303 
00304 // ######################################################################
00305 //! inverse secant
00306 template <class T> inline T asec(T A)
00307 {
00308   ASSERT(A >= 1.0);
00309   return clamped_convert<T>(acos(1.0/A));
00310 }
00311 
00312 // ######################################################################
00313 //! inverse cosecant
00314 template <class T> inline T acosec(T A)
00315 {
00316   ASSERT(A >= 1.0);
00317   return clamped_convert<T>(asin(1.0/A));
00318 }
00319 
00320 // ######################################################################
00321 //! inverse cotangent
00322 template <class T> inline T acotan(T A)
00323 {
00324   return clamped_convert<T>(atan(1.0/A));
00325 }
00326 
00327 // ######################################################################
00328 //! Hyperbolic Secant
00329 template <class T> inline T sech(T A)
00330 {
00331   return clamped_convert<T>(1.0/cosh(A));
00332 }
00333 
00334 // ######################################################################
00335 //! Hyperbolic Cosecant
00336 template <class T> inline T cosech(T A)
00337 {
00338   return clamped_convert<T>(1.0/sinh(A));
00339 }
00340 
00341 // ######################################################################
00342 //! Hyperbolic Cotangent
00343 template <class T> inline T cotanh(T A)
00344 {
00345   return clamped_convert<T>(1.0/tanh(A));
00346 }
00347 
00348 // ######################################################################
00349 //! Inverse Hyperbolic Secant
00350 template <class T> inline T asech(T A)
00351 {
00352   return clamped_convert<T>(acosh(1.0/A));
00353 }
00354 
00355 // ######################################################################
00356 //! Inverse Hyperbolic Cosecant
00357 template <class T> inline T acosech(T A)
00358 {
00359   return clamped_convert<T>(asinh(1.0/A));
00360 }
00361 
00362 // ######################################################################
00363 //! Inverse Hyperbolic Cotangent
00364 template <class T> inline T acotanh(T A)
00365 {
00366   return clamped_convert<T>(atanh(1.0/A));
00367 }
00368 
00369 // ######################################################################
00370 //! return the sign of this item
00371 template <class T> inline T sign(T A)
00372 {
00373   if (A >= 0) A = 1;
00374   else A = -1;
00375   return A;
00376 }
00377 
00378 // ######################################################################
00379 //! logN for pixel
00380 template <class T> inline T logN(T A, const T n)
00381 {
00382   A = clamped_convert<T>(
00383       log(static_cast<double>(A))/
00384       log(static_cast<double>(n)));
00385   return A;
00386 }
00387 
00388 // ######################################################################
00389 //! log sigmoid for pixel
00390 template <class T> inline T logsig(T A,const T a, const T b)
00391 {
00392   A = clamped_convert<T>(1.0/(1+exp(static_cast<double>(- (b * (A - a))))));
00393   return A;
00394 }
00395 
00396 // ######################################################################
00397 //! log sigmoid for pixel with offset
00398 /*! Values like a = 10 and b = 5 create a nice sigmoid for x = 0 to 1 since
00399     the center of the sigmoid is at b/a. 
00400     @param a The slope for the sigmoid
00401     @param b The offset for the sigmoid
00402 */
00403 template <class T> inline T logsig2(T x, const T a, const T b)
00404 {
00405   x = clamped_convert<T>(1.0/(1+exp(static_cast<double>(-x*a + b))));
00406   return x;
00407 }
00408 
00409 // ######################################################################
00410 //! tan sigmoid for pixel
00411 template <class T> inline T tansig(T A)
00412 {
00413   A = clamped_convert<T>(2/1+exp(-2*static_cast<double>(A))-1);
00414   return A;
00415 }
00416 
00417 // ######################################################################
00418 //! saturate pixel at some value
00419 template <class T> inline T saturate(T A, const T n)
00420 {
00421   if(A >= n) A = n;
00422   else A = A;
00423   return A;
00424 }
00425 
00426 // ######################################################################
00427 //! find p from a Gaussian distribution
00428 template <class T> inline T gauss(T A, const T Mu, const T Std)
00429 {
00430   return clamped_convert<T>(
00431       (1/(fastSqrt(D_2_PI*pow(static_cast<double>(Std),2))))
00432       *exp(-1*(pow((static_cast<double>(A) -
00433                     static_cast<double>(Mu)),2)
00434                /(2*pow(static_cast<double>(Std),2)))));
00435 }
00436 
00437 //! find p from a Gaussian distribution
00438 //! (instead of the mu and A, the difference is supplied)
00439 template <class T> inline T gauss(T diff, const T Std)
00440 {
00441   return clamped_convert<T>(
00442       (1/(fastSqrt(D_2_PI*pow(static_cast<double>(Std),2))))
00443       *exp(-1*(pow((static_cast<double>(diff)),2)
00444                /(2*pow(static_cast<double>(Std),2)))));
00445 }
00446 
00447 // ######################################################################
00448 //! find p from a gamma distrabution
00449 template <class T> inline T gamma(T X, const T A, const T B)
00450 {
00451   return clamped_convert<T>((
00452                              pow(static_cast<double>(X),static_cast<double>(A) -1) *
00453                              pow(static_cast<double>(B),static_cast<double>(A))    *
00454                              exp(static_cast<double>(-1.0*B*X)))/
00455                             lgamma(static_cast<double>(A)));
00456 }
00457 
00458 // ######################################################################
00459 //! this nonsense operator is for compatability
00460 template <class T> inline T max(T A)
00461 {
00462   return A;
00463 }
00464 
00465 // ######################################################################
00466 //! this nonsense operator is for compatability
00467 template <class T> inline T min(T A)
00468 {
00469   return A;
00470 }
00471 
00472 // ######################################################################
00473 //! find if this value or pixel is bounded by the other two
00474 template <class T> inline bool isBounded(T A, const T upper, const T lower)
00475 {
00476   return ((A >= lower) && (A <= upper));
00477 }
00478 
00479 // ######################################################################
00480 //! this nonsense operator is for compatability
00481 template <class T> inline T sum(T A)
00482 {
00483   return A;
00484 }
00485 
00486 // ######################################################################
00487 //! this nonsense operator is for compatability
00488 template <class T> inline T mean(T A)
00489 {
00490   return A;
00491 }
00492 
00493 //@}
00494 
00495 
00496 // ######################################################################
00497 //compute the stddev and mean of each feature
00498 //This algorithm is due to Knuth (The Art of Computer Programming, volume 2:
00499 //  Seminumerical Algorithms, 3rd edn., p. 232. Boston: Addison-Wesley.a
00500 //
00501 //! Compute the mean online by supplying the current mean and a new value
00502 //! mu is the previous mean, A is the current value and n is the number of values proceses so far
00503 template <class T> inline T onlineMean(T mu, T A, int n)
00504 {
00505   const T delta = A - mu;
00506   return mu + (delta/n);
00507 }
00508 
00509 template <class T> inline T onlineStdev(T mu, T stdev, T A, int n)
00510 {
00511   T ret = stdev;
00512   if (n > 2) //watch for divide by 0
00513   {
00514     const T delta = A - mu;
00515     ret = (stdev * (n-2)) + delta*delta;
00516     ret /= T(n-1);
00517   }
00518 
00519   return ret;
00520 }
00521 
00522 // ######################################################################
00523 // ######################################################################
00524 // ######################################################################
00525 // ##### Implementation of inlined functions
00526 // ######################################################################
00527 // ######################################################################
00528 // ######################################################################
00529 
00530 template <class T> inline int signOf(const T& x)
00531 { return (x < 0) ? -1 : 1; }
00532 
00533 template <class T> inline T squareOf(const T& x)
00534 { return (x * x); }
00535 
00536 template <class T, class T2>
00537 inline T clampValue(const T& val, const T2& bound1, const T2& bound2)
00538 {
00539   if (bound1 < bound2)
00540     {
00541       if (val < bound1) return bound1;
00542       if (val > bound2) return bound2;
00543       return val;
00544     }
00545   else
00546     {
00547       if (val < bound2) return bound2;
00548       if (val > bound1) return bound1;
00549     }
00550   return val;
00551 }
00552 
00553 template <class T> inline void randShuffle(T* array, const uint size)
00554 {
00555   for (uint i = 0; i < size; ++i)
00556     {
00557       const uint idx = i + randomUpToNotIncluding(size-i);
00558       std::swap(array[i], array[idx]);
00559     }
00560 }
00561 
00562 // ######################################################################
00563 // ##### Digamma (psi) function
00564 // ######################################################################
00565 // Code for computation of psi function (derivative of log gamma)
00566 // ripped from GSL, the GNU scientific library
00567 //
00568 /* Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman
00569  *
00570  * This program is free software; you can redistribute it and/or modify
00571  * it under the terms of the GNU General Public License as published by
00572  * the Free Software Foundation; either version 2 of the License, or (at
00573  * your option) any later version.
00574  *
00575  * This program is distributed in the hope that it will be useful, but
00576  * WITHOUT ANY WARRANTY; without even the implied warranty of
00577  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00578  * General Public License for more details.
00579  *
00580  * You should have received a copy of the GNU General Public License
00581  * along with this program; if not, write to the Free Software
00582  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00583  */
00584 
00585 // ######################################################################
00586 /* data for a Chebyshev series over a given interval */
00587 struct cheb_series_struct {
00588   double * c;   /* coefficients                */
00589   int order;    /* order of expansion          */
00590   double a;     /* lower interval point        */
00591   double b;     /* upper interval point        */
00592   int order_sp; /* effective single precision order */
00593 };
00594 typedef struct cheb_series_struct cheb_series;
00595 
00596 // ######################################################################
00597 /* Chebyshev fits from SLATEC code for psi(x) */
00598 static double psics_data[23] = {
00599   -.038057080835217922,
00600    .491415393029387130,
00601   -.056815747821244730,
00602    .008357821225914313,
00603   -.001333232857994342,
00604    .000220313287069308,
00605   -.000037040238178456,
00606    .000006283793654854,
00607   -.000001071263908506,
00608    .000000183128394654,
00609   -.000000031353509361,
00610    .000000005372808776,
00611   -.000000000921168141,
00612    .000000000157981265,
00613   -.000000000027098646,
00614    .000000000004648722,
00615   -.000000000000797527,
00616    .000000000000136827,
00617   -.000000000000023475,
00618    .000000000000004027,
00619   -.000000000000000691,
00620    .000000000000000118,
00621   -.000000000000000020
00622 };
00623 const static cheb_series psi_cs = { psics_data, 22, -1, 1, 17 };
00624 
00625 // ######################################################################
00626 static double apsics_data[16] = {
00627   -.0204749044678185,
00628   -.0101801271534859,
00629    .0000559718725387,
00630   -.0000012917176570,
00631    .0000000572858606,
00632   -.0000000038213539,
00633    .0000000003397434,
00634   -.0000000000374838,
00635    .0000000000048990,
00636   -.0000000000007344,
00637    .0000000000001233,
00638   -.0000000000000228,
00639    .0000000000000045,
00640   -.0000000000000009,
00641    .0000000000000002,
00642   -.0000000000000000
00643 };
00644 const static cheb_series apsi_cs = { apsics_data, 15, -1, 1, 9 };
00645 
00646 // ######################################################################
00647 // Ripped from GSL, the GNU scientific library, function
00648 // cheb_eval_e(); modified to eliminate the error computation and just
00649 // return the result:
00650 
00651 inline double cheb_eval(const cheb_series* cs, const double x)
00652 {
00653   double d  = 0.0, dd = 0.0;
00654 
00655   const double y  = (2.0*x - cs->a - cs->b) * (1.0/(cs->b - cs->a));
00656   //Was: const double y  = (2.0*x - cs->a - cs->b) / (cs->b - cs->a);
00657   const double y2 = 2.0 * y;
00658 
00659   for (uint j = cs->order; j >= 1; j--)
00660     {
00661       const double temp = d;
00662       d = y2*d - dd + cs->c[j];
00663       dd = temp;
00664     }
00665 
00666   return y*d - dd + 0.5 * cs->c[0];
00667 }
00668 
00669 // ######################################################################
00670 // This is the Chebyshev evaluation manually speciallized. This is *probably*
00671 // faster than the non specialized version since no structures are used and
00672 // there are no pointers. This depends on the compiler and flags used. At
00673 // worst it's just as fast as the non specialized version
00674  
00675 inline double cheb_eval_psi(const double x)
00676 {
00677   double d  = 0.0, dd = 0.0;
00678 
00679   const double y2 = 2.0 * x;
00680 
00681   for (uint j = 22; j >= 1; j--)
00682     {
00683       const double temp = d;
00684       d = y2*d - dd + psics_data[j];
00685       dd = temp;
00686     }
00687 
00688   return x*d - dd + 0.5 * -.038057080835217922;
00689 }
00690 
00691 inline double cheb_eval_apsi(const double x)
00692 {
00693   double d  = 0.0, dd = 0.0;
00694 
00695   const double y2 = 2.0 * x;
00696 
00697   for (uint j = 15; j >= 1; j--)
00698     {
00699       const double temp = d;
00700       d = y2*d - dd + apsics_data[j];
00701       dd = temp;
00702     }
00703 
00704   return x*d - dd + 0.5 * -.0204749044678185;
00705 }
00706 
00707 // ######################################################################
00708 // Ripped from GSL, the GNU scientific library, function psi_x();
00709 // modified to eliminate the error computation and just return the
00710 // result:
00711 inline double psi(const double x)
00712 {
00713   if (x >= 2.0)
00714     {
00715       /*
00716       const double d    = 1.0 / x;
00717       const double t    = 8.0 * d * d - 1.0;
00718       const double cheb = cheb_eval(&apsi_cs, t);
00719       return fastLog(x) - 0.5 * d + cheb;
00720       */
00721       const double t    = 8.0 / (x*x) - 1.0;
00722       const double cheb = cheb_eval(&apsi_cs, t);
00723       return fastLog(x) - 0.5 / x + cheb;
00724     }
00725   else if (x < 1.0)
00726     {
00727       if( x <= 0.0)
00728         LFATAL("Digamma (Psi) Only defined for x > 0.0");
00729 
00730       const double t1   = 1.0 / x;
00731       const double cheb = cheb_eval(&psi_cs, 2.0*x-1.0);
00732       return cheb - t1;
00733     }
00734   else
00735     {
00736       const double v = x - 1.0;
00737       return cheb_eval(&psi_cs, 2.0*v-1.0);
00738 
00739     }
00740 }
00741 
00742 // ######################################################################
00743 // Somewhat faster psi. dumps error checking and structure usage.
00744 inline double fast_psi(const double x)
00745 {
00746   if (x >= 2.0)
00747     {
00748       const double t    = 8.0 / (x*x) - 1.0;
00749       const double cheb = cheb_eval_apsi(t);
00750       return fastLog(x) - 0.5 / x + cheb;
00751     }
00752   else if (x < 1.0)
00753     {
00754       const double t1   = 1.0 / x;
00755       const double cheb = cheb_eval_psi(2.0*x-1.0);
00756       return cheb - t1;
00757     }
00758   else
00759     {
00760       const double v = x - 1.0;
00761       return cheb_eval_psi(2.0*v-1.0);
00762     }
00763 }
00764 
00765 // ######################################################################
00766 // ##### Kullback-Leibler (KL) distances
00767 // ######################################################################
00768 //! Convert a number into Wows, for instance a KL distance
00769 /*! Wow's in this computation is the same as the conversion
00770   from Nats to Bits in KL
00771 */
00772 template <class T> inline T wow(const T& k)
00773 {
00774   // surprise should always be positive but rounding may mess that up:
00775   // This is OK since surprise is negative with equality if and only
00776   // if two distribution functions are equal. Thus, we gain no insite
00777   // with negative surprise.
00778 
00779   if (k < 0.0) return 0.0;
00780   // return the surprise, in units of wows (KL Bits):
00781   return k * (1.0F/D_LOG_2);
00782 }
00783 
00784 // ######################################################################
00785 //! Compute the KL distance for a joint gamma PDF
00786 /*!
00787   @param ai New Alpha in model i
00788   @param aj New Alpha in model j
00789   @param bi New Beta  in model i
00790   @param bj New Beta  in model j
00791   @param Ai Current Alpha in model i
00792   @param Aj Current Alpha in model j
00793   @param Bi Current Beta  in model i
00794   @param Bj Current Beta  in model j
00795   @param doWow is true then convert output to Wows
00796 
00797   This formula derived by T. Nathan Mundhenk 2007
00798 */
00799 template <class T> inline T KLjointGammaGamma(const T ai,const T aj,
00800                                               const T bi,const T bj,
00801                                               const T Ai,const T Aj,
00802                                               const T Bi,const T Bj,
00803                                               const bool doWow = false,
00804                                               const T gammaBiasi = 1.0F,
00805                                               const T gammaBiasj = 1.0F)
00806 {
00807 
00808   /* We will compute the joint KL for P(x), P(X), P(y) and P(Y) where
00809      they are gamma distributions.
00810 
00811                                P(X) P(Y)
00812   KL = Integrate[P(x) P(y) log[---------] ]
00813                                P(x) P(y)
00814 
00815      ai - New Alpha in model i
00816      aj - New Alpha in model j
00817      bi - New Beta  in model i
00818      bj - New Beta  in model j
00819 
00820      Ai - Current Alpha in model i
00821      Aj - Current Alpha in model j
00822      Bi - Current Beta  in model i
00823      Bj - Current Beta  in model j
00824 
00825                      ai Bi   aj Bj          bi           bj
00826   KL =    -ai - aj + ----- + ----- - Ai Log[--] - Aj Log[--] +
00827                       bi      bj            Bi           Bj
00828 
00829          Gamma[Ai] Gamma[Aj]
00830 >    Log[-------------------] - (-ai + Ai) PolyGamma[0, ai] -
00831          Gamma[ai] Gamma[aj]
00832 
00833 >    (-aj + Aj) PolyGamma[0, aj]
00834 
00835 
00836   Note: Since the pure Gamma function can get large very quickly, we avoid
00837   large numbers by computing the log gamma directly as lgamma.
00838 
00839   */
00840 
00841   // Simplified a little from the above:
00842   const T k = gammaBiasi * KLgamma(ai,bi,Ai,Bi) + gammaBiasj * KLgamma(aj,bj,Aj,Bj);
00843 
00844   if(doWow) return wow(k);
00845   else      return k;
00846 }
00847 
00848 // ######################################################################
00849 //! Compute the KL distance for a joint gamma gauss PDF
00850 /*!
00851   @param a  New Alpha in model 1
00852   @param b  New Beta  in model 1
00853   @param u  New Mean  in model 2
00854   @param s  New Std.  in model 2
00855   @param A  Current Alpha in model 1
00856   @param B  Current Beta  in model 1
00857   @param U  Current Mean  in model 2
00858   @param S  Current Std.  in model 2
00859   @param doWow is true then convert output to Wows
00860 
00861   This formula derived by T. Nathan Mundhenk 2007
00862 */
00863 template <class T> inline T KLjointGammaGauss(const T a,const T u,
00864                                               const T b,const T s,
00865                                               const T A,const T U,
00866                                               const T B,const T S,
00867                                               const bool doWow = false,
00868                                               const T gammaBias = 1.0F,
00869                                               const T gaussBias = 1.0F)
00870 {
00871 
00872   /* We will compute the joint KL for P(x), P(X), P(y) and P(Y)
00873      where one is a gamma distribution and the other gaussian as:
00874 
00875                                P(X) P(Y)
00876   KL = Integrate[P(x) P(y) log[---------] ]
00877                                P(x) P(y)
00878 
00879      a - New Alpha in model 1
00880      b - New Beta  in model 1
00881      u - New Mean  in model 2
00882      s - New Std.  in model 2
00883 
00884      A - Current Alpha in model 1
00885      B - Current Beta  in model 1
00886      U - Current Mean  in model 2
00887      S - Current Std.  in model 2
00888 
00889                              2           2
00890             1        a B    s     (u - U)          B        s
00891         = -(-) + a - --- + ---- + -------- + A Log[-] - Log[-] +
00892             2         b       2        2           b        S
00893                            2 S      2 S
00894 
00895          Gamma[a]
00896 >    Log[--------] - (a - A) PolyGamma[0, a]
00897          Gamma[A]
00898 */
00899  
00900   const T k = gammaBias * KLgamma(a,b,A,B) + gaussBias * KLgauss(u,s,U,S);
00901 
00902   if(doWow) return wow(k);
00903   else      return k;
00904 }
00905 
00906 // ######################################################################
00907 //! Compute the KL distance for a single gamma PDF
00908 /*!
00909   @param a New Alpha
00910   @param b New Beta
00911   @param A Current Alpha
00912   @param B Current Beta
00913   @param doWow is true then convert output to Wows
00914 */
00915 template <class T> inline T KLgamma(const T a,const T b,
00916                                     const T A,const T B,
00917                                     const bool doWow = false)
00918 {
00919   /* We will compute the joint KL for P(x), P(X), P(y) and P(Y)
00920      where one is a gamma distribution and the other gaussian as:
00921 
00922      surprise is KL(new || old):
00923 
00924                           P(X)
00925   KL = Integrate[P(x) log[----] ]
00926                           P(x)
00927 
00928      a - New Alpha
00929      b - New Beta
00930      A - Current Alpha
00931      B - Current Beta
00932 
00933                a B         b        Gamma[A]
00934   KL    = -a + --- + A Log[-] + Log[--------] + a PolyGamma[0, a] -
00935                 b          B        Gamma[a]
00936 
00937 >    A * PolyGamma[0, a]
00938 
00939   Note: Since the pure Gamma function can get large very quickly, we avoid
00940   large numbers by computing the log gamma directly as lgamma.
00941   */
00942 
00943   const T k =  - a + a*B/b + A*fastLog(b/B) + lgamma(A) - lgamma(a)
00944                + (a - A)*fast_psi(a);
00945 
00946   if(doWow) return wow(k);
00947   else      return k;
00948 }
00949 
00950 // ######################################################################
00951 //! Compute the KL distance for a single gamma PDF
00952 /*!
00953   This method produces the best results for usage with RSVP data as measured
00954   by the MAG when using the example values for C1 and C2. It is also faster
00955   than the basic KL computation since we eliminate two divisions and one log
00956   computation.
00957 
00958   @param a New Alpha
00959   @param A Current Alpha
00960   @param C1 the const standin for B/b - 1
00961   @param C2 the const standin for log(b/B)
00962   @param doWow is true then convert output to Wows
00963 */
00964 template <class T> inline T KLgammaConst(const T a,  const T A,
00965                                          const T C1, const T C2,
00966                                          const bool doWow = false)
00967 {
00968   /* We will compute the joint KL for P(x), P(X), P(y) and P(Y)
00969      where one is a gamma distribution and the other gaussian as:
00970 
00971      surprise is KL(new || old):
00972 
00973                           P(X)
00974   KL = Integrate[P(x) log[----] ]
00975                           P(x)
00976 
00977      a - New Alpha
00978      A - Current Alpha
00979 
00980                                      Gamma[A]
00981   KL    = -a + a * C1 + A * C2 + Log[--------] + a PolyGamma[0, a] -
00982                                      Gamma[a]
00983 
00984 >    A * PolyGamma[0, a]
00985 
00986   This simplifies a little to:
00987 
00988          k =  a*C1 + A*C2 + lgamma(A) - lgamma(a) + (a - A)*psi(a)
00989 
00990   NOTES: (1) Psi is the same as the first order PolyGamma
00991          (2) lgamma(A) - lgamma(a) is a simplification of the Log gamma part
00992 
00993   Note: Since the pure Gamma function can get large very quickly, we avoid
00994   large numbers by computing the log gamma directly as lgamma.
00995 
00996   Examples of good values for C1 and C2 are:
00997 
00998          C1 = D_SQRT_2/2.0F - 1.0F  (i.e. sqrt(2)/2 - 1 )
00999          C2 = D_LOG_SQRT_2          (i.e. log(sqrt(2))  )
01000 
01001   Also notice, if a = A then:
01002          
01003          k = a*(C1 + C2)
01004   */
01005 
01006   const T k =  a*C1 + A*C2 + lgamma(A) - lgamma(a) + (a - A)*fast_psi(a);
01007 
01008   if(doWow) return wow(k);
01009   else      return k;
01010 }
01011 
01012 // ######################################################################
01013 //! Compute the KL distance for a single gamma PDF
01014 /*!
01015   Here we fix beta to be 1. This is a special case, but if we have it
01016   we can compute KL much faster. We can also use this if beta1 = beta2
01017   The Chi Square is one such case where beta is 1/2 .
01018 
01019   @param a New Alpha
01020   @param A Current Alpha 
01021   @param doWow is true then convert output to Wows
01022 */
01023 template <class T> inline T KLgamma(const T a,const T A,
01024                                     const bool doWow = false)
01025 {
01026   /*
01027   Note: Since the pure Gamma function can get large very quickly, we avoid
01028   large numbers by computing the log gamma directly as lgamma.
01029   */
01030 
01031   const T k = lgamma(A) - lgamma(a) + (a - A)*fast_psi(a);
01032 
01033   if(doWow) return wow(k);
01034   else      return k;
01035 }
01036 
01037 // ######################################################################
01038 //! Compute the KL distance for a single gauss PDF
01039 /*!
01040   @param u New Mean
01041   @param s New Std.
01042   @param U Current Mean
01043   @param S Current Std.
01044   @param doWow is true then convert output to Wows
01045 */
01046 template <class T> inline T KLgauss(const T u,const T s,
01047                                     const T U,const T S,
01048                                     const bool doWow = false)
01049 {
01050   /* Compute the KL distance between two Gaussian PDFs as:
01051 
01052                           P(X)
01053   KL = Integrate[P(x) log[----] ]
01054                           P(x)
01055 
01056     u - New Mean
01057     s - New Std.
01058     U - Current Mean
01059     S - Current Std.
01060 
01061                       2            2
01062              -1     s      (u - U)        s
01063   KL =    - (--- + ----- + -------- - Log[-])
01064               2        2         2        S
01065                     2 S       2 S
01066   */
01067 
01068   const T iS = 1.0 / 2*S*S;
01069   const T x  = s*s * iS; 
01070   const T mm = (u - U)*(u - U);
01071   const T k  = -1.0 * (x - 0.5 - log(s/S) + mm * iS);
01072 
01073   if(doWow)
01074     return wow(k);
01075   else
01076     return k;
01077 }
01078 
01079 // return the AUC of two vectors
01080 double AUC(const float* model, const float* rand,
01081            size_t sm, size_t sr,
01082            const double step = 0.1);
01083 
01084 #endif
01085 /* So things look consistent in everyone's emacs... */
01086 /* Local Variables: */
01087 /* indent-tabs-mode: nil */
01088 /* End: */

Generated on Mon Nov 23 15:47:25 2009 for iLab Neuromorphic Vision Toolkit by  doxygen 1.4.4