annotate src/Matcher.cpp @ 213:2fcd1c14f0f6

Default scale of 150 seems a reasonable cautious value
author Chris Cannam
date Fri, 27 Feb 2015 14:27:34 +0000
parents 827176d3b6ec
children 97cc0b9135e7
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@212 84 return (m_bestPathCost[i][j - m_first[i]] != INVALID_PATHCOST);
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@203 99 for (auto c: m_bestPathCost[i]) {
Chris@212 100 if (c != INVALID_PATHCOST) 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@212 115 if (m_bestPathCost[i][j - m_first[i]] != INVALID_PATHCOST) {
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@87 133 (j < int(m_first[i] + m_bestPathCost[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