00001 /*!@file Util/MathFunctions.C 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.C $ 00035 // $Id: MathFunctions.C 14590 2011-03-10 22:25:43Z lior $ 00036 // 00037 00038 #include "Util/MathFunctions.H" 00039 #include "Util/log.H" 00040 #include <cmath> 00041 #include <sys/types.h> // for getpid() 00042 #include <unistd.h> // for getpid() 00043 00044 // ###################################################################### 00045 bool isFinite(const byte& arg) { return true; } 00046 bool isFinite(const int16& arg) { return true; } 00047 bool isFinite(const int32& arg) { return true; } 00048 00049 #if !defined(MISSING_ISINF) 00050 bool isFinite(const float& arg) { return !isinf(arg); } 00051 bool isFinite(const double& arg) { return !isinf(arg); } 00052 #elif defined(HAVE_STD_ISFINITE) 00053 bool isFinite(const float& arg) { return std::isfinite(arg); } 00054 bool isFinite(const double& arg) { return std::isfinite(arg); } 00055 #elif defined(HAVE_ISFINITE) 00056 bool isFinite(const float& arg) { return isfinite(arg); } 00057 bool isFinite(const double& arg) { return isfinite(arg); } 00058 #elif defined(HAVE___ISFINITEF) 00059 // Use built-in functions, e.g. on Mac OSX 00060 bool isFinite(const float& arg) { return __isfinitef(arg); } 00061 bool isFinite(const double& arg) { return __isfinited(arg); } 00062 #else 00063 bool isFinite(const float& arg) { return true; } 00064 bool isFinite(const double& arg) { return true; } 00065 #endif 00066 00067 // ##################################################################### 00068 void initRandomNumbers() 00069 { 00070 #ifdef HAVE_SRAND48 00071 srand48(time(0) + getpid() * 123); 00072 #endif 00073 srand(time(0) + getpid() * 345); 00074 } 00075 00076 // ##################################################################### 00077 void initRandomNumbersZero() 00078 { 00079 #ifdef HAVE_SRAND48 00080 srand48(0); 00081 #endif 00082 srand(0); 00083 } 00084 00085 // ##################################################################### 00086 double randomDouble() 00087 { 00088 #ifdef HAVE_SRAND48 00089 return drand48(); 00090 #else 00091 return double(rand()) / (double(RAND_MAX) + 1.0); 00092 #endif 00093 } 00094 00095 // ##################################################################### 00096 double randomDoubleFromNormal(const double s) 00097 { 00098 double sum = 0; 00099 for(int i=0; i<12; i++){ 00100 sum += randomDouble()*2*s - s; 00101 } 00102 return sum/2; 00103 } 00104 00105 // ##################################################################### 00106 int randomUpToIncluding(const int n) 00107 { 00108 return randomUpToNotIncluding(n + 1); 00109 } 00110 00111 // ##################################################################### 00112 int randomUpToNotIncluding(const int n) 00113 { 00114 // NOTE: we don't do (RAND%n) because the low-order bits of the 00115 // random number may be less random than the high-order bits 00116 00117 const int result = int(randomDouble() * n); 00118 00119 // randomDouble() is supposed to be in [0.0, 1.0), but just in case 00120 // randomDouble()*n happens to equal n due to floating-point 00121 // weirdness, let's return n-1 to fulfill the "NotIncluding" part of 00122 // our contract: 00123 if (result == n) 00124 return n-1; 00125 00126 return result; 00127 } 00128 00129 // ##################################################################### 00130 double ran2 (int& idum) 00131 { 00132 const int IM1 = 2147483563, IM2 = 2147483399; 00133 const double AM = (1.0/IM1); 00134 const int IMM1 = IM1-1; 00135 const int IA1 = 40014, IA2 = 40692, IQ1 = 53668, IQ2 = 52774; 00136 const int IR1 = 12211, IR2 = 3791, NTAB = 32; 00137 const int NDIV = 1+IMM1/NTAB; 00138 const double EPS = 3.0e-16, RNMX = 1.0-EPS; 00139 00140 int j, k; 00141 static int idum2 = 123456789, iy = 0; 00142 static int iv[NTAB]; 00143 double temp; 00144 00145 if (idum <= 0) { 00146 idum = (idum == 0 ? 1 : -idum); 00147 idum2=idum; 00148 for (j=NTAB+7;j>=0;j--) { 00149 k=idum/IQ1; 00150 idum=IA1*(idum-k*IQ1)-k*IR1; 00151 if (idum < 0) idum += IM1; 00152 if (j < NTAB) iv[j] = idum; 00153 } 00154 iy=iv[0]; 00155 } 00156 k=idum/IQ1; 00157 idum=IA1*(idum-k*IQ1)-k*IR1; 00158 00159 if (idum < 0) idum += IM1; 00160 k=idum2/IQ2; 00161 idum2=IA2*(idum2-k*IQ2)-k*IR2; 00162 if (idum2 < 0) idum2 += IM2; 00163 j=iy/NDIV; 00164 iy=iv[j]-idum2; 00165 iv[j] = idum; 00166 if (iy < 1) iy += IMM1; 00167 if ((temp=AM*iy) > RNMX) return RNMX; 00168 else return temp; 00169 } 00170 00171 // ###################################################################### 00172 int getIdum(const bool useRandom) 00173 { 00174 if (useRandom) 00175 return -(time(NULL) + 17 * getpid()); 00176 else 00177 return -123456; 00178 } 00179 00180 // ###################################################################### 00181 double gasdev (int& idum) { 00182 static int iset = 0; 00183 static double gset; 00184 00185 double fac, rsq, v1, v2; 00186 if (idum < 0) iset = 0; 00187 if (iset == 0) { 00188 do { 00189 v1 = 2.0*ran2(idum)-1.0; 00190 v2 = 2.0*ran2(idum)-1.0; 00191 rsq = v1*v1 + v2*v2; 00192 } while (rsq >= 1.0 || rsq == 0.0); 00193 00194 fac = std::sqrt(-2.0*std::log(rsq)/rsq); 00195 gset = v1*fac; iset = 1; 00196 return v2*fac; 00197 } else { 00198 iset = 0; 00199 return gset; 00200 } 00201 } 00202 00203 // ###################################################################### 00204 double expdev(int& idum) 00205 { 00206 double dum; 00207 do dum = ran2(idum); while (dum == 0.0); 00208 return -log(dum); 00209 } 00210 00211 /* Lanczos method for real x > 0; 00212 * gamma=7, truncated at 1/(z+8) 00213 * [J. SIAM Numer. Anal, Ser. B, 1 (1964) 86] 00214 */ 00215 double lngamma(double x) 00216 { 00217 00218 #ifdef HAVE_LGAMMA 00219 return lgamma(x); 00220 #else 00221 00222 // ripped from GSL (see above). 00223 /* coefficients for gamma=7, kmax=8 Lanczos method */ 00224 static const double lanczos_7_c[9] = { 00225 0.99999999999980993227684700473478, 00226 676.520368121885098567009190444019, 00227 -1259.13921672240287047156078755283, 00228 771.3234287776530788486528258894, 00229 -176.61502916214059906584551354, 00230 12.507343278686904814458936853, 00231 -0.13857109526572011689554707, 00232 9.984369578019570859563e-6, 00233 1.50563273514931155834e-7 00234 }; 00235 00236 x -= 1.0; /* Lanczos writes z! instead of Gamma(z) */ 00237 00238 double Ag = lanczos_7_c[0]; 00239 for (int k = 1; k <= 8; k++) { Ag += lanczos_7_c[k] / (x+k); } 00240 00241 /* (x+0.5)*log(x+7.5) - (x+7.5) + LogRootTwoPi_ + log(Ag(x)) */ 00242 const double term1 = (x + 0.5) * log((x + 7.5) / M_E); 00243 const double term2 = D_LOG_SQRT_2_PI + log(Ag); 00244 return term1 + (term2 - 7.0); 00245 #endif 00246 } 00247 00248 // ripped from GSL (see above). Compute probability of getting a value 00249 // k from a Poisson distribution with mean mu: 00250 double poisson(const unsigned int k, const double mu) 00251 { 00252 double lf = lngamma(k+1); 00253 return exp(log(mu) * k - lf - mu); 00254 } 00255 00256 //computes the AUC, inspired by ROC, between two data sets 00257 //the intended use is to compare human eye movements to a random 00258 //model 00259 double AUC(const float* model, const float* rand, 00260 size_t sm, size_t sr, 00261 const double step) 00262 { 00263 //if ((max(model) > 1.0F) || (max(rand) > 1.0F) 00264 //|| (min(model) < 0.0F) || (min(rand) < 0.0F)) 00265 //LFATAL("Vectors must be normalized"); 00266 00267 double auc = 0.0; 00268 double last_tp = 1.0; 00269 double last_fp = 1.0; 00270 00271 for (double thresh = 0.0; thresh <= 1.0+step; thresh+=step) 00272 { 00273 uint tp = 0; 00274 uint fp = 0; 00275 for (size_t jj = 0; jj < sm; ++jj) 00276 if (model[jj] >= thresh) 00277 tp++; 00278 00279 for (size_t jj = 0; jj < sr; ++jj) 00280 if (rand[jj] >= thresh) 00281 fp++; 00282 00283 double fpr = (double)fp/(double)sr; 00284 double tpr = (double)tp/(double)sm; 00285 00286 auc+= ( (last_fp - fpr) * (tpr) ) + 00287 ( 0.5 * (last_fp - fpr) * (last_tp - tpr) ); 00288 00289 last_tp = tpr; 00290 last_fp = fpr; 00291 } 00292 return auc; 00293 } 00294 00295 Point2D<float> getEllipseFromCov(const Image<double>& cov) 00296 { 00297 ASSERT(cov.getWidth() == 2 && cov.getHeight() == 2); 00298 00299 //Using matlab Compute the Mahalanobis radius of the ellipsoid that encloses 00300 //the desired probability mass. 00301 //k = chi2inv(p, 2); where p = 0.9 00302 00303 double k = 4.605170185988091; //From matlab 00304 00305 //Compute the eigen values 00306 double trace = (cov.getVal(0,0) + cov.getVal(1,1))/2; 00307 00308 double a = cov.getVal(0,0) - trace; 00309 double b = cov.getVal(0,1); 00310 00311 double ab2 = sqrt((a*a) + (b*b)); 00312 00313 double l1 = ab2 + trace; 00314 double l2 = -ab2 + trace; 00315 00316 return Point2D<float>(k*sqrt(l1), k*sqrt(l2)); 00317 00318 } 00319 00320 00321 // ###################################################################### 00322 /* So things look consistent in everyone's emacs... */ 00323 /* Local Variables: */ 00324 /* indent-tabs-mode: nil */ 00325 /* End: */