annotate src/Matcher.cpp @ 220:edd9c1c769a0

Fix crash in looking up expand direction, when the entire reference audio has been fed before any performance has (a pathological case)
author Chris Cannam
date Thu, 11 Jun 2015 12:30:51 +0100
parents aa795f660b2b
children 175c8f044e7c
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 Vamp feature extraction plugin using the MATCH audio alignment
cannam@0 5 algorithm.
cannam@0 6
cannam@0 7 Centre for Digital Music, Queen Mary, University of London.
cannam@0 8 This file copyright 2007 Simon Dixon, Chris Cannam and QMUL.
cannam@0 9
cannam@0 10 This program is free software; you can redistribute it and/or
cannam@0 11 modify it under the terms of the GNU General Public License as
cannam@0 12 published by the Free Software Foundation; either version 2 of the
cannam@0 13 License, or (at your option) any later version. See the file
cannam@0 14 COPYING included with this distribution for more information.
cannam@0 15 */
cannam@0 16
cannam@0 17 #include "Matcher.h"
cannam@0 18
cannam@0 19 #include <iostream>
cannam@0 20
cannam@4 21 #include <cstdlib>
Chris@16 22 #include <cassert>
cannam@4 23
Chris@72 24 using namespace std;
Chris@72 25
Chris@10 26 //#define DEBUG_MATCHER 1
Chris@220 27 //#define PERFORM_ERROR_CHECKS 1
Chris@10 28
Chris@143 29 Matcher::Matcher(Parameters parameters, DistanceMetric::Parameters dparams,
Chris@143 30 Matcher *p) :
Chris@43 31 m_params(parameters),
Chris@143 32 m_metric(dparams)
Chris@23 33 {
Chris@23 34 #ifdef DEBUG_MATCHER
Chris@143 35 cerr << "*** Matcher: hopTime = " << parameters.hopTime
Chris@140 36 << ", blockTime = " << parameters.blockTime
Chris@140 37 << ", maxRunCount = " << parameters.maxRunCount
Chris@140 38 << ", diagonalWeight = " << parameters.diagonalWeight << endl;
Chris@23 39 #endif
Chris@140 40
Chris@43 41 m_otherMatcher = p; // the first matcher will need this to be set later
Chris@43 42 m_firstPM = (!p);
Chris@43 43 m_frameCount = 0;
Chris@43 44 m_runCount = 0;
Chris@43 45 m_blockSize = 0;
Chris@202 46 m_distXSize = 0;
cannam@0 47
Chris@180 48 m_blockSize = int(m_params.blockTime / m_params.hopTime + 0.5);
Chris@15 49 #ifdef DEBUG_MATCHER
Chris@43 50 cerr << "Matcher: m_blockSize = " << m_blockSize << endl;
Chris@15 51 #endif
cannam@0 52
Chris@43 53 m_initialised = false;
Chris@23 54 }
cannam@0 55
cannam@0 56 Matcher::~Matcher()
cannam@0 57 {
Chris@10 58 #ifdef DEBUG_MATCHER
Chris@15 59 cerr << "Matcher(" << this << ")::~Matcher()" << endl;
Chris@10 60 #endif
cannam@0 61 }
cannam@0 62
cannam@0 63 void
cannam@0 64 Matcher::init()
cannam@0 65 {
Chris@43 66 if (m_initialised) return;
cannam@0 67
Chris@182 68 m_features = featureseq_t(m_blockSize);
cannam@0 69
Chris@43 70 m_distXSize = m_blockSize * 2;
Chris@45 71
Chris@41 72 size();
cannam@0 73
Chris@43 74 m_frameCount = 0;
Chris@43 75 m_runCount = 0;
Chris@38 76
Chris@43 77 m_initialised = true;
Chris@16 78 }
Chris@16 79
Chris@87 80 bool
Chris@203 81 Matcher::isAvailable(int i, int j)
Chris@154 82 {
Chris@203 83 if (m_firstPM) {
Chris@203 84 if (isInRange(i, j)) {
Chris@214 85 return (m_distance[i][j - m_first[i]] != INVALID_DISTANCE);
Chris@203 86 } else {
Chris@203 87 return false;
Chris@154 88 }
Chris@203 89 } else {
Chris@203 90 return m_otherMatcher->isAvailable(j, i);
Chris@154 91 }
Chris@154 92 }
Chris@154 93
Chris@154 94 bool
Chris@203 95 Matcher::isRowAvailable(int i)
Chris@154 96 {
Chris@203 97 if (m_firstPM) {
Chris@203 98
Chris@203 99 if (i < 0 || i >= int(m_first.size())) return false;
Chris@214 100 for (auto c: m_distance[i]) {
Chris@214 101 if (c != INVALID_DISTANCE) return true;
Chris@203 102 }
Chris@203 103 return false;
Chris@203 104
Chris@203 105 } else {
Chris@203 106 return m_otherMatcher->isColAvailable(i);
Chris@203 107 }
Chris@203 108 }
Chris@203 109
Chris@203 110 bool
Chris@203 111 Matcher::isColAvailable(int j)
Chris@203 112 {
Chris@203 113 if (m_firstPM) {
Chris@203 114 for (int i = 0; i < int(m_first.size()); ++i) {
Chris@208 115 if (j >= m_first[i] && j < m_last[i]) {
Chris@214 116 if (m_distance[i][j - m_first[i]] != INVALID_DISTANCE) {
Chris@203 117 return true;
Chris@203 118 }
Chris@203 119 }
Chris@203 120 }
Chris@203 121 return false;
Chris@203 122 } else {
Chris@203 123 return m_otherMatcher->isRowAvailable(j);
Chris@203 124 }
Chris@154 125 }
Chris@154 126
Chris@154 127 bool
Chris@87 128 Matcher::isInRange(int i, int j)
Chris@87 129 {
Chris@87 130 if (m_firstPM) {
Chris@87 131 return ((i >= 0) &&
Chris@87 132 (i < int(m_first.size())) &&
Chris@87 133 (j >= m_first[i]) &&
Chris@214 134 (j < int(m_first[i] + m_distance[i].size())));
Chris@87 135 } else {
Chris@87 136 return m_otherMatcher->isInRange(j, i);
Chris@87 137 }
Chris@87 138 }
Chris@87 139
Chris@87 140 pair<int, int>
Chris@205 141 Matcher::getColRangeForRow(int i)
Chris@87 142 {
Chris@204 143 if (m_firstPM) {
Chris@208 144 #ifdef PERFORM_ERROR_CHECKS
Chris@204 145 if (i < 0 || i >= int(m_first.size())) {
Chris@206 146 cerr << "ERROR: Matcher::getColRangeForRow(" << i << "): Index out of range"
Chris@204 147 << endl;
Chris@204 148 throw "Index out of range";
Chris@204 149 }
Chris@208 150 #endif
Chris@208 151 return pair<int, int>(m_first[i], m_last[i]);
Chris@87 152 } else {
Chris@205 153 return m_otherMatcher->getRowRangeForCol(i);
Chris@87 154 }
Chris@87 155 }
Chris@87 156
Chris@87 157 pair<int, int>
Chris@206 158 Matcher::getRowRangeForCol(int i)
Chris@87 159 {
Chris@204 160 if (m_firstPM) {
Chris@208 161 #ifdef PERFORM_ERROR_CHECKS
Chris@206 162 if (i < 0 || i >= int(m_otherMatcher->m_first.size())) {
Chris@206 163 cerr << "ERROR: Matcher::getRowRangeForCol(" << i << "): Index out of range"
Chris@204 164 << endl;
Chris@204 165 throw "Index out of range";
Chris@204 166 }
Chris@208 167 #endif
Chris@208 168 return pair<int, int>(m_otherMatcher->m_first[i],
Chris@208 169 m_otherMatcher->m_last[i]);
Chris@204 170 } else {
Chris@206 171 return m_otherMatcher->getColRangeForRow(i);
Chris@204 172 }
Chris@87 173 }
Chris@87 174
Chris@182 175 distance_t
Chris@87 176 Matcher::getDistance(int i, int j)
Chris@87 177 {
Chris@87 178 if (m_firstPM) {
Chris@208 179 #ifdef PERFORM_ERROR_CHECKS
Chris@87 180 if (!isInRange(i, j)) {
Chris@87 181 cerr << "ERROR: Matcher::getDistance(" << i << ", " << j << "): "
Chris@87 182 << "Location is not in range" << endl;
Chris@87 183 throw "Distance not available";
Chris@87 184 }
Chris@208 185 #endif
Chris@182 186 distance_t dist = m_distance[i][j - m_first[i]];
Chris@208 187 #ifdef PERFORM_ERROR_CHECKS
Chris@212 188 if (dist == INVALID_DISTANCE) {
Chris@87 189 cerr << "ERROR: Matcher::getDistance(" << i << ", " << j << "): "
Chris@87 190 << "Location is in range, but distance ("
Chris@191 191 << distance_print_t(dist)
Chris@191 192 << ") is invalid or has not been set" << endl;
Chris@87 193 throw "Distance not available";
Chris@87 194 }
Chris@208 195 #endif
Chris@87 196 return dist;
Chris@87 197 } else {
Chris@87 198 return m_otherMatcher->getDistance(j, i);
Chris@87 199 }
Chris@87 200 }
Chris@87 201
Chris@87 202 void
Chris@182 203 Matcher::setDistance(int i, int j, distance_t distance)
Chris@87 204 {
Chris@87 205 if (m_firstPM) {
Chris@208 206 #ifdef PERFORM_ERROR_CHECKS
Chris@87 207 if (!isInRange(i, j)) {
Chris@87 208 cerr << "ERROR: Matcher::setDistance(" << i << ", " << j << ", "
Chris@191 209 << distance_print_t(distance)
Chris@191 210 << "): Location is out of range" << endl;
Chris@87 211 throw "Indices out of range";
Chris@87 212 }
Chris@208 213 #endif
Chris@87 214 m_distance[i][j - m_first[i]] = distance;
Chris@87 215 } else {
Chris@87 216 m_otherMatcher->setDistance(j, i, distance);
Chris@87 217 }
Chris@87 218 }
Chris@87 219
Chris@191 220 normpathcost_t
Chris@135 221 Matcher::getNormalisedPathCost(int i, int j)
Chris@135 222 {
Chris@135 223 // normalised for path length. 1+ prevents division by zero here
Chris@191 224 return normpathcost_t(getPathCost(i, j)) / normpathcost_t(1 + i + j);
Chris@135 225 }
Chris@135 226
Chris@182 227 pathcost_t
Chris@87 228 Matcher::getPathCost(int i, int j)
Chris@87 229 {
Chris@87 230 if (m_firstPM) {
Chris@203 231 #ifdef PERFORM_ERROR_CHECKS
Chris@87 232 if (!isAvailable(i, j)) {
Chris@87 233 if (!isInRange(i, j)) {
Chris@87 234 cerr << "ERROR: Matcher::getPathCost(" << i << ", " << j << "): "
Chris@87 235 << "Location is not in range" << endl;
Chris@87 236 } else {
Chris@87 237 cerr << "ERROR: Matcher::getPathCost(" << i << ", " << j << "): "
Chris@87 238 << "Location is in range, but pathCost ("
Chris@87 239 << m_bestPathCost[i][j - m_first[i]]
Chris@87 240 << ") is invalid or has not been set" << endl;
Chris@87 241 }
Chris@87 242 throw "Path cost not available";
Chris@87 243 }
Chris@203 244 #endif
Chris@87 245 return m_bestPathCost[i][j - m_first[i]];
Chris@87 246 } else {
Chris@87 247 return m_otherMatcher->getPathCost(j, i);
Chris@87 248 }
Chris@87 249 }
Chris@87 250
Chris@87 251 void
Chris@182 252 Matcher::setPathCost(int i, int j, advance_t dir, pathcost_t pathCost)
Chris@87 253 {
Chris@87 254 if (m_firstPM) {
Chris@208 255 #ifdef PERFORM_ERROR_CHECKS
Chris@87 256 if (!isInRange(i, j)) {
Chris@87 257 cerr << "ERROR: Matcher::setPathCost(" << i << ", " << j << ", "
Chris@87 258 << dir << ", " << pathCost
Chris@87 259 << "): Location is out of range" << endl;
Chris@87 260 throw "Indices out of range";
Chris@87 261 }
Chris@208 262 #endif
Chris@87 263 m_advance[i][j - m_first[i]] = dir;
Chris@87 264 m_bestPathCost[i][j - m_first[i]] = pathCost;
Chris@87 265 } else {
Chris@87 266 if (dir == AdvanceThis) {
Chris@87 267 dir = AdvanceOther;
Chris@87 268 } else if (dir == AdvanceOther) {
Chris@87 269 dir = AdvanceThis;
Chris@87 270 }
Chris@87 271 m_otherMatcher->setPathCost(j, i, dir, pathCost);
Chris@87 272 }
Chris@87 273 }
Chris@87 274
cannam@0 275 void
Chris@41 276 Matcher::size()
cannam@0 277 {
Chris@43 278 m_first.resize(m_distXSize, 0);
Chris@43 279 m_last.resize(m_distXSize, 0);
Chris@206 280
Chris@206 281 if (m_firstPM) {
Chris@206 282 int distSize = (m_params.maxRunCount + 1) * m_blockSize;
Chris@212 283 m_bestPathCost.resize(m_distXSize, pathcostvec_t(distSize, INVALID_PATHCOST));
Chris@212 284 m_distance.resize(m_distXSize, distancevec_t(distSize, INVALID_DISTANCE));
Chris@206 285 m_advance.resize(m_distXSize, advancevec_t(distSize, AdvanceNone));
Chris@206 286 }
Chris@38 287 }
cannam@0 288
Chris@23 289 void
Chris@182 290 Matcher::consumeFeatureVector(const feature_t &feature)
Chris@23 291 {
Chris@43 292 if (!m_initialised) init();
Chris@43 293 int frameIndex = m_frameCount % m_blockSize;
Chris@182 294 m_features[frameIndex] = feature;
Chris@23 295 calcAdvance();
Chris@21 296 }
Chris@21 297
Chris@211 298 pathcost_t
Chris@211 299 Matcher::addToCost(pathcost_t cost, pathcost_t increment)
Chris@211 300 {
Chris@212 301 if (PATHCOST_MAX - increment < cost) {
Chris@212 302 return PATHCOST_MAX;
Chris@211 303 } else {
Chris@211 304 return cost + pathcost_t(increment);
Chris@211 305 }
Chris@211 306 }
Chris@211 307
Chris@21 308 void
Chris@21 309 Matcher::calcAdvance()
Chris@21 310 {
Chris@43 311 int frameIndex = m_frameCount % m_blockSize;
Chris@21 312
Chris@43 313 if (m_frameCount >= m_distXSize) {
Chris@211 314 m_distXSize = int(m_distXSize * 1.2);
Chris@41 315 size();
cannam@0 316 }
Chris@207 317
Chris@43 318 if (m_firstPM && (m_frameCount >= m_blockSize)) {
Chris@207 319 // Memory reduction for old rows
Chris@207 320 int oldidx = m_frameCount - m_blockSize;
Chris@207 321 int len = m_last[oldidx] - m_first[oldidx];
Chris@207 322 m_distance[oldidx].resize(len);
Chris@209 323 m_distance[oldidx].shrink_to_fit();
Chris@207 324 m_bestPathCost[oldidx].resize(len);
Chris@209 325 m_bestPathCost[oldidx].shrink_to_fit();
Chris@207 326 m_advance[oldidx].resize(len);
Chris@209 327 m_advance[oldidx].shrink_to_fit();
cannam@0 328 }
cannam@0 329
Chris@43 330 int stop = m_otherMatcher->m_frameCount;
Chris@43 331 int index = stop - m_blockSize;
Chris@86 332 if (index < 0) index = 0;
Chris@86 333
Chris@43 334 m_first[m_frameCount] = index;
Chris@43 335 m_last[m_frameCount] = stop;
cannam@0 336
cannam@0 337 for ( ; index < stop; index++) {
Chris@26 338
Chris@188 339 distance_t distance = m_metric.calcDistance
Chris@182 340 (m_features[frameIndex],
Chris@182 341 m_otherMatcher->m_features[index % m_blockSize]);
Chris@26 342
Chris@188 343 pathcost_t straightIncrement(distance);
Chris@188 344 pathcost_t diagIncrement = pathcost_t(distance * m_params.diagonalWeight);
Chris@89 345
Chris@86 346 if ((m_frameCount == 0) && (index == 0)) { // first element
Chris@86 347
Chris@86 348 updateValue(0, 0, AdvanceNone,
Chris@86 349 0,
Chris@86 350 distance);
Chris@86 351
Chris@86 352 } else if (m_frameCount == 0) { // first row
Chris@86 353
Chris@220 354 pathcost_t cost {};
Chris@220 355
Chris@220 356 if (isInRange(0, index - 1)) {
Chris@220 357 cost = getPathCost(0, index - 1);
Chris@220 358 }
Chris@220 359
Chris@220 360 updateValue(0, index, AdvanceOther, cost, distance);
Chris@86 361
Chris@86 362 } else if (index == 0) { // first column
Chris@86 363
Chris@220 364 pathcost_t cost {};
Chris@220 365
Chris@220 366 if (isInRange(m_frameCount - 1, 0)) {
Chris@220 367 cost = getPathCost(m_frameCount - 1, 0);
Chris@220 368 }
Chris@220 369
Chris@220 370 updateValue(m_frameCount, index, AdvanceThis, cost, distance);
Chris@86 371
Chris@86 372 } else if (index == m_otherMatcher->m_frameCount - m_blockSize) {
Chris@86 373
cannam@0 374 // missing value(s) due to cutoff
cannam@0 375 // - no previous value in current row (resp. column)
cannam@0 376 // - no diagonal value if prev. dir. == curr. dirn
Chris@86 377
Chris@182 378 pathcost_t min2 = getPathCost(m_frameCount - 1, index);
Chris@86 379
Chris@91 380 // cerr << "NOTE: missing value at i = " << m_frameCount << ", j = "
Chris@91 381 // << index << " (first = " << m_firstPM << ")" << endl;
Chris@86 382
Chris@43 383 // if ((m_firstPM && (first[m_frameCount - 1] == index)) ||
Chris@43 384 // (!m_firstPM && (m_last[index-1] < m_frameCount)))
Chris@86 385 if (m_first[m_frameCount - 1] == index) {
Chris@86 386
Chris@86 387 updateValue(m_frameCount, index, AdvanceThis,
Chris@86 388 min2, distance);
Chris@86 389
Chris@86 390 } else {
Chris@86 391
Chris@182 392 pathcost_t min1 = getPathCost(m_frameCount - 1, index - 1);
Chris@211 393 if (addToCost(min1, diagIncrement) <=
Chris@211 394 addToCost(min2, straightIncrement)) {
Chris@86 395 updateValue(m_frameCount, index, AdvanceBoth,
Chris@86 396 min1, distance);
Chris@86 397 } else {
Chris@86 398 updateValue(m_frameCount, index, AdvanceThis,
Chris@86 399 min2, distance);
Chris@86 400 }
cannam@0 401 }
Chris@86 402
cannam@0 403 } else {
Chris@86 404
Chris@182 405 pathcost_t min1 = getPathCost(m_frameCount, index - 1);
Chris@182 406 pathcost_t min2 = getPathCost(m_frameCount - 1, index);
Chris@182 407 pathcost_t min3 = getPathCost(m_frameCount - 1, index - 1);
Chris@87 408
Chris@211 409 pathcost_t cost1 = addToCost(min1, straightIncrement);
Chris@211 410 pathcost_t cost2 = addToCost(min2, straightIncrement);
Chris@211 411 pathcost_t cost3 = addToCost(min3, diagIncrement);
Chris@93 412
Chris@93 413 // Choosing is easy if there is a strict cheapest of the
Chris@93 414 // three. If two or more share the lowest cost, we choose
Chris@93 415 // in order of preference: cost3 (AdvanceBoth), cost2
Chris@94 416 // (AdvanceThis), cost1 (AdvanceOther) if we are the first
Chris@94 417 // matcher; and cost3 (AdvanceBoth), cost1 (AdvanceOther),
Chris@94 418 // cost2 (AdvanceThis) if we are the second matcher. That
Chris@94 419 // is, we always prioritise the diagonal followed by the
Chris@94 420 // first matcher.
Chris@94 421
Chris@94 422 if (( m_firstPM && (cost1 < cost2)) ||
Chris@94 423 (!m_firstPM && (cost1 <= cost2))) {
Chris@89 424 if (cost3 <= cost1) {
Chris@86 425 updateValue(m_frameCount, index, AdvanceBoth,
Chris@86 426 min3, distance);
Chris@86 427 } else {
Chris@86 428 updateValue(m_frameCount, index, AdvanceOther,
Chris@86 429 min1, distance);
Chris@86 430 }
cannam@0 431 } else {
Chris@89 432 if (cost3 <= cost2) {
Chris@86 433 updateValue(m_frameCount, index, AdvanceBoth,
Chris@86 434 min3, distance);
Chris@86 435 } else {
Chris@86 436 updateValue(m_frameCount, index, AdvanceThis,
Chris@86 437 min2, distance);
Chris@86 438 }
cannam@0 439 }
cannam@0 440 }
Chris@86 441
Chris@43 442 m_otherMatcher->m_last[index]++;
cannam@0 443 } // loop for row (resp. column)
cannam@0 444
Chris@43 445 m_frameCount++;
Chris@43 446 m_runCount++;
cannam@0 447
Chris@43 448 m_otherMatcher->m_runCount = 0;
Chris@21 449 }
cannam@0 450
cannam@0 451 void
Chris@182 452 Matcher::updateValue(int i, int j, advance_t dir, pathcost_t value, distance_t distance)
cannam@0 453 {
Chris@188 454 pathcost_t increment = distance;
Chris@83 455 if (dir == AdvanceBoth) {
Chris@188 456 increment = pathcost_t(increment * m_params.diagonalWeight);
Chris@188 457 }
Chris@188 458
Chris@211 459 pathcost_t newValue = addToCost(value, increment);
Chris@212 460 if (newValue == PATHCOST_MAX) {
Chris@188 461 cerr << "ERROR: Path cost overflow at i=" << i << ", j=" << j << ": "
Chris@212 462 << value << " + " << increment << " >= " << PATHCOST_MAX << endl;
Chris@212 463 newValue = PATHCOST_MAX;
Chris@83 464 }
Chris@83 465
Chris@43 466 if (m_firstPM) {
Chris@45 467
Chris@96 468 setDistance(i, j, distance);
Chris@188 469 setPathCost(i, j, dir, newValue);
Chris@45 470
cannam@0 471 } else {
Chris@45 472
Chris@86 473 if (dir == AdvanceThis) dir = AdvanceOther;
Chris@86 474 else if (dir == AdvanceOther) dir = AdvanceThis;
Chris@84 475
Chris@43 476 int idx = i - m_otherMatcher->m_first[j];
Chris@45 477
Chris@188 478 if (idx < 0 || size_t(idx) == m_otherMatcher->m_distance[j].size()) {
cannam@0 479 // This should never happen, but if we allow arbitrary
cannam@0 480 // pauses in either direction, and arbitrary lengths at
cannam@0 481 // end, it is better than a segmentation fault.
Chris@217 482 // cerr << "Emergency resize: " << idx << " -> " << idx * 2 << endl;
Chris@212 483 m_otherMatcher->m_bestPathCost[j].resize(idx * 2, INVALID_PATHCOST);
Chris@212 484 m_otherMatcher->m_distance[j].resize(idx * 2, INVALID_DISTANCE);
Chris@46 485 m_otherMatcher->m_advance[j].resize(idx * 2, AdvanceNone);
cannam@0 486 }
Chris@45 487
Chris@96 488 m_otherMatcher->setDistance(j, i, distance);
Chris@188 489 m_otherMatcher->setPathCost(j, i, dir, newValue);
cannam@0 490 }
Chris@71 491 }
cannam@0 492
Chris@181 493 advance_t
Chris@72 494 Matcher::getAdvance(int i, int j)
Chris@72 495 {
Chris@72 496 if (m_firstPM) {
Chris@208 497 #ifdef PERFORM_ERROR_CHECKS
Chris@72 498 if (!isInRange(i, j)) {
Chris@72 499 cerr << "ERROR: Matcher::getAdvance(" << i << ", " << j << "): "
Chris@72 500 << "Location is not in range" << endl;
Chris@72 501 throw "Advance not available";
Chris@72 502 }
Chris@208 503 #endif
Chris@72 504 return m_advance[i][j - m_first[i]];
Chris@72 505 } else {
Chris@72 506 return m_otherMatcher->getAdvance(j, i);
Chris@72 507 }
Chris@72 508 }
Chris@202 509
Chris@202 510 static double k(size_t sz)
Chris@202 511 {
Chris@202 512 return double(sz) / 1024.0;
Chris@202 513 }
Chris@202 514
Chris@202 515 void
Chris@202 516 Matcher::printStats()
Chris@202 517 {
Chris@202 518 if (m_firstPM) cerr << endl;
Chris@202 519
Chris@202 520 cerr << "Matcher[" << this << "] (" << (m_firstPM ? "first" : "second") << "):" << endl;
Chris@202 521 cerr << "- block size " << m_blockSize << ", frame count " << m_frameCount << ", dist x size " << m_distXSize << ", initialised " << m_initialised << endl;
Chris@202 522
Chris@202 523 if (m_features.empty()) {
Chris@202 524 cerr << "- have no features yet" << endl;
Chris@202 525 } else {
Chris@202 526 cerr << "- have " << m_features.size() << " features of " << m_features[0].size() << " bins each (= "
Chris@202 527 << k(m_features.size() * m_features[0].size() * sizeof(featurebin_t)) << "K)" << endl;
Chris@202 528 }
Chris@202 529
Chris@202 530 size_t cells = 0;
Chris@202 531 for (const auto &d: m_distance) {
Chris@202 532 cells += d.size();
Chris@202 533 }
Chris@202 534 if (m_distance.empty()) {
Chris@202 535 cerr << "- have no cells in matrix" << endl;
Chris@202 536 } else {
Chris@202 537 cerr << "- have " << m_distance.size() << " cols in matrix with avg "
Chris@203 538 << double(cells) / double(m_distance.size()) << " rows, total "
Chris@202 539 << cells << " cells" << endl;
Chris@202 540 cerr << "- path costs " << k(cells * sizeof(pathcost_t))
Chris@202 541 << "K, distances " << k(cells * sizeof(distance_t))
Chris@202 542 << "K, advances " << k(cells * sizeof(advance_t)) << "K" << endl;
Chris@202 543 }
Chris@202 544
Chris@202 545 if (m_firstPM && m_otherMatcher) {
Chris@202 546 m_otherMatcher->printStats();
Chris@202 547 cerr << endl;
Chris@202 548 }
Chris@202 549 }
Chris@202 550