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