use of de.lmu.ifi.dbs.elki.database.ids.ArrayDBIDs in project elki by elki-project.
the class MaterializeKNNAndRKNNPreprocessor method updateKNNsAndRkNNs.
/**
* Updates the kNNs and RkNNs after insertion of the specified ids.
*
* @param ids the ids of newly inserted objects causing a change of
* materialized kNNs and RkNNs
* @return the RkNNs of the specified ids, i.e. the kNNs which have been
* updated
*/
private ArrayDBIDs updateKNNsAndRkNNs(DBIDs ids) {
ArrayModifiableDBIDs rkNN_ids = DBIDUtil.newArray();
DBIDs oldids = DBIDUtil.difference(relation.getDBIDs(), ids);
for (DBIDIter id = oldids.iter(); id.valid(); id.advance()) {
KNNList oldkNNs = storage.get(id);
double knnDist = oldkNNs.getKNNDistance();
// look for new kNNs
KNNHeap heap = null;
for (DBIDIter newid = ids.iter(); newid.valid(); newid.advance()) {
double dist = distanceQuery.distance(id, newid);
if (dist <= knnDist) {
// New id changes the kNNs of oldid.
if (heap == null) {
heap = DBIDUtil.newHeap(oldkNNs);
}
heap.insert(dist, newid);
}
}
// kNNs for oldid have changed:
if (heap != null) {
KNNList newkNNs = heap.toKNNList();
storage.put(id, newkNNs);
// get the difference
int i = 0;
int j = 0;
ModifiableDoubleDBIDList added = DBIDUtil.newDistanceDBIDList();
ModifiableDoubleDBIDList removed = DBIDUtil.newDistanceDBIDList();
// TODO: use iterators.
while (i < oldkNNs.size() && j < newkNNs.size()) {
DoubleDBIDPair drp1 = oldkNNs.get(i);
DoubleDBIDPair drp2 = newkNNs.get(j);
// NOTE: we assume that on ties they are ordered the same way!
if (!DBIDUtil.equal(drp1, drp2)) {
added.add(drp2);
j++;
} else {
i++;
j++;
}
}
if (i != j) {
for (; i < oldkNNs.size(); i++) {
removed.add(oldkNNs.get(i));
}
for (; j < newkNNs.size(); i++) {
added.add(newkNNs.get(i));
}
}
// add new RkNN
for (DoubleDBIDListIter newnn = added.iter(); newnn.valid(); newnn.advance()) {
TreeSet<DoubleDBIDPair> rknns = materialized_RkNN.get(newnn);
rknns.add(makePair(newnn, id));
}
// remove old RkNN
for (DoubleDBIDListIter oldnn = removed.iter(); oldnn.valid(); oldnn.advance()) {
TreeSet<DoubleDBIDPair> rknns = materialized_RkNN.get(oldnn);
rknns.remove(makePair(oldnn, id));
}
rkNN_ids.add(id);
}
}
return rkNN_ids;
}
use of de.lmu.ifi.dbs.elki.database.ids.ArrayDBIDs in project elki by elki-project.
the class NNDescentTest method testKNNQueries.
private void testKNNQueries(Relation<DoubleVector> rep, KNNQuery<DoubleVector> lin_knn_query, KNNQuery<DoubleVector> preproc_knn_query, int k) {
ArrayDBIDs sample = DBIDUtil.ensureArray(rep.getDBIDs());
List<? extends KNNList> lin_knn_ids = lin_knn_query.getKNNForBulkDBIDs(sample, k);
List<? extends KNNList> preproc_knn_ids = preproc_knn_query.getKNNForBulkDBIDs(sample, k);
for (int i = 0; i < rep.size(); i++) {
KNNList lin_knn = lin_knn_ids.get(i);
KNNList pre_knn = preproc_knn_ids.get(i);
DoubleDBIDListIter lin = lin_knn.iter(), pre = pre_knn.iter();
for (; lin.valid() && pre.valid(); lin.advance(), pre.advance(), i++) {
if (DBIDUtil.equal(lin, pre) || lin.doubleValue() == pre.doubleValue()) {
continue;
}
fail(//
new StringBuilder(1000).append("Neighbor distances do not agree: ").append(lin_knn.toString()).append(" got: ").append(pre_knn.toString()).toString());
}
assertEquals("kNN sizes do not agree.", lin_knn.size(), pre_knn.size());
for (int j = 0; j < lin_knn.size(); j++) {
assertTrue("kNNs of linear scan and preprocessor do not match!", DBIDUtil.equal(lin_knn.get(j), pre_knn.get(j)));
assertEquals("kNNs of linear scan and preprocessor do not match!", lin_knn.get(j).doubleValue(), pre_knn.get(j).doubleValue(), 0.);
}
}
}
use of de.lmu.ifi.dbs.elki.database.ids.ArrayDBIDs in project elki by elki-project.
the class MaterializeKNNPreprocessor method objectsInserted.
/**
* Called after new objects have been inserted, updates the materialized
* neighborhood.
*
* @param ids the ids of the newly inserted objects
*/
protected void objectsInserted(DBIDs ids) {
// Could be subclass
final Logging log = getLogger();
StepProgress stepprog = log.isVerbose() ? new StepProgress(3) : null;
ArrayDBIDs aids = DBIDUtil.ensureArray(ids);
// materialize the new kNNs
log.beginStep(stepprog, 1, "New insertions ocurred, materialize their new kNNs.");
// Bulk-query kNNs
List<? extends KNNList> kNNList = knnQuery.getKNNForBulkDBIDs(aids, k);
// Store in storage
DBIDIter iter = aids.iter();
for (int i = 0; i < aids.size(); i++, iter.advance()) {
storage.put(iter, kNNList.get(i));
}
// update the affected kNNs
log.beginStep(stepprog, 2, "New insertions ocurred, update the affected kNNs.");
ArrayDBIDs rkNN_ids = updateKNNsAfterInsertion(ids);
// inform listener
log.beginStep(stepprog, 3, "New insertions ocurred, inform listeners.");
fireKNNsInserted(ids, rkNN_ids);
log.setCompleted(stepprog);
}
use of de.lmu.ifi.dbs.elki.database.ids.ArrayDBIDs in project elki by elki-project.
the class MaterializeKNNPreprocessor method preprocess.
/**
* The actual preprocessing step.
*/
@Override
protected void preprocess() {
// Could be subclass
final Logging log = getLogger();
createStorage();
ArrayDBIDs ids = DBIDUtil.ensureArray(relation.getDBIDs());
if (log.isStatistics()) {
log.statistics(new LongStatistic(this.getClass().getName() + ".k", k));
}
Duration duration = log.isStatistics() ? log.newDuration(this.getClass().getName() + ".precomputation-time").begin() : null;
FiniteProgress progress = getLogger().isVerbose() ? new FiniteProgress("Materializing k nearest neighbors (k=" + k + ")", ids.size(), getLogger()) : null;
// Try bulk
List<? extends KNNList> kNNList = null;
if (usebulk) {
kNNList = knnQuery.getKNNForBulkDBIDs(ids, k);
if (kNNList != null) {
int i = 0;
for (DBIDIter id = ids.iter(); id.valid(); id.advance(), i++) {
storage.put(id, kNNList.get(i));
log.incrementProcessed(progress);
}
}
} else {
final boolean ismetric = getDistanceQuery().getDistanceFunction().isMetric();
for (DBIDIter iter = ids.iter(); iter.valid(); iter.advance()) {
if (ismetric && storage.get(iter) != null) {
log.incrementProcessed(progress);
// Previously computed (duplicate point?)
continue;
}
KNNList knn = knnQuery.getKNNForDBID(iter, k);
storage.put(iter, knn);
if (ismetric) {
for (DoubleDBIDListIter it = knn.iter(); it.valid() && it.doubleValue() == 0.; it.advance()) {
// Reuse
storage.put(it, knn);
}
}
log.incrementProcessed(progress);
}
}
log.ensureCompleted(progress);
if (duration != null) {
log.statistics(duration.end());
}
}
use of de.lmu.ifi.dbs.elki.database.ids.ArrayDBIDs in project elki by elki-project.
the class MaterializeKNNPreprocessor method updateKNNsAfterInsertion.
/**
* Updates the kNNs of the RkNNs of the specified ids.
*
* @param ids the ids of newly inserted objects causing a change of
* materialized kNNs
* @return the RkNNs of the specified ids, i.e. the kNNs which have been
* updated
*/
private ArrayDBIDs updateKNNsAfterInsertion(DBIDs ids) {
ArrayModifiableDBIDs rkNN_ids = DBIDUtil.newArray();
DBIDs oldids = DBIDUtil.difference(relation.getDBIDs(), ids);
for (DBIDIter iter = oldids.iter(); iter.valid(); iter.advance()) {
KNNList kNNs = storage.get(iter);
double knnDist = kNNs.getKNNDistance();
// look for new kNNs
KNNHeap heap = null;
for (DBIDIter iter2 = ids.iter(); iter2.valid(); iter2.advance()) {
double dist = distanceQuery.distance(iter, iter2);
if (dist <= knnDist) {
if (heap == null) {
heap = DBIDUtil.newHeap(kNNs);
}
heap.insert(dist, iter2);
}
}
if (heap != null) {
kNNs = heap.toKNNList();
storage.put(iter, kNNs);
rkNN_ids.add(iter);
}
}
return rkNN_ids;
}
Aggregations