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: */