annotate src/Matcher.cpp @ 246:aac9ad4064ea subsequence tip

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