annotate src/Matcher.cpp @ 214:97cc0b9135e7

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