// Build priority queue
final int sqsize = ps_candidates.size() * (ps_candidates.size() - 1) / 2;
if(logger.isDebuggingFine()) {
logger.debugFine("Number of leaves: " + ps_candidates.size() + " so " + sqsize + " MBR computations.");
}
FiniteProgress mprogress = logger.isVerbose() ? new FiniteProgress("Comparing leaf MBRs", sqsize, logger) : null;
for(int i = 0; i < ps_candidates.size(); i++) {
E pr_entry = ps_candidates.get(i);
List<KNNHeap<D>> pr_heaps = heaps.get(i);
D pr_knn_distance = computeStopDistance(pr_heaps);
for(int j = i + 1; j < ps_candidates.size(); j++) {
E ps_entry = ps_candidates.get(j);
List<KNNHeap<D>> ps_heaps = heaps.get(j);
D ps_knn_distance = computeStopDistance(ps_heaps);
D minDist = distFunction.minDist(pr_entry, ps_entry);
// Resolve immediately:
if(minDist.isNullDistance()) {
N pr = index.getNode(ps_candidates.get(i));
N ps = index.getNode(ps_candidates.get(j));
processDataPagesOptimize(distFunction, doubleOptimize, pr_heaps, ps_heaps, pr, ps);
}
else if(minDist.compareTo(pr_knn_distance) <= 0 || minDist.compareTo(ps_knn_distance) <= 0) {
pq.add(new Task(minDist, i, j));
}
if(mprogress != null) {
mprogress.incrementProcessed(logger);
}
}
}
if(mprogress != null) {
mprogress.ensureCompleted(logger);
}
// Process the queue
FiniteProgress qprogress = logger.isVerbose() ? new FiniteProgress("Processing queue", pq.size(), logger) : null;
IndefiniteProgress fprogress = logger.isVerbose() ? new IndefiniteProgress("Full comparisons", logger) : null;
while(!pq.isEmpty()) {
Task task = pq.poll();
List<KNNHeap<D>> pr_heaps = heaps.get(task.i);
List<KNNHeap<D>> ps_heaps = heaps.get(task.j);
D pr_knn_distance = computeStopDistance(pr_heaps);
D ps_knn_distance = computeStopDistance(ps_heaps);
boolean dor = task.mindist.compareTo(pr_knn_distance) <= 0;
boolean dos = task.mindist.compareTo(ps_knn_distance) <= 0;
if(dor || dos) {
N pr = index.getNode(ps_candidates.get(task.i));
N ps = index.getNode(ps_candidates.get(task.j));
if(dor && dos) {
processDataPagesOptimize(distFunction, doubleOptimize, pr_heaps, ps_heaps, pr, ps);
}
else {
if(dor) {
processDataPagesOptimize(distFunction, doubleOptimize, pr_heaps, null, pr, ps);
}
else /* dos */{
processDataPagesOptimize(distFunction, doubleOptimize, ps_heaps, null, ps, pr);
}
}
if(fprogress != null) {
fprogress.incrementProcessed(logger);
}
}
if(qprogress != null) {
qprogress.incrementProcessed(logger);
}
}
if(qprogress != null) {
qprogress.ensureCompleted(logger);
}
if(fprogress != null) {
fprogress.setCompleted(logger);
}
WritableDataStore<KNNList<D>> knnLists = DataStoreUtil.makeStorage(ids, DataStoreFactory.HINT_STATIC, KNNList.class);
// FiniteProgress progress = logger.isVerbose() ? new
// FiniteProgress(this.getClass().getName(), relation.size(), logger) :
// null;
FiniteProgress pageprog = logger.isVerbose() ? new FiniteProgress("Number of processed data pages", ps_candidates.size(), logger) : null;
// int processed = 0;
for(int i = 0; i < ps_candidates.size(); i++) {
N pr = index.getNode(ps_candidates.get(i));
List<KNNHeap<D>> pr_heaps = heaps.get(i);
// Finalize lists
for(int j = 0; j < pr.getNumEntries(); j++) {
knnLists.put(((LeafEntry) pr.getEntry(j)).getDBID(), pr_heaps.get(j).toKNNList());
}
// Forget heaps and pq
heaps.set(i, null);
// processed += pr.getNumEntries();
// if(progress != null) {
// progress.setProcessed(processed, logger);
// }
if(pageprog != null) {
pageprog.incrementProcessed(logger);
}
}
// if(progress != null) {
// progress.ensureCompleted(logger);
// }
if(pageprog != null) {
pageprog.ensureCompleted(logger);
}
return knnLists;
}