annotate maths/MathUtilities.cpp @ 194:26daede606a8

Add L^p norms, doc, tests
author Chris Cannam
date Wed, 07 Oct 2015 11:14:16 +0100
parents e4a57215ddee
children
rev   line source
cannam@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@0 2
cannam@0 3 /*
cannam@0 4 QM DSP Library
cannam@0 5
cannam@0 6 Centre for Digital Music, Queen Mary, University of London.
Chris@84 7 This file 2005-2006 Christian Landone.
Chris@84 8
Chris@84 9 This program is free software; you can redistribute it and/or
Chris@84 10 modify it under the terms of the GNU General Public License as
Chris@84 11 published by the Free Software Foundation; either version 2 of the
Chris@84 12 License, or (at your option) any later version. See the file
Chris@84 13 COPYING included with this distribution for more information.
cannam@0 14 */
cannam@0 15
cannam@0 16 #include "MathUtilities.h"
cannam@0 17
cannam@0 18 #include <iostream>
Chris@123 19 #include <algorithm>
Chris@123 20 #include <vector>
cannam@0 21 #include <cmath>
cannam@0 22
Chris@194 23 using namespace std;
cannam@0 24
cannam@0 25 double MathUtilities::mod(double x, double y)
cannam@0 26 {
cannam@0 27 double a = floor( x / y );
cannam@0 28
cannam@0 29 double b = x - ( y * a );
cannam@0 30 return b;
cannam@0 31 }
cannam@0 32
cannam@0 33 double MathUtilities::princarg(double ang)
cannam@0 34 {
cannam@0 35 double ValOut;
cannam@0 36
cannam@0 37 ValOut = mod( ang + M_PI, -2 * M_PI ) + M_PI;
cannam@0 38
cannam@0 39 return ValOut;
cannam@0 40 }
cannam@0 41
Chris@189 42 void MathUtilities::getAlphaNorm(const double *data, int len, int alpha, double* ANorm)
cannam@0 43 {
Chris@189 44 int i;
cannam@0 45 double temp = 0.0;
cannam@0 46 double a=0.0;
cannam@0 47
cannam@0 48 for( i = 0; i < len; i++)
cannam@0 49 {
cannam@0 50 temp = data[ i ];
cannam@0 51
cannam@79 52 a += ::pow( fabs(temp), double(alpha) );
cannam@0 53 }
cannam@0 54 a /= ( double )len;
cannam@0 55 a = ::pow( a, ( 1.0 / (double) alpha ) );
cannam@0 56
cannam@0 57 *ANorm = a;
cannam@0 58 }
cannam@0 59
Chris@194 60 double MathUtilities::getAlphaNorm( const vector <double> &data, int alpha )
cannam@0 61 {
Chris@189 62 int i;
Chris@189 63 int len = data.size();
cannam@0 64 double temp = 0.0;
cannam@0 65 double a=0.0;
cannam@0 66
cannam@0 67 for( i = 0; i < len; i++)
cannam@0 68 {
cannam@0 69 temp = data[ i ];
cannam@79 70 a += ::pow( fabs(temp), double(alpha) );
cannam@0 71 }
cannam@0 72 a /= ( double )len;
cannam@0 73 a = ::pow( a, ( 1.0 / (double) alpha ) );
cannam@0 74
cannam@0 75 return a;
cannam@0 76 }
cannam@0 77
cannam@0 78 double MathUtilities::round(double x)
cannam@0 79 {
Chris@123 80 if (x < 0) {
Chris@123 81 return -floor(-x + 0.5);
Chris@123 82 } else {
Chris@123 83 return floor(x + 0.5);
Chris@123 84 }
cannam@0 85 }
cannam@0 86
Chris@189 87 double MathUtilities::median(const double *src, int len)
cannam@0 88 {
Chris@123 89 if (len == 0) return 0;
Chris@123 90
Chris@194 91 vector<double> scratch;
Chris@123 92 for (int i = 0; i < len; ++i) scratch.push_back(src[i]);
Chris@194 93 sort(scratch.begin(), scratch.end());
cannam@0 94
Chris@123 95 int middle = len/2;
Chris@123 96 if (len % 2 == 0) {
Chris@123 97 return (scratch[middle] + scratch[middle - 1]) / 2;
Chris@123 98 } else {
Chris@123 99 return scratch[middle];
cannam@0 100 }
cannam@0 101 }
cannam@0 102
Chris@189 103 double MathUtilities::sum(const double *src, int len)
cannam@0 104 {
Chris@189 105 int i ;
cannam@0 106 double retVal =0.0;
cannam@0 107
cannam@0 108 for( i = 0; i < len; i++)
cannam@0 109 {
cannam@0 110 retVal += src[ i ];
cannam@0 111 }
cannam@0 112
cannam@0 113 return retVal;
cannam@0 114 }
cannam@0 115
Chris@189 116 double MathUtilities::mean(const double *src, int len)
cannam@0 117 {
cannam@0 118 double retVal =0.0;
cannam@0 119
Chris@123 120 if (len == 0) return 0;
Chris@123 121
cannam@0 122 double s = sum( src, len );
cannam@0 123
cannam@0 124 retVal = s / (double)len;
cannam@0 125
cannam@0 126 return retVal;
cannam@0 127 }
cannam@0 128
Chris@194 129 double MathUtilities::mean(const vector<double> &src,
Chris@189 130 int start,
Chris@189 131 int count)
cannam@54 132 {
cannam@54 133 double sum = 0.;
cannam@54 134
Chris@123 135 if (count == 0) return 0;
Chris@123 136
Chris@102 137 for (int i = 0; i < (int)count; ++i)
cannam@54 138 {
cannam@54 139 sum += src[start + i];
cannam@54 140 }
cannam@54 141
cannam@54 142 return sum / count;
cannam@54 143 }
cannam@54 144
Chris@189 145 void MathUtilities::getFrameMinMax(const double *data, int len, double *min, double *max)
cannam@0 146 {
Chris@189 147 int i;
cannam@0 148 double temp = 0.0;
cannam@58 149
cannam@58 150 if (len == 0) {
cannam@58 151 *min = *max = 0;
cannam@58 152 return;
cannam@58 153 }
cannam@0 154
cannam@0 155 *min = data[0];
cannam@0 156 *max = data[0];
cannam@0 157
cannam@0 158 for( i = 0; i < len; i++)
cannam@0 159 {
cannam@0 160 temp = data[ i ];
cannam@0 161
cannam@0 162 if( temp < *min )
cannam@0 163 {
cannam@0 164 *min = temp ;
cannam@0 165 }
cannam@0 166 if( temp > *max )
cannam@0 167 {
cannam@0 168 *max = temp ;
cannam@0 169 }
cannam@0 170
cannam@0 171 }
cannam@0 172 }
cannam@7 173
Chris@189 174 int MathUtilities::getMax( double* pData, int Length, double* pMax )
cannam@7 175 {
Chris@189 176 int index = 0;
Chris@189 177 int i;
cannam@7 178 double temp = 0.0;
cannam@7 179
cannam@7 180 double max = pData[0];
cannam@7 181
cannam@7 182 for( i = 0; i < Length; i++)
cannam@7 183 {
cannam@7 184 temp = pData[ i ];
cannam@7 185
cannam@7 186 if( temp > max )
cannam@7 187 {
cannam@7 188 max = temp ;
cannam@7 189 index = i;
cannam@7 190 }
cannam@7 191
cannam@7 192 }
cannam@7 193
cannam@54 194 if (pMax) *pMax = max;
cannam@54 195
cannam@54 196
cannam@54 197 return index;
cannam@54 198 }
cannam@54 199
Chris@194 200 int MathUtilities::getMax( const vector<double> & data, double* pMax )
cannam@54 201 {
Chris@189 202 int index = 0;
Chris@189 203 int i;
cannam@54 204 double temp = 0.0;
cannam@54 205
cannam@54 206 double max = data[0];
cannam@54 207
Chris@189 208 for( i = 0; i < int(data.size()); i++)
cannam@54 209 {
cannam@54 210 temp = data[ i ];
cannam@54 211
cannam@54 212 if( temp > max )
cannam@54 213 {
cannam@54 214 max = temp ;
cannam@54 215 index = i;
cannam@54 216 }
cannam@54 217
cannam@54 218 }
cannam@54 219
cannam@54 220 if (pMax) *pMax = max;
cannam@7 221
cannam@7 222
cannam@7 223 return index;
cannam@7 224 }
cannam@7 225
cannam@7 226 void MathUtilities::circShift( double* pData, int length, int shift)
cannam@7 227 {
cannam@7 228 shift = shift % length;
cannam@7 229 double temp;
cannam@7 230 int i,n;
cannam@7 231
cannam@7 232 for( i = 0; i < shift; i++)
cannam@7 233 {
cannam@7 234 temp=*(pData + length - 1);
cannam@7 235
cannam@7 236 for( n = length-2; n >= 0; n--)
cannam@7 237 {
cannam@7 238 *(pData+n+1)=*(pData+n);
cannam@7 239 }
cannam@7 240
cannam@7 241 *pData = temp;
cannam@7 242 }
cannam@7 243 }
cannam@7 244
cannam@7 245 int MathUtilities::compareInt (const void * a, const void * b)
cannam@7 246 {
cannam@7 247 return ( *(int*)a - *(int*)b );
cannam@7 248 }
cannam@7 249
cannam@34 250 void MathUtilities::normalise(double *data, int length, NormaliseType type)
cannam@34 251 {
cannam@34 252 switch (type) {
cannam@34 253
cannam@34 254 case NormaliseNone: return;
cannam@34 255
cannam@34 256 case NormaliseUnitSum:
cannam@34 257 {
cannam@34 258 double sum = 0.0;
cannam@34 259 for (int i = 0; i < length; ++i) {
cannam@34 260 sum += data[i];
cannam@34 261 }
cannam@34 262 if (sum != 0.0) {
cannam@34 263 for (int i = 0; i < length; ++i) {
cannam@34 264 data[i] /= sum;
cannam@34 265 }
cannam@34 266 }
cannam@34 267 }
cannam@34 268 break;
cannam@34 269
cannam@34 270 case NormaliseUnitMax:
cannam@34 271 {
cannam@34 272 double max = 0.0;
cannam@34 273 for (int i = 0; i < length; ++i) {
cannam@34 274 if (fabs(data[i]) > max) {
cannam@34 275 max = fabs(data[i]);
cannam@34 276 }
cannam@34 277 }
cannam@34 278 if (max != 0.0) {
cannam@34 279 for (int i = 0; i < length; ++i) {
cannam@34 280 data[i] /= max;
cannam@34 281 }
cannam@34 282 }
cannam@34 283 }
cannam@34 284 break;
cannam@34 285
cannam@34 286 }
cannam@34 287 }
cannam@34 288
Chris@194 289 void MathUtilities::normalise(vector<double> &data, NormaliseType type)
cannam@34 290 {
cannam@34 291 switch (type) {
cannam@34 292
cannam@34 293 case NormaliseNone: return;
cannam@34 294
cannam@34 295 case NormaliseUnitSum:
cannam@34 296 {
cannam@34 297 double sum = 0.0;
Chris@102 298 for (int i = 0; i < (int)data.size(); ++i) sum += data[i];
cannam@34 299 if (sum != 0.0) {
Chris@102 300 for (int i = 0; i < (int)data.size(); ++i) data[i] /= sum;
cannam@34 301 }
cannam@34 302 }
cannam@34 303 break;
cannam@34 304
cannam@34 305 case NormaliseUnitMax:
cannam@34 306 {
cannam@34 307 double max = 0.0;
Chris@102 308 for (int i = 0; i < (int)data.size(); ++i) {
cannam@34 309 if (fabs(data[i]) > max) max = fabs(data[i]);
cannam@34 310 }
cannam@34 311 if (max != 0.0) {
Chris@102 312 for (int i = 0; i < (int)data.size(); ++i) data[i] /= max;
cannam@34 313 }
cannam@34 314 }
cannam@34 315 break;
cannam@34 316
cannam@34 317 }
cannam@34 318 }
cannam@34 319
Chris@194 320 double MathUtilities::getLpNorm(const vector<double> &data, int p)
Chris@194 321 {
Chris@194 322 double tot = 0.0;
Chris@194 323 for (int i = 0; i < int(data.size()); ++i) {
Chris@194 324 tot += abs(pow(data[i], p));
Chris@194 325 }
Chris@194 326 return pow(tot, 1.0 / p);
Chris@194 327 }
Chris@194 328
Chris@194 329 vector<double> MathUtilities::normaliseLp(const vector<double> &data,
Chris@194 330 int p,
Chris@194 331 double threshold)
Chris@194 332 {
Chris@194 333 int n = int(data.size());
Chris@194 334 if (n == 0 || p == 0) return data;
Chris@194 335 double norm = getLpNorm(data, p);
Chris@194 336 if (norm < threshold) {
Chris@194 337 return vector<double>(n, 1.0 / pow(n, 1.0 / p)); // unit vector
Chris@194 338 }
Chris@194 339 vector<double> out(n);
Chris@194 340 for (int i = 0; i < n; ++i) {
Chris@194 341 out[i] = data[i] / norm;
Chris@194 342 }
Chris@194 343 return out;
Chris@194 344 }
Chris@194 345
Chris@194 346 void MathUtilities::adaptiveThreshold(vector<double> &data)
cannam@54 347 {
cannam@54 348 int sz = int(data.size());
cannam@54 349 if (sz == 0) return;
cannam@54 350
Chris@194 351 vector<double> smoothed(sz);
cannam@54 352
cannam@54 353 int p_pre = 8;
cannam@54 354 int p_post = 7;
cannam@54 355
cannam@54 356 for (int i = 0; i < sz; ++i) {
cannam@54 357
Chris@194 358 int first = max(0, i - p_pre);
Chris@194 359 int last = min(sz - 1, i + p_post);
cannam@54 360
cannam@54 361 smoothed[i] = mean(data, first, last - first + 1);
cannam@54 362 }
cannam@54 363
cannam@54 364 for (int i = 0; i < sz; i++) {
cannam@54 365 data[i] -= smoothed[i];
cannam@54 366 if (data[i] < 0.0) data[i] = 0.0;
cannam@54 367 }
cannam@54 368 }
cannam@34 369
cannam@55 370 bool
cannam@55 371 MathUtilities::isPowerOfTwo(int x)
cannam@55 372 {
Chris@123 373 if (x < 1) return false;
cannam@55 374 if (x & (x-1)) return false;
cannam@55 375 return true;
cannam@55 376 }
cannam@55 377
cannam@55 378 int
cannam@55 379 MathUtilities::nextPowerOfTwo(int x)
cannam@55 380 {
cannam@55 381 if (isPowerOfTwo(x)) return x;
Chris@123 382 if (x < 1) return 1;
cannam@55 383 int n = 1;
cannam@55 384 while (x) { x >>= 1; n <<= 1; }
cannam@55 385 return n;
cannam@55 386 }
cannam@55 387
cannam@55 388 int
cannam@55 389 MathUtilities::previousPowerOfTwo(int x)
cannam@55 390 {
cannam@55 391 if (isPowerOfTwo(x)) return x;
Chris@123 392 if (x < 1) return 1;
cannam@55 393 int n = 1;
cannam@55 394 x >>= 1;
cannam@55 395 while (x) { x >>= 1; n <<= 1; }
cannam@55 396 return n;
cannam@55 397 }
cannam@55 398
cannam@55 399 int
cannam@55 400 MathUtilities::nearestPowerOfTwo(int x)
cannam@55 401 {
cannam@55 402 if (isPowerOfTwo(x)) return x;
Chris@123 403 int n0 = previousPowerOfTwo(x), n1 = nextPowerOfTwo(x);
cannam@55 404 if (x - n0 < n1 - x) return n0;
cannam@55 405 else return n1;
cannam@55 406 }
cannam@55 407
Chris@135 408 double
Chris@123 409 MathUtilities::factorial(int x)
Chris@123 410 {
Chris@123 411 if (x < 0) return 0;
Chris@135 412 double f = 1;
Chris@123 413 for (int i = 1; i <= x; ++i) {
Chris@123 414 f = f * i;
Chris@123 415 }
Chris@123 416 return f;
Chris@123 417 }
Chris@123 418
Chris@125 419 int
Chris@125 420 MathUtilities::gcd(int a, int b)
Chris@125 421 {
Chris@125 422 int c = a % b;
Chris@125 423 if (c == 0) {
Chris@125 424 return b;
Chris@125 425 } else {
Chris@125 426 return gcd(b, c);
Chris@125 427 }
Chris@125 428 }
Chris@125 429