annotate query.cpp @ 425:d65410f4bb85 api-inversion

Begin pushing information through. Create and initialize an adb_query_refine_t struct in audioDB::query, and pass it through to various callees, which can then use it instead of the automagic class member variables. This allows conversion of some routines into ordinary static C functions. Begin doing so.
author mas01cr
date Wed, 24 Dec 2008 10:55:16 +0000
parents c6046dd80570
children 4a22a0bdf9a9
rev   line source
mas01cr@239 1 #include "audioDB.h"
mas01cr@239 2 #include "reporter.h"
mas01cr@239 3
mas01cr@422 4 #include "audioDB-internals.h"
mas01cr@422 5 #include "accumulators.h"
mas01cr@422 6
mas01cr@425 7 static bool audiodb_powers_acceptable(adb_query_refine_t *r, double p1, double p2) {
mas01cr@425 8 if (r->flags & ADB_REFINE_ABSOLUTE_THRESHOLD) {
mas01cr@425 9 if ((p1 < r->absolute_threshold) || (p2 < r->absolute_threshold)) {
mas01cr@239 10 return false;
mas01cr@239 11 }
mas01cr@239 12 }
mas01cr@425 13 if (r->flags & ADB_REFINE_RELATIVE_THRESHOLD) {
mas01cr@425 14 if (fabs(p1-p2) > fabs(r->relative_threshold)) {
mas01cr@239 15 return false;
mas01cr@239 16 }
mas01cr@239 17 }
mas01cr@239 18 return true;
mas01cr@239 19 }
mas01cr@239 20
mas01cr@239 21 void audioDB::query(const char* dbName, const char* inFile, adb__queryResponse *adbQueryResponse) {
mas01cr@425 22
mas01cr@425 23 adb_query_refine_t refine;
mas01cr@425 24 refine.flags = 0;
mas01cr@425 25 /* FIXME: trackFile / ADB_REFINE_KEYLIST */
mas01cr@425 26 if(radius) {
mas01cr@425 27 refine.flags |= ADB_REFINE_RADIUS;
mas01cr@425 28 refine.radius = radius;
mas01cr@425 29 }
mas01cr@425 30 if(use_absolute_threshold) {
mas01cr@425 31 refine.flags |= ADB_REFINE_ABSOLUTE_THRESHOLD;
mas01cr@425 32 refine.absolute_threshold = absolute_threshold;
mas01cr@425 33 }
mas01cr@425 34 if(use_relative_threshold) {
mas01cr@425 35 refine.flags |= ADB_REFINE_RELATIVE_THRESHOLD;
mas01cr@425 36 refine.relative_threshold = relative_threshold;
mas01cr@425 37 }
mas01cr@425 38 if(usingTimes) {
mas01cr@425 39 refine.flags |= ADB_REFINE_DURATION_RATIO;
mas01cr@425 40 refine.duration_ratio = timesTol;
mas01cr@425 41 }
mas01cr@425 42 /* FIXME: not sure about this any more; maybe it belongs in query_id */
mas01cr@425 43 if(sequenceHop != 1) {
mas01cr@425 44 refine.flags |= ADB_REFINE_HOP_SIZE;
mas01cr@425 45 refine.hopsize = sequenceHop;
mas01cr@425 46 }
mas01cr@425 47
mas01mc@292 48 // init database tables and dbH first
mas01mc@292 49 if(query_from_key)
mas01mc@292 50 initTables(dbName);
mas01mc@292 51 else
mas01mc@292 52 initTables(dbName, inFile);
mas01mc@292 53
mas01mc@292 54 // keyKeyPos requires dbH to be initialized
mas01mc@292 55 if(query_from_key && (!key || (query_from_key_index = getKeyPos((char*)key))==O2_ERR_KEYNOTFOUND))
mas01mc@292 56 error("Query key not found :",key);
mas01mc@292 57
mas01cr@239 58 switch (queryType) {
mas01cr@239 59 case O2_POINT_QUERY:
mas01cr@239 60 sequenceLength = 1;
mas01cr@239 61 normalizedDistance = false;
mas01mc@292 62 reporter = new pointQueryReporter< std::greater < NNresult > >(pointNN);
mas01cr@422 63 accumulator = new DBAccumulator<adb_result_dist_gt>(pointNN);
mas01cr@239 64 break;
mas01cr@239 65 case O2_TRACK_QUERY:
mas01cr@239 66 sequenceLength = 1;
mas01cr@239 67 normalizedDistance = false;
mas01mc@292 68 reporter = new trackAveragingReporter< std::greater< NNresult > >(pointNN, trackNN, dbH->numFiles);
mas01cr@422 69 accumulator = new PerTrackAccumulator<adb_result_dist_gt>(pointNN, trackNN);
mas01cr@239 70 break;
mas01mc@292 71 case O2_SEQUENCE_QUERY:
mas01mc@292 72 if(no_unit_norming)
mas01mc@292 73 normalizedDistance = false;
mas01cr@422 74 accumulator = new PerTrackAccumulator<adb_result_dist_lt>(pointNN, trackNN);
mas01cr@425 75 if(!(refine.flags & ADB_REFINE_RADIUS)) {
mas01mc@292 76 reporter = new trackAveragingReporter< std::less< NNresult > >(pointNN, trackNN, dbH->numFiles);
mas01cr@239 77 } else {
mas01mc@292 78 if(index_exists(dbName, radius, sequenceLength)){
mas01mc@292 79 char* indexName = index_get_name(dbName, radius, sequenceLength);
mas01mc@308 80 lsh = index_allocate(indexName, false);
mas01mc@324 81 reporter = new trackSequenceQueryRadReporter(trackNN, index_to_trackID(lsh->get_maxp(), lsh_n_point_bits)+1);
mas01mc@292 82 delete[] indexName;
mas01mc@292 83 }
mas01mc@292 84 else
mas01mc@292 85 reporter = new trackSequenceQueryRadReporter(trackNN, dbH->numFiles);
mas01cr@239 86 }
mas01cr@239 87 break;
mas01mc@292 88 case O2_N_SEQUENCE_QUERY:
mas01mc@292 89 if(no_unit_norming)
mas01mc@292 90 normalizedDistance = false;
mas01cr@422 91 accumulator = new PerTrackAccumulator<adb_result_dist_lt>(pointNN, trackNN);
mas01cr@425 92 if(!(refine.flags & ADB_REFINE_RADIUS)) {
mas01mc@292 93 reporter = new trackSequenceQueryNNReporter< std::less < NNresult > >(pointNN, trackNN, dbH->numFiles);
mas01mc@248 94 } else {
mas01mc@292 95 if(index_exists(dbName, radius, sequenceLength)){
mas01mc@292 96 char* indexName = index_get_name(dbName, radius, sequenceLength);
mas01mc@308 97 lsh = index_allocate(indexName, false);
mas01mc@324 98 reporter = new trackSequenceQueryRadNNReporter(pointNN,trackNN, index_to_trackID(lsh->get_maxp(), lsh_n_point_bits)+1);
mas01mc@292 99 delete[] indexName;
mas01mc@292 100 }
mas01mc@292 101 else
mas01mc@292 102 reporter = new trackSequenceQueryRadNNReporter(pointNN,trackNN, dbH->numFiles);
mas01mc@248 103 }
mas01mc@248 104 break;
mas01mc@263 105 case O2_ONE_TO_ONE_N_SEQUENCE_QUERY :
mas01cr@422 106 accumulator = new NearestAccumulator<adb_result_dist_lt>();
mas01cr@425 107 if(!(refine.flags & ADB_REFINE_RADIUS)) {
mas01mc@263 108 error("query-type not yet supported");
mas01mc@263 109 } else {
mas01mc@292 110 reporter = new trackSequenceQueryRadNNReporterOneToOne(pointNN,trackNN, dbH->numFiles);
mas01mc@263 111 }
mas01mc@263 112 break;
mas01cr@239 113 default:
mas01cr@239 114 error("unrecognized queryType in query()");
mas01cr@239 115 }
mas01mc@292 116
mas01mc@292 117 // Test for index (again) here
mas01cr@425 118 if((refine.flags & ADB_REFINE_RADIUS) && index_exists(dbName, radius, sequenceLength)){
mas01mc@329 119 VERB_LOG(1, "Calling indexed query on database %s, radius=%f, sequenceLength=%d\n", dbName, radius, sequenceLength);
mas01cr@425 120 index_query_loop(&refine, dbName, query_from_key_index);
mas01mc@329 121 }
mas01mc@329 122 else{
mas01mc@329 123 VERB_LOG(1, "Calling brute-force query on database %s\n", dbName);
mas01cr@425 124 query_loop(&refine, query_from_key_index);
mas01mc@329 125 }
mas01mc@292 126
mas01cr@423 127 adb_query_results_t *rs = accumulator->get_points();
mas01cr@423 128 for(unsigned int k = 0; k < rs->nresults; k++) {
mas01cr@423 129 adb_result_t r = rs->results[k];
mas01cr@423 130 reporter->add_point(getKeyPos(r.key), r.qpos, r.ipos, r.dist);
mas01cr@423 131 }
mas01cr@423 132
mas01mc@292 133 reporter->report(fileTable, adbQueryResponse);
mas01cr@239 134 }
mas01cr@239 135
mas01cr@239 136 // return ordinal position of key in keyTable
mas01mc@292 137 // this should really be a STL hash map search
mas01cr@423 138 unsigned audioDB::getKeyPos(const char* key){
mas01mc@292 139 if(!dbH)
mas01mc@292 140 error("dbH not initialized","getKeyPos");
mas01cr@239 141 for(unsigned k=0; k<dbH->numFiles; k++)
mas01cr@256 142 if(strncmp(fileTable + k*O2_FILETABLE_ENTRY_SIZE, key, strlen(key))==0)
mas01cr@239 143 return k;
mas01cr@239 144 error("Key not found",key);
mas01cr@239 145 return O2_ERR_KEYNOTFOUND;
mas01cr@239 146 }
mas01cr@239 147
mas01cr@239 148 // This is a common pattern in sequence queries: what we are doing is
mas01cr@239 149 // taking a window of length seqlen over a buffer of length length,
mas01cr@239 150 // and placing the sum of the elements in that window in the first
mas01cr@239 151 // element of the window: thus replacing all but the last seqlen
mas01cr@239 152 // elements in the buffer with the corresponding windowed sum.
mas01cr@239 153 void audioDB::sequence_sum(double *buffer, int length, int seqlen) {
mas01cr@239 154 double tmp1, tmp2, *ps;
mas01cr@239 155 int j, w;
mas01cr@239 156
mas01cr@239 157 tmp1 = *buffer;
mas01cr@239 158 j = 1;
mas01cr@239 159 w = seqlen - 1;
mas01cr@239 160 while(w--) {
mas01cr@239 161 *buffer += buffer[j++];
mas01cr@239 162 }
mas01cr@239 163 ps = buffer + 1;
mas01cr@239 164 w = length - seqlen; // +1 - 1
mas01cr@239 165 while(w--) {
mas01cr@239 166 tmp2 = *ps;
mas01cr@239 167 if(isfinite(tmp1)) {
mas01cr@239 168 *ps = *(ps - 1) - tmp1 + *(ps + seqlen - 1);
mas01cr@239 169 } else {
mas01cr@239 170 for(int i = 1; i < seqlen; i++) {
mas01cr@239 171 *ps += *(ps + i);
mas01cr@239 172 }
mas01cr@239 173 }
mas01cr@239 174 tmp1 = tmp2;
mas01cr@239 175 ps++;
mas01cr@239 176 }
mas01cr@239 177 }
mas01cr@239 178
mas01cr@239 179 // In contrast to sequence_sum() above, sequence_sqrt() and
mas01cr@239 180 // sequence_average() below are simple mappers across the sequence.
mas01cr@239 181 void audioDB::sequence_sqrt(double *buffer, int length, int seqlen) {
mas01cr@239 182 int w = length - seqlen + 1;
mas01cr@239 183 while(w--) {
mas01cr@239 184 *buffer = sqrt(*buffer);
mas01cr@239 185 buffer++;
mas01cr@239 186 }
mas01cr@239 187 }
mas01cr@239 188
mas01cr@239 189 void audioDB::sequence_average(double *buffer, int length, int seqlen) {
mas01cr@239 190 int w = length - seqlen + 1;
mas01cr@239 191 while(w--) {
mas01cr@239 192 *buffer /= seqlen;
mas01cr@239 193 buffer++;
mas01cr@239 194 }
mas01cr@239 195 }
mas01cr@239 196
mas01cr@239 197 void audioDB::initialize_arrays(int track, unsigned int numVectors, double *query, double *data_buffer, double **D, double **DD) {
mas01cr@239 198 unsigned int j, k, l, w;
mas01cr@239 199 double *dp, *qp, *sp;
mas01cr@239 200
mas01cr@239 201 const unsigned HOP_SIZE = sequenceHop;
mas01cr@239 202 const unsigned wL = sequenceLength;
mas01cr@239 203
mas01cr@239 204 for(j = 0; j < numVectors; j++) {
mas01cr@239 205 // Sum products matrix
mas01cr@239 206 D[j] = new double[trackTable[track]];
mas01cr@239 207 assert(D[j]);
mas01cr@239 208 // Matched filter matrix
mas01cr@239 209 DD[j]=new double[trackTable[track]];
mas01cr@239 210 assert(DD[j]);
mas01cr@239 211 }
mas01cr@239 212
mas01cr@239 213 // Dot product
mas01cr@239 214 for(j = 0; j < numVectors; j++)
mas01cr@239 215 for(k = 0; k < trackTable[track]; k++){
mas01cr@239 216 qp = query + j * dbH->dim;
mas01cr@239 217 sp = data_buffer + k * dbH->dim;
mas01cr@239 218 DD[j][k] = 0.0; // Initialize matched filter array
mas01cr@239 219 dp = &D[j][k]; // point to correlation cell j,k
mas01cr@239 220 *dp = 0.0; // initialize correlation cell
mas01cr@239 221 l = dbH->dim; // size of vectors
mas01cr@239 222 while(l--)
mas01cr@239 223 *dp += *qp++ * *sp++;
mas01cr@239 224 }
mas01cr@239 225
mas01cr@239 226 // Matched Filter
mas01cr@239 227 // HOP SIZE == 1
mas01cr@239 228 double* spd;
mas01cr@239 229 if(HOP_SIZE == 1) { // HOP_SIZE = shingleHop
mas01cr@239 230 for(w = 0; w < wL; w++) {
mas01cr@239 231 for(j = 0; j < numVectors - w; j++) {
mas01cr@239 232 sp = DD[j];
mas01cr@239 233 spd = D[j+w] + w;
mas01cr@239 234 k = trackTable[track] - w;
mas01mc@292 235 while(k--)
mas01mc@292 236 *sp++ += *spd++;
mas01cr@239 237 }
mas01cr@239 238 }
mas01cr@239 239 } else { // HOP_SIZE != 1
mas01cr@239 240 for(w = 0; w < wL; w++) {
mas01cr@239 241 for(j = 0; j < numVectors - w; j += HOP_SIZE) {
mas01cr@239 242 sp = DD[j];
mas01cr@239 243 spd = D[j+w]+w;
mas01cr@239 244 for(k = 0; k < trackTable[track] - w; k += HOP_SIZE) {
mas01cr@239 245 *sp += *spd;
mas01cr@239 246 sp += HOP_SIZE;
mas01cr@239 247 spd += HOP_SIZE;
mas01cr@239 248 }
mas01cr@239 249 }
mas01cr@239 250 }
mas01cr@239 251 }
mas01cr@239 252 }
mas01cr@239 253
mas01cr@239 254 void audioDB::delete_arrays(int track, unsigned int numVectors, double **D, double **DD) {
mas01cr@239 255 if(D != NULL) {
mas01cr@239 256 for(unsigned int j = 0; j < numVectors; j++) {
mas01cr@239 257 delete[] D[j];
mas01cr@239 258 }
mas01cr@239 259 }
mas01cr@239 260 if(DD != NULL) {
mas01cr@239 261 for(unsigned int j = 0; j < numVectors; j++) {
mas01cr@239 262 delete[] DD[j];
mas01cr@239 263 }
mas01cr@239 264 }
mas01cr@239 265 }
mas01cr@239 266
mas01mc@324 267 void audioDB::read_data(int trkfid, int track, double **data_buffer_p, size_t *data_buffer_size_p) {
mas01cr@239 268 if (trackTable[track] * sizeof(double) * dbH->dim > *data_buffer_size_p) {
mas01cr@239 269 if(*data_buffer_p) {
mas01cr@239 270 free(*data_buffer_p);
mas01cr@239 271 }
mas01cr@239 272 {
mas01cr@239 273 *data_buffer_size_p = trackTable[track] * sizeof(double) * dbH->dim;
mas01cr@239 274 void *tmp = malloc(*data_buffer_size_p);
mas01cr@239 275 if (tmp == NULL) {
mas01cr@239 276 error("error allocating data buffer");
mas01cr@239 277 }
mas01cr@239 278 *data_buffer_p = (double *) tmp;
mas01cr@239 279 }
mas01cr@239 280 }
mas01cr@239 281
mas01cr@370 282 CHECKED_READ(trkfid, *data_buffer_p, trackTable[track] * sizeof(double) * dbH->dim);
mas01cr@239 283 }
mas01cr@239 284
mas01cr@405 285 void audioDB::insertTimeStamps(unsigned numVectors, std::ifstream *timesFile, double *timesdata) {
mas01cr@405 286 assert(usingTimes);
mas01cr@405 287
mas01cr@405 288 unsigned numtimes = 0;
mas01cr@405 289
mas01cr@405 290 if(!timesFile->is_open()) {
mas01cr@405 291 error("problem opening times file on timestamped database", timesFileName);
mas01cr@405 292 }
mas01cr@405 293
mas01cr@405 294 double timepoint, next;
mas01cr@405 295 *timesFile >> timepoint;
mas01cr@405 296 if (timesFile->eof()) {
mas01cr@405 297 error("no entries in times file", timesFileName);
mas01cr@405 298 }
mas01cr@405 299 numtimes++;
mas01cr@405 300 do {
mas01cr@405 301 *timesFile >> next;
mas01cr@405 302 if (timesFile->eof()) {
mas01cr@405 303 break;
mas01cr@405 304 }
mas01cr@405 305 numtimes++;
mas01cr@405 306 timesdata[0] = timepoint;
mas01cr@405 307 timepoint = (timesdata[1] = next);
mas01cr@405 308 timesdata += 2;
mas01cr@405 309 } while (numtimes < numVectors + 1);
mas01cr@405 310
mas01cr@405 311 if (numtimes < numVectors + 1) {
mas01cr@405 312 error("too few timepoints in times file", timesFileName);
mas01cr@405 313 }
mas01cr@405 314
mas01cr@405 315 *timesFile >> next;
mas01cr@405 316 if (!timesFile->eof()) {
mas01cr@405 317 error("too many timepoints in times file", timesFileName);
mas01cr@405 318 }
mas01cr@405 319 }
mas01cr@405 320
mas01cr@239 321 // These names deserve some unpicking. The names starting with a "q"
mas01cr@239 322 // are pointers to the query, norm and power vectors; the names
mas01cr@239 323 // starting with "v" are things that will end up pointing to the
mas01cr@239 324 // actual query point's information. -- CSR, 2007-12-05
mas01cr@239 325 void audioDB::set_up_query(double **qp, double **vqp, double **qnp, double **vqnp, double **qpp, double **vqpp, double *mqdp, unsigned *nvp) {
mas01cr@239 326 *nvp = (statbuf.st_size - sizeof(int)) / (dbH->dim * sizeof(double));
mas01mc@292 327
mas01cr@239 328 if(!(dbH->flags & O2_FLAG_L2NORM)) {
mas01cr@239 329 error("Database must be L2 normed for sequence query","use -L2NORM");
mas01cr@239 330 }
mas01cr@239 331
mas01cr@239 332 if(*nvp < sequenceLength) {
mas01cr@239 333 error("Query shorter than requested sequence length", "maybe use -l");
mas01cr@239 334 }
mas01cr@239 335
mas01cr@239 336 VERB_LOG(1, "performing norms... ");
mas01cr@239 337
mas01cr@239 338 *qp = new double[*nvp * dbH->dim];
mas01cr@239 339 memcpy(*qp, indata+sizeof(int), *nvp * dbH->dim * sizeof(double));
mas01cr@239 340 *qnp = new double[*nvp];
mas01cr@239 341 unitNorm(*qp, dbH->dim, *nvp, *qnp);
mas01cr@239 342
mas01cr@239 343 sequence_sum(*qnp, *nvp, sequenceLength);
mas01cr@239 344 sequence_sqrt(*qnp, *nvp, sequenceLength);
mas01cr@239 345
mas01cr@239 346 if (usingPower) {
mas01cr@239 347 *qpp = new double[*nvp];
mas01cr@239 348 if (lseek(powerfd, sizeof(int), SEEK_SET) == (off_t) -1) {
mas01cr@239 349 error("error seeking to data", powerFileName, "lseek");
mas01cr@239 350 }
mas01cr@239 351 int count = read(powerfd, *qpp, *nvp * sizeof(double));
mas01cr@239 352 if (count == -1) {
mas01cr@239 353 error("error reading data", powerFileName, "read");
mas01cr@239 354 }
mas01cr@239 355 if ((unsigned) count != *nvp * sizeof(double)) {
mas01cr@239 356 error("short read", powerFileName);
mas01cr@239 357 }
mas01cr@239 358
mas01cr@239 359 sequence_sum(*qpp, *nvp, sequenceLength);
mas01cr@239 360 sequence_average(*qpp, *nvp, sequenceLength);
mas01cr@239 361 }
mas01cr@239 362
mas01cr@239 363 if (usingTimes) {
mas01cr@239 364 unsigned int k;
mas01cr@239 365 *mqdp = 0.0;
mas01cr@239 366 double *querydurs = new double[*nvp];
mas01cr@239 367 double *timesdata = new double[*nvp*2];
mas01cr@239 368 insertTimeStamps(*nvp, timesFile, timesdata);
mas01cr@239 369 for(k = 0; k < *nvp; k++) {
mas01cr@239 370 querydurs[k] = timesdata[2*k+1] - timesdata[2*k];
mas01cr@239 371 *mqdp += querydurs[k];
mas01cr@239 372 }
mas01cr@239 373 *mqdp /= k;
mas01cr@239 374
mas01cr@239 375 VERB_LOG(1, "mean query file duration: %f\n", *mqdp);
mas01cr@239 376
mas01cr@239 377 delete [] querydurs;
mas01cr@239 378 delete [] timesdata;
mas01cr@239 379 }
mas01cr@239 380
mas01cr@239 381 // Defaults, for exhaustive search (!usingQueryPoint)
mas01cr@239 382 *vqp = *qp;
mas01cr@239 383 *vqnp = *qnp;
mas01cr@239 384 *vqpp = *qpp;
mas01cr@239 385
mas01cr@239 386 if(usingQueryPoint) {
mas01mc@341 387 if( !(queryPoint < *nvp && queryPoint < *nvp - sequenceLength + 1) ) {
mas01mc@342 388 error("queryPoint >= numVectors-sequenceLength+1 in query");
mas01cr@239 389 } else {
mas01cr@239 390 VERB_LOG(1, "query point: %u\n", queryPoint);
mas01cr@239 391 *vqp = *qp + queryPoint * dbH->dim;
mas01cr@239 392 *vqnp = *qnp + queryPoint;
mas01cr@239 393 if (usingPower) {
mas01cr@239 394 *vqpp = *qpp + queryPoint;
mas01cr@239 395 }
mas01cr@239 396 *nvp = sequenceLength;
mas01cr@239 397 }
mas01cr@239 398 }
mas01cr@239 399 }
mas01cr@239 400
mas01mc@292 401 // Does the same as set_up_query(...) but from database features instead of from a file
mas01mc@292 402 // Constructs the same outputs as set_up_query
mas01mc@292 403 void audioDB::set_up_query_from_key(double **qp, double **vqp, double **qnp, double **vqnp, double **qpp, double **vqpp, double *mqdp, unsigned *nvp, Uns32T queryIndex) {
mas01mc@292 404 if(!trackTable)
mas01mc@292 405 error("trackTable not initialized","set_up_query_from_key");
mas01mc@292 406
mas01mc@292 407 if(!(dbH->flags & O2_FLAG_L2NORM)) {
mas01mc@292 408 error("Database must be L2 normed for sequence query","use -L2NORM");
mas01mc@292 409 }
mas01mc@292 410
mas01mc@292 411 if(dbH->flags & O2_FLAG_POWER)
mas01mc@292 412 usingPower = true;
mas01mc@292 413
mas01mc@292 414 if(dbH->flags & O2_FLAG_TIMES)
mas01mc@292 415 usingTimes = true;
mas01mc@292 416
mas01mc@292 417 *nvp = trackTable[queryIndex];
mas01mc@292 418 if(*nvp < sequenceLength) {
mas01mc@292 419 error("Query shorter than requested sequence length", "maybe use -l");
mas01mc@292 420 }
mas01mc@292 421
mas01mc@292 422 VERB_LOG(1, "performing norms... ");
mas01mc@292 423
mas01mc@324 424 // For LARGE_ADB load query features from file
mas01mc@324 425 if( dbH->flags & O2_FLAG_LARGE_ADB ){
mas01mc@324 426 if(infid>0)
mas01mc@324 427 close(infid);
mas01mc@324 428 char* prefixedString = new char[O2_MAXFILESTR];
mas01mc@324 429 char* tmpStr = prefixedString;
mas01mc@324 430 strncpy(prefixedString, featureFileNameTable+queryIndex*O2_FILETABLE_ENTRY_SIZE, O2_MAXFILESTR);
mas01mc@324 431 prefix_name(&prefixedString, adb_feature_root);
mas01mc@324 432 if(tmpStr!=prefixedString)
mas01mc@324 433 delete[] tmpStr;
mas01mc@324 434 initInputFile(prefixedString, false); // nommap, file pointer at correct position
mas01mc@324 435 size_t allocatedSize = 0;
mas01mc@324 436 read_data(infid, queryIndex, qp, &allocatedSize); // over-writes qp and allocatedSize
mas01mc@324 437 // Consistency check on allocated memory and query feature size
mas01mc@324 438 if(*nvp*sizeof(double)*dbH->dim != allocatedSize)
mas01mc@324 439 error("Query memory allocation failed consitency check","set_up_query_from_key");
mas01mc@324 440 // Allocated and calculate auxillary sequences: l2norm and power
mas01mc@324 441 init_track_aux_data(queryIndex, *qp, qnp, vqnp, qpp, vqpp);
mas01mc@324 442 }
mas01mc@324 443 else{ // Load from self-contained ADB database
mas01mc@324 444 // Read query feature vectors from database
mas01mc@324 445 *qp = NULL;
mas01mc@324 446 lseek(dbfid, dbH->dataOffset + trackOffsetTable[queryIndex] * sizeof(double), SEEK_SET);
mas01mc@324 447 size_t allocatedSize = 0;
mas01mc@324 448 read_data(dbfid, queryIndex, qp, &allocatedSize);
mas01mc@324 449 // Consistency check on allocated memory and query feature size
mas01mc@324 450 if(*nvp*sizeof(double)*dbH->dim != allocatedSize)
mas01mc@324 451 error("Query memory allocation failed consitency check","set_up_query_from_key");
mas01mc@324 452
mas01mc@324 453 Uns32T trackIndexOffset = trackOffsetTable[queryIndex]/dbH->dim; // Convert num data elements to num vectors
mas01mc@324 454 // Copy L2 norm partial-sum coefficients
mas01mc@324 455 assert(*qnp = new double[*nvp]);
mas01mc@324 456 memcpy(*qnp, l2normTable+trackIndexOffset, *nvp*sizeof(double));
mas01mc@324 457 sequence_sum(*qnp, *nvp, sequenceLength);
mas01mc@324 458 sequence_sqrt(*qnp, *nvp, sequenceLength);
mas01mc@324 459
mas01mc@324 460 if( usingPower ){
mas01mc@324 461 // Copy Power partial-sum coefficients
mas01mc@324 462 assert(*qpp = new double[*nvp]);
mas01mc@324 463 memcpy(*qpp, powerTable+trackIndexOffset, *nvp*sizeof(double));
mas01mc@324 464 sequence_sum(*qpp, *nvp, sequenceLength);
mas01mc@324 465 sequence_average(*qpp, *nvp, sequenceLength);
mas01mc@324 466 }
mas01mc@324 467
mas01mc@324 468 if (usingTimes) {
mas01mc@324 469 unsigned int k;
mas01mc@324 470 *mqdp = 0.0;
mas01mc@324 471 double *querydurs = new double[*nvp];
mas01mc@324 472 double *timesdata = new double[*nvp*2];
mas01mc@324 473 assert(querydurs && timesdata);
mas01mc@324 474 memcpy(timesdata, timesTable+trackIndexOffset, *nvp*sizeof(double));
mas01mc@324 475 for(k = 0; k < *nvp; k++) {
mas01mc@324 476 querydurs[k] = timesdata[2*k+1] - timesdata[2*k];
mas01mc@324 477 *mqdp += querydurs[k];
mas01mc@324 478 }
mas01mc@324 479 *mqdp /= k;
mas01mc@324 480
mas01mc@324 481 VERB_LOG(1, "mean query file duration: %f\n", *mqdp);
mas01mc@324 482
mas01mc@324 483 delete [] querydurs;
mas01mc@324 484 delete [] timesdata;
mas01mc@324 485 }
mas01mc@292 486 }
mas01mc@292 487
mas01mc@292 488 // Defaults, for exhaustive search (!usingQueryPoint)
mas01mc@292 489 *vqp = *qp;
mas01mc@292 490 *vqnp = *qnp;
mas01mc@292 491 *vqpp = *qpp;
mas01mc@292 492
mas01mc@292 493 if(usingQueryPoint) {
mas01mc@341 494 if( !(queryPoint < *nvp && queryPoint < *nvp - sequenceLength + 1) ) {
mas01mc@342 495 error("queryPoint >= numVectors-sequenceLength+1 in query");
mas01mc@292 496 } else {
mas01mc@292 497 VERB_LOG(1, "query point: %u\n", queryPoint);
mas01mc@292 498 *vqp = *qp + queryPoint * dbH->dim;
mas01mc@292 499 *vqnp = *qnp + queryPoint;
mas01mc@292 500 if (usingPower) {
mas01mc@292 501 *vqpp = *qpp + queryPoint;
mas01mc@292 502 }
mas01mc@292 503 *nvp = sequenceLength;
mas01mc@292 504 }
mas01mc@292 505 }
mas01mc@292 506 }
mas01mc@292 507
mas01mc@292 508
mas01cr@239 509 // FIXME: this is not the right name; we're not actually setting up
mas01cr@239 510 // the database, but copying various bits of it out of mmap()ed tables
mas01cr@239 511 // in order to reduce seeks.
mas01cr@239 512 void audioDB::set_up_db(double **snp, double **vsnp, double **spp, double **vspp, double **mddp, unsigned int *dvp) {
mas01cr@239 513 *dvp = dbH->length / (dbH->dim * sizeof(double));
mas01cr@239 514 *snp = new double[*dvp];
mas01cr@239 515
mas01cr@239 516 double *snpp = *snp, *sppp = 0;
mas01cr@239 517 memcpy(*snp, l2normTable, *dvp * sizeof(double));
mas01cr@239 518
mas01cr@239 519 if (usingPower) {
mas01cr@239 520 if (!(dbH->flags & O2_FLAG_POWER)) {
mas01cr@239 521 error("database not power-enabled", dbName);
mas01cr@239 522 }
mas01cr@239 523 *spp = new double[*dvp];
mas01cr@239 524 sppp = *spp;
mas01cr@239 525 memcpy(*spp, powerTable, *dvp * sizeof(double));
mas01cr@239 526 }
mas01cr@239 527
mas01cr@239 528 for(unsigned int i = 0; i < dbH->numFiles; i++){
mas01cr@239 529 if(trackTable[i] >= sequenceLength) {
mas01cr@239 530 sequence_sum(snpp, trackTable[i], sequenceLength);
mas01cr@239 531 sequence_sqrt(snpp, trackTable[i], sequenceLength);
mas01cr@239 532
mas01cr@239 533 if (usingPower) {
mas01cr@239 534 sequence_sum(sppp, trackTable[i], sequenceLength);
mas01cr@239 535 sequence_average(sppp, trackTable[i], sequenceLength);
mas01cr@239 536 }
mas01cr@239 537 }
mas01cr@239 538 snpp += trackTable[i];
mas01cr@239 539 if (usingPower) {
mas01cr@239 540 sppp += trackTable[i];
mas01cr@239 541 }
mas01cr@239 542 }
mas01cr@239 543
mas01cr@239 544 if (usingTimes) {
mas01cr@239 545 if(!(dbH->flags & O2_FLAG_TIMES)) {
mas01cr@239 546 error("query timestamps provided for non-timed database", dbName);
mas01cr@239 547 }
mas01cr@239 548
mas01cr@239 549 *mddp = new double[dbH->numFiles];
mas01cr@239 550
mas01cr@239 551 for(unsigned int k = 0; k < dbH->numFiles; k++) {
mas01cr@239 552 unsigned int j;
mas01cr@239 553 (*mddp)[k] = 0.0;
mas01cr@239 554 for(j = 0; j < trackTable[k]; j++) {
mas01cr@239 555 (*mddp)[k] += timesTable[2*j+1] - timesTable[2*j];
mas01cr@239 556 }
mas01cr@239 557 (*mddp)[k] /= j;
mas01cr@239 558 }
mas01cr@239 559 }
mas01cr@239 560
mas01cr@239 561 *vsnp = *snp;
mas01cr@239 562 *vspp = *spp;
mas01cr@239 563 }
mas01cr@239 564
mas01mc@292 565 // query_points()
mas01mc@292 566 //
mas01mc@292 567 // using PointPairs held in the exact_evaluation_queue compute squared distance for each PointPair
mas01mc@292 568 // and insert result into the current reporter.
mas01mc@292 569 //
mas01mc@292 570 // Preconditions:
mas01mc@292 571 // A query inFile has been opened with setup_query(...) and query pointers initialized
mas01mc@292 572 // The database contains some points
mas01mc@292 573 // An exact_evaluation_queue has been allocated and populated
mas01mc@292 574 // A reporter has been allocated
mas01mc@292 575 //
mas01mc@292 576 // Postconditions:
mas01mc@292 577 // reporter contains the points and distances that meet the reporter constraints
mas01mc@292 578
mas01cr@425 579 void audioDB::query_loop_points(double* query, double* qnPtr, double* qpPtr, double meanQdur, Uns32T numVectors, adb_query_refine_t *refine){
mas01mc@292 580 unsigned int dbVectors;
mas01mc@315 581 double *sNorm = 0, *snPtr, *sPower = 0, *spPtr = 0;
mas01mc@292 582 double *meanDBdur = 0;
mas01mc@292 583
mas01mc@292 584 // check pre-conditions
mas01mc@292 585 assert(exact_evaluation_queue&&reporter);
mas01mc@292 586 if(!exact_evaluation_queue->size()) // Exit if no points to evaluate
mas01mc@292 587 return;
mas01mc@292 588
mas01mc@292 589 // Compute database info
mas01mc@292 590 // FIXME: we more than likely don't need very much of the database
mas01mc@292 591 // so make a new method to build these values per-track or, even better, per-point
mas01mc@324 592 if( !( dbH->flags & O2_FLAG_LARGE_ADB) )
mas01mc@324 593 set_up_db(&sNorm, &snPtr, &sPower, &spPtr, &meanDBdur, &dbVectors);
mas01mc@292 594
mas01mc@292 595 VERB_LOG(1, "matching points...");
mas01mc@292 596
mas01mc@292 597 assert(pointNN>0 && pointNN<=O2_MAXNN);
mas01mc@292 598 assert(trackNN>0 && trackNN<=O2_MAXNN);
mas01mc@292 599
mas01mc@292 600 // We are guaranteed that the order of points is sorted by:
mas01mc@324 601 // trackID, spos, qpos
mas01mc@292 602 // so we can be relatively efficient in initialization of track data.
mas01mc@292 603 // Here we assume that points don't overlap, so we will use exhaustive dot
mas01mc@324 604 // product evaluation instead of memoization of partial sums which is used
mas01mc@324 605 // for exhaustive brute-force evaluation from smaller databases: e.g. query_loop()
mas01mc@292 606 double dist;
mas01mc@292 607 size_t data_buffer_size = 0;
mas01mc@292 608 double *data_buffer = 0;
mas01mc@324 609 Uns32T trackOffset = 0;
mas01mc@324 610 Uns32T trackIndexOffset = 0;
mas01mc@292 611 Uns32T currentTrack = 0x80000000; // Initialize with a value outside of track index range
mas01mc@292 612 Uns32T npairs = exact_evaluation_queue->size();
mas01mc@292 613 while(npairs--){
mas01mc@292 614 PointPair pp = exact_evaluation_queue->top();
mas01mc@324 615 // Large ADB track data must be loaded here for sPower
mas01mc@324 616 if(dbH->flags & O2_FLAG_LARGE_ADB){
mas01mc@324 617 trackOffset=0;
mas01mc@324 618 trackIndexOffset=0;
mas01mc@292 619 if(currentTrack!=pp.trackID){
mas01mc@324 620 char* prefixedString = new char[O2_MAXFILESTR];
mas01mc@324 621 char* tmpStr = prefixedString;
mas01mc@324 622 // On currentTrack change, allocate and load track data
mas01mc@292 623 currentTrack=pp.trackID;
mas01mc@324 624 SAFE_DELETE_ARRAY(sNorm);
mas01mc@324 625 SAFE_DELETE_ARRAY(sPower);
mas01mc@324 626 if(infid>0)
mas01mc@324 627 close(infid);
mas01mc@324 628 // Open and check dimensions of feature file
mas01mc@324 629 strncpy(prefixedString, featureFileNameTable+pp.trackID*O2_FILETABLE_ENTRY_SIZE, O2_MAXFILESTR);
mas01mc@324 630 prefix_name((char ** const) &prefixedString, adb_feature_root);
mas01mc@324 631 if (prefixedString!=tmpStr)
mas01mc@324 632 delete[] tmpStr;
mas01mc@324 633 initInputFile(prefixedString, false); // nommap, file pointer at correct position
mas01mc@324 634 // Load the feature vector data for current track into data_buffer
mas01mc@324 635 read_data(infid, pp.trackID, &data_buffer, &data_buffer_size);
mas01mc@324 636 // Load power and calculate power and l2norm sequence sums
mas01mc@324 637 init_track_aux_data(pp.trackID, data_buffer, &sNorm, &snPtr, &sPower, &spPtr);
mas01mc@292 638 }
mas01mc@324 639 }
mas01mc@324 640 else{
mas01mc@324 641 // These offsets are w.r.t. the entire database of feature vectors and auxillary variables
mas01mc@324 642 trackOffset=trackOffsetTable[pp.trackID]; // num data elements offset
mas01mc@324 643 trackIndexOffset=trackOffset/dbH->dim; // num vectors offset
mas01mc@324 644 }
mas01mc@324 645 Uns32T qPos = usingQueryPoint?0:pp.qpos;// index for query point
mas01mc@324 646 Uns32T sPos = trackIndexOffset+pp.spos; // index into l2norm table
mas01mc@324 647 // Test power thresholds before computing distance
mas01cr@425 648 if( ( !usingPower || audiodb_powers_acceptable(refine, qpPtr[qPos], sPower[sPos])) &&
mas01mc@324 649 ( qPos<numVectors-sequenceLength+1 && pp.spos<trackTable[pp.trackID]-sequenceLength+1 ) ){
mas01mc@324 650 // Non-large ADB track data is loaded inside power test for efficiency
mas01mc@324 651 if( !(dbH->flags & O2_FLAG_LARGE_ADB) && (currentTrack!=pp.trackID) ){
mas01mc@324 652 // On currentTrack change, allocate and load track data
mas01mc@324 653 currentTrack=pp.trackID;
mas01mc@324 654 lseek(dbfid, dbH->dataOffset + trackOffset * sizeof(double), SEEK_SET);
mas01mc@324 655 read_data(dbfid, currentTrack, &data_buffer, &data_buffer_size);
mas01mc@324 656 }
mas01mc@324 657 // Compute distance
mas01cr@425 658 dist = audiodb_dot_product(query+qPos*dbH->dim, data_buffer+pp.spos*dbH->dim, dbH->dim*sequenceLength);
mas01mc@324 659 double qn = qnPtr[qPos];
mas01mc@324 660 double sn = sNorm[sPos];
mas01mc@292 661 if(normalizedDistance)
mas01mc@324 662 dist = 2 - (2/(qn*sn))*dist;
mas01mc@292 663 else
mas01mc@292 664 if(no_unit_norming)
mas01mc@324 665 dist = qn*qn + sn*sn - 2*dist;
mas01mc@292 666 // else
mas01mc@292 667 // dist = dist;
mas01cr@424 668 if((!radius) || dist <= (O2_LSH_EXACT_MULT*radius+O2_DISTANCE_TOLERANCE)) {
mas01cr@424 669 adb_result_t r;
mas01cr@424 670 r.key = fileTable + pp.trackID * O2_FILETABLE_ENTRY_SIZE;
mas01cr@424 671 r.dist = dist;
mas01cr@424 672 r.qpos = pp.qpos;
mas01cr@424 673 r.ipos = pp.spos;
mas01cr@424 674 accumulator->add_point(&r);
mas01cr@424 675 }
mas01mc@292 676 }
mas01mc@292 677 exact_evaluation_queue->pop();
mas01mc@292 678 }
mas01mc@315 679 // Cleanup
mas01mc@324 680 SAFE_DELETE_ARRAY(sNorm);
mas01mc@324 681 SAFE_DELETE_ARRAY(sPower);
mas01mc@324 682 SAFE_DELETE_ARRAY(meanDBdur);
mas01mc@292 683 }
mas01mc@292 684
mas01cr@425 685 void audioDB::query_loop(adb_query_refine_t *refine, Uns32T queryIndex) {
mas01cr@239 686
mas01cr@239 687 unsigned int numVectors;
mas01cr@239 688 double *query, *query_data;
mas01cr@239 689 double *qNorm, *qnPtr, *qPower = 0, *qpPtr = 0;
mas01cr@239 690 double meanQdur;
mas01cr@239 691
mas01mc@324 692 if( dbH->flags & O2_FLAG_LARGE_ADB )
mas01mc@324 693 error("error: LARGE_ADB requires indexed query");
mas01mc@324 694
mas01mc@292 695 if(query_from_key)
mas01mc@292 696 set_up_query_from_key(&query_data, &query, &qNorm, &qnPtr, &qPower, &qpPtr, &meanQdur, &numVectors, queryIndex);
mas01mc@292 697 else
mas01mc@292 698 set_up_query(&query_data, &query, &qNorm, &qnPtr, &qPower, &qpPtr, &meanQdur, &numVectors);
mas01cr@239 699
mas01cr@239 700 unsigned int dbVectors;
mas01cr@239 701 double *sNorm, *snPtr, *sPower = 0, *spPtr = 0;
mas01cr@239 702 double *meanDBdur = 0;
mas01cr@239 703
mas01cr@239 704 set_up_db(&sNorm, &snPtr, &sPower, &spPtr, &meanDBdur, &dbVectors);
mas01cr@239 705
mas01cr@239 706 VERB_LOG(1, "matching tracks...");
mas01cr@239 707
mas01cr@239 708 assert(pointNN>0 && pointNN<=O2_MAXNN);
mas01cr@239 709 assert(trackNN>0 && trackNN<=O2_MAXNN);
mas01cr@239 710
mas01cr@239 711 unsigned j,k,track,trackOffset=0, HOP_SIZE=sequenceHop, wL=sequenceLength;
mas01cr@239 712 double **D = 0; // Differences query and target
mas01cr@239 713 double **DD = 0; // Matched filter distance
mas01cr@239 714
mas01mc@292 715 D = new double*[numVectors]; // pre-allocate
mas01cr@239 716 DD = new double*[numVectors];
mas01cr@239 717
mas01cr@239 718 gettimeofday(&tv1, NULL);
mas01cr@239 719 unsigned processedTracks = 0;
mas01cr@239 720 off_t trackIndexOffset;
mas01cr@239 721 char nextKey[MAXSTR];
mas01cr@239 722
mas01cr@239 723 // Track loop
mas01cr@239 724 size_t data_buffer_size = 0;
mas01cr@239 725 double *data_buffer = 0;
mas01cr@239 726 lseek(dbfid, dbH->dataOffset, SEEK_SET);
mas01cr@239 727
mas01cr@239 728 for(processedTracks=0, track=0 ; processedTracks < dbH->numFiles ; track++, processedTracks++) {
mas01cr@239 729
mas01cr@239 730 trackOffset = trackOffsetTable[track]; // numDoubles offset
mas01cr@239 731
mas01cr@239 732 // get trackID from file if using a control file
mas01cr@239 733 if(trackFile) {
mas01cr@239 734 trackFile->getline(nextKey,MAXSTR);
mas01cr@239 735 if(!trackFile->eof()) {
mas01cr@239 736 track = getKeyPos(nextKey);
mas01cr@239 737 trackOffset = trackOffsetTable[track];
mas01cr@239 738 lseek(dbfid, dbH->dataOffset + trackOffset * sizeof(double), SEEK_SET);
mas01cr@239 739 } else {
mas01cr@239 740 break;
mas01cr@239 741 }
mas01cr@239 742 }
mas01cr@239 743
mas01mc@292 744 // skip identity on query_from_key
mas01mc@292 745 if( query_from_key && (track == queryIndex) ) {
mas01mc@292 746 if(queryIndex!=dbH->numFiles-1){
mas01mc@292 747 track++;
mas01mc@292 748 trackOffset = trackOffsetTable[track];
mas01mc@292 749 lseek(dbfid, dbH->dataOffset + trackOffset * sizeof(double), SEEK_SET);
mas01mc@292 750 }
mas01mc@292 751 else{
mas01mc@292 752 break;
mas01mc@292 753 }
mas01mc@292 754 }
mas01mc@292 755
mas01cr@239 756 trackIndexOffset=trackOffset/dbH->dim; // numVectors offset
mas01cr@239 757
mas01mc@324 758 read_data(dbfid, track, &data_buffer, &data_buffer_size);
mas01cr@239 759 if(sequenceLength <= trackTable[track]) { // test for short sequences
mas01cr@239 760
mas01cr@239 761 VERB_LOG(7,"%u.%jd.%u | ", track, (intmax_t) trackIndexOffset, trackTable[track]);
mas01cr@239 762
mas01cr@239 763 initialize_arrays(track, numVectors, query, data_buffer, D, DD);
mas01cr@239 764
mas01cr@425 765 if(refine->flags & ADB_REFINE_DURATION_RATIO) {
mas01cr@239 766 VERB_LOG(3,"meanQdur=%f meanDBdur=%f\n", meanQdur, meanDBdur[track]);
mas01cr@239 767 }
mas01cr@239 768
mas01cr@425 769 if((!(refine->flags & ADB_REFINE_DURATION_RATIO)) || fabs(meanDBdur[track]-meanQdur) < meanQdur*refine->duration_ratio) {
mas01cr@425 770 if(refine->flags & ADB_REFINE_DURATION_RATIO) {
mas01cr@239 771 VERB_LOG(3,"within duration tolerance.\n");
mas01cr@239 772 }
mas01cr@239 773
mas01cr@239 774 // Search for minimum distance by shingles (concatenated vectors)
mas01cr@239 775 for(j = 0; j <= numVectors - wL; j += HOP_SIZE) {
mas01cr@239 776 for(k = 0; k <= trackTable[track] - wL; k += HOP_SIZE) {
mas01cr@239 777 double thisDist;
mas01mc@292 778 if(normalizedDistance)
mas01cr@239 779 thisDist = 2-(2/(qnPtr[j]*sNorm[trackIndexOffset+k]))*DD[j][k];
mas01mc@292 780 else
mas01mc@292 781 if(no_unit_norming)
mas01mc@292 782 thisDist = qnPtr[j]*qnPtr[j]+sNorm[trackIndexOffset+k]*sNorm[trackIndexOffset+k] - 2*DD[j][k];
mas01mc@292 783 else
mas01mc@292 784 thisDist = DD[j][k];
mas01mc@292 785
mas01cr@239 786 // Power test
mas01cr@425 787 if ((!usingPower) || audiodb_powers_acceptable(refine, qpPtr[j], sPower[trackIndexOffset + k])) {
mas01cr@239 788 // radius test
mas01cr@425 789 if((!(refine->flags & ADB_REFINE_RADIUS)) ||
mas01cr@425 790 thisDist <= (refine->radius+O2_DISTANCE_TOLERANCE)) {
mas01cr@423 791 adb_result_t r;
mas01cr@423 792 r.key = fileTable + track * O2_FILETABLE_ENTRY_SIZE;
mas01cr@423 793 r.dist = thisDist;
mas01cr@423 794 r.qpos = usingQueryPoint ? queryPoint : j;
mas01cr@423 795 r.ipos = k;
mas01cr@423 796 accumulator->add_point(&r);
mas01cr@239 797 }
mas01cr@239 798 }
mas01cr@239 799 }
mas01cr@239 800 }
mas01cr@239 801 } // Duration match
mas01cr@239 802 delete_arrays(track, numVectors, D, DD);
mas01cr@239 803 }
mas01cr@239 804 }
mas01cr@239 805
mas01cr@239 806 free(data_buffer);
mas01cr@239 807
mas01cr@239 808 gettimeofday(&tv2,NULL);
mas01cr@239 809 VERB_LOG(1,"elapsed time: %ld msec\n",
mas01cr@239 810 (tv2.tv_sec*1000 + tv2.tv_usec/1000) -
mas01cr@239 811 (tv1.tv_sec*1000 + tv1.tv_usec/1000))
mas01cr@239 812
mas01cr@239 813 // Clean up
mas01cr@239 814 if(query_data)
mas01cr@239 815 delete[] query_data;
mas01cr@239 816 if(qNorm)
mas01cr@239 817 delete[] qNorm;
mas01cr@239 818 if(sNorm)
mas01cr@239 819 delete[] sNorm;
mas01cr@239 820 if(qPower)
mas01cr@239 821 delete[] qPower;
mas01cr@239 822 if(sPower)
mas01cr@239 823 delete[] sPower;
mas01cr@239 824 if(D)
mas01cr@239 825 delete[] D;
mas01cr@239 826 if(DD)
mas01cr@239 827 delete[] DD;
mas01cr@239 828 if(meanDBdur)
mas01cr@239 829 delete[] meanDBdur;
mas01cr@239 830 }
mas01cr@239 831
mas01cr@239 832 // Unit norm block of features
mas01cr@239 833 void audioDB::unitNorm(double* X, unsigned dim, unsigned n, double* qNorm){
mas01cr@239 834 unsigned d;
mas01cr@239 835 double L2, *p;
mas01cr@239 836
mas01cr@239 837 VERB_LOG(2, "norming %u vectors...", n);
mas01cr@239 838 while(n--) {
mas01cr@239 839 p = X;
mas01cr@239 840 L2 = 0.0;
mas01cr@239 841 d = dim;
mas01cr@239 842 while(d--) {
mas01cr@239 843 L2 += *p * *p;
mas01cr@239 844 p++;
mas01cr@239 845 }
mas01cr@239 846 if(qNorm) {
mas01cr@239 847 *qNorm++=L2;
mas01cr@239 848 }
mas01cr@239 849 X += dim;
mas01cr@239 850 }
mas01cr@239 851 VERB_LOG(2, "done.\n");
mas01cr@239 852 }