use of de.lmu.ifi.dbs.elki.database.ids.KNNHeap 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.KNNHeap in project elki by elki-project.
the class SpacefillingMaterializeKNNPreprocessor method preprocess.
@Override
protected void preprocess() {
// Prepare space filling curve:
final long starttime = System.currentTimeMillis();
final int size = relation.size();
final int numgen = curvegen.size();
final int numcurves = numgen * variants;
List<List<SpatialPair<DBID, NumberVector>>> curves = new ArrayList<>(numcurves);
for (int i = 0; i < numcurves; i++) {
curves.add(new ArrayList<SpatialPair<DBID, NumberVector>>(size));
}
for (DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
final NumberVector v = relation.get(iditer);
SpatialPair<DBID, NumberVector> ref = new SpatialPair<DBID, NumberVector>(DBIDUtil.deref(iditer), v);
for (List<SpatialPair<DBID, NumberVector>> curve : curves) {
curve.add(ref);
}
}
// Sort spatially
final double[] mms = SpatialSorter.computeMinMax(curves.get(0));
final double[] mmscratch = new double[mms.length];
final int numdim = mms.length >>> 1;
final int[] permutation = new int[numdim];
for (int j = 0; j < variants; j++) {
for (int i = 0; i < mms.length; i += 2) {
double len = mms[i + 1] - mms[i];
mmscratch[i] = mms[i] - len * random.nextDouble();
mmscratch[i + 1] = mms[i + 1] + len * random.nextDouble();
}
// Generate permutation:
for (int i = 0; i < numdim; i++) {
permutation[i] = i;
}
// Knuth / Fisher-Yates style shuffle
for (int i = numdim - 1; i > 0; i--) {
// Swap with random preceeding element.
int ri = random.nextInt(i + 1);
int tmp = permutation[ri];
permutation[ri] = permutation[i];
permutation[i] = tmp;
}
for (int i = 0; i < numgen; i++) {
curvegen.get(i).sort(curves.get(i + numgen * j), 0, size, mmscratch, permutation);
}
}
// Build position index, DBID -> position in the three curves
WritableDataStore<int[]> positions = DataStoreUtil.makeStorage(relation.getDBIDs(), DataStoreFactory.HINT_TEMP | DataStoreFactory.HINT_HOT, int[].class);
for (int cnum = 0; cnum < numcurves; cnum++) {
Iterator<SpatialPair<DBID, NumberVector>> it = curves.get(cnum).iterator();
for (int i = 0; it.hasNext(); i++) {
SpatialPair<DBID, NumberVector> r = it.next();
final int[] data;
if (cnum == 0) {
data = new int[numcurves];
positions.put(r.first, data);
} else {
data = positions.get(r.first);
}
data[cnum] = i;
}
}
// Convert to final storage
final int wsize = (int) Math.ceil(window * k);
storage = DataStoreUtil.makeStorage(relation.getDBIDs(), DataStoreFactory.HINT_STATIC, KNNList.class);
HashSetModifiableDBIDs cands = DBIDUtil.newHashSet(2 * wsize * numcurves);
for (DBIDIter iditer = relation.iterDBIDs(); iditer.valid(); iditer.advance()) {
// Get candidates.
cands.clear();
int[] posi = positions.get(iditer);
for (int i = 0; i < posi.length; i++) {
List<SpatialPair<DBID, NumberVector>> curve = curves.get(i);
final int start = Math.max(0, posi[i] - wsize);
final int end = Math.min(posi[i] + wsize + 1, curve.size());
for (int pos = start; pos < end; pos++) {
cands.add(curve.get(pos).first);
}
}
int distc = 0;
KNNHeap heap = DBIDUtil.newHeap(k);
O vec = relation.get(iditer);
for (DBIDIter iter = cands.iter(); iter.valid(); iter.advance()) {
heap.insert(distanceQuery.distance(vec, iter), iter);
distc++;
}
storage.put(iditer, heap.toKNNList());
mean.put(distc / (double) k);
}
final long end = System.currentTimeMillis();
if (LOG.isStatistics()) {
LOG.statistics(new LongStatistic(this.getClass().getCanonicalName() + ".construction-time.ms", end - starttime));
}
}
use of de.lmu.ifi.dbs.elki.database.ids.KNNHeap in project elki by elki-project.
the class MkMaxTree method preInsert.
/**
* Adapts the knn distances before insertion of the specified entry.
*/
@Override
protected void preInsert(MkMaxEntry entry) {
KNNHeap knns_o = DBIDUtil.newHeap(getKmax());
preInsert(entry, getRootEntry(), knns_o);
}
use of de.lmu.ifi.dbs.elki.database.ids.KNNHeap 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