use of de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox in project elki by elki-project.
the class SpatialDirectoryEntry method readExternal.
/**
* Calls the super method and reads the MBR object of this entry from the
* specified input stream.
*
* @param in the stream to read data from in order to restore the object
* @throws java.io.IOException if I/O errors occur
* @throws ClassNotFoundException If the class for an object being restored
* cannot be found.
*/
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.id = in.readInt();
this.mbr = new ModifiableHyperBoundingBox();
this.mbr.readExternal(in);
}
use of de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox in project elki by elki-project.
the class RTreeLinearSplit method split.
@Override
public <E extends SpatialComparable, A> long[] split(A entries, ArrayAdapter<E, A> getter, int minEntries) {
final int num = getter.size(entries);
// Object assignment, and processed objects
long[] assignment = BitsUtil.zero(num);
long[] assigned = BitsUtil.zero(num);
// MBRs and Areas of current assignments
ModifiableHyperBoundingBox mbr1, mbr2;
double area1 = 0, area2 = 0;
// LinearPickSeeds - find worst pair
{
final int dim = getter.get(entries, 0).getDimensionality();
// Best candidates
double bestsep = Double.NEGATIVE_INFINITY;
int w1 = -1, w2 = -1;
// LPS1: find extreme rectangles
for (int d = 0; d < dim; d++) {
// We need to find two candidates each, in case of el==eh!
double minlow = Double.POSITIVE_INFINITY;
double maxlow = Double.NEGATIVE_INFINITY, maxlow2 = Double.NEGATIVE_INFINITY;
double minhig = Double.POSITIVE_INFINITY, minhig2 = Double.POSITIVE_INFINITY;
double maxhig = Double.NEGATIVE_INFINITY;
int el = -1, el2 = -1;
int eh = -1, eh2 = -1;
for (int i = 0; i < num; i++) {
E ei = getter.get(entries, i);
final double low = ei.getMin(d);
final double hig = ei.getMax(d);
minlow = Math.min(minlow, low);
maxhig = Math.max(maxhig, hig);
if (low >= maxlow) {
maxlow2 = maxlow;
maxlow = low;
el2 = el;
el = i;
} else if (low > maxlow2) {
maxlow2 = low;
el2 = i;
}
if (hig <= minhig) {
minhig2 = minhig;
minhig = hig;
eh2 = eh;
eh = i;
} else if (hig < minhig2) {
minhig2 = hig;
eh2 = i;
}
}
// Compute normalized separation
final double normsep;
if (el != eh) {
normsep = minhig - maxlow / (maxhig - minlow);
} else {
// Resolve tie.
double normsep1 = minhig - maxlow2 / (maxhig - minlow);
double normsep2 = minhig2 - maxlow / (maxhig - minlow);
if (normsep1 > normsep2) {
el = el2;
normsep = normsep1;
} else {
eh = eh2;
normsep = normsep2;
}
}
assert (eh != -1 && el != -1 && (eh != el));
if (normsep > bestsep) {
bestsep = normsep;
w1 = el;
w2 = eh;
}
}
// Data to keep
// Mark both as used
BitsUtil.setI(assigned, w1);
BitsUtil.setI(assigned, w2);
// Assign second to second set
BitsUtil.setI(assignment, w2);
// Initial mbrs and areas
final E w1i = getter.get(entries, w1);
final E w2i = getter.get(entries, w2);
area1 = SpatialUtil.volume(w1i);
area2 = SpatialUtil.volume(w2i);
mbr1 = new ModifiableHyperBoundingBox(w1i);
mbr2 = new ModifiableHyperBoundingBox(w2i);
}
// Second phase, QS2+QS3
{
int in1 = 1, in2 = 1;
int remaining = num - 2;
// Choose any element, for example the next.
for (int next = BitsUtil.nextClearBit(assigned, 0); remaining > 0 && next < num; next = BitsUtil.nextClearBit(assigned, next + 1)) {
// Shortcut when minEntries must be fulfilled
if (in1 + remaining <= minEntries) {
// No need to updated assigned, no changes to assignment.
break;
}
if (in2 + remaining <= minEntries) {
// Don't bother to update assigned, though
for (; next < num; next = BitsUtil.nextClearBit(assigned, next + 1)) {
BitsUtil.setI(assignment, next);
}
break;
}
// PickNext
boolean preferSecond = false;
// Cost of putting object into both mbrs
final E next_i = getter.get(entries, next);
final double d1 = SpatialUtil.volumeUnion(mbr1, next_i) - area1;
final double d2 = SpatialUtil.volumeUnion(mbr2, next_i) - area2;
// Prefer smaller increase
preferSecond = (d2 < d1);
// QS3: tie handling
if (d1 == d2) {
// Prefer smaller area
if (area1 != area2) {
preferSecond = (area2 < area1);
} else {
// Prefer smaller group size
preferSecond = (in2 < in1);
}
}
// Mark as used.
BitsUtil.setI(assigned, next);
remaining--;
// Assign
if (!preferSecond) {
in1++;
mbr1.extend(next_i);
area1 = SpatialUtil.volume(mbr1);
} else {
in2++;
BitsUtil.setI(assignment, next);
mbr2.extend(next_i);
area2 = SpatialUtil.volume(mbr2);
}
// Loop from QS2
}
// Note: "assigned" and "remaining" likely not updated!
}
return assignment;
}
use of de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox in project elki by elki-project.
the class AbstractRStarTreeNode method computeMBR.
/**
* Recomputing the MBR is rather expensive.
*
* @return MBR
*/
public ModifiableHyperBoundingBox computeMBR() {
E firstEntry = getEntry(0);
if (firstEntry == null) {
return null;
}
// Note: we deliberately get a cloned copy here, since we will modify it.
ModifiableHyperBoundingBox mbr = new ModifiableHyperBoundingBox(firstEntry);
for (int i = 1; i < numEntries; i++) {
mbr.extend(getEntry(i));
}
return mbr;
}
use of de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox in project elki by elki-project.
the class AbstractXTree method initializeCapacities.
@Override
protected void initializeCapacities(SpatialEntry exampleLeaf) {
/* Simulate the creation of a leaf page to get the page capacity */
try {
int cap = 0;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
SpatialPointLeafEntry sl = new SpatialPointLeafEntry(DBIDUtil.importInteger(0), new double[exampleLeaf.getDimensionality()]);
while (baos.size() <= getPageSize()) {
sl.writeExternal(oos);
oos.flush();
cap++;
}
// the last one caused the page to overflow.
leafCapacity = cap - 1;
} catch (IOException e) {
throw new AbortException("Error determining page sizes.", e);
}
/* Simulate the creation of a directory page to get the capacity */
try {
int cap = 0;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
ModifiableHyperBoundingBox hb = new ModifiableHyperBoundingBox(new double[exampleLeaf.getDimensionality()], new double[exampleLeaf.getDimensionality()]);
XTreeDirectoryEntry xl = new XTreeDirectoryEntry(0, hb);
while (baos.size() <= getPageSize()) {
xl.writeExternal(oos);
oos.flush();
cap++;
}
dirCapacity = cap - 1;
} catch (IOException e) {
throw new AbortException("Error determining page sizes.", e);
}
if (dirCapacity <= 1) {
throw new IllegalArgumentException("Node size of " + getPageSize() + " Bytes is chosen too small!");
}
if (dirCapacity < 10) {
getLogger().warning("Page size is choosen very small! Maximum number of entries " + "in a directory node = " + (dirCapacity - 1));
}
// minimum entries per directory node
dirMinimum = (int) Math.round((dirCapacity - 1) * settings.relativeMinEntries);
if (dirMinimum < 2) {
dirMinimum = 2;
}
// minimum entries per directory node
settings.min_fanout = (int) Math.round((dirCapacity - 1) * settings.relativeMinFanout);
if (settings.min_fanout < 2) {
settings.min_fanout = 2;
}
if (leafCapacity <= 1) {
throw new IllegalArgumentException("Node size of " + getPageSize() + " Bytes is chosen too small!");
}
if (leafCapacity < 10) {
getLogger().warning("Page size is choosen very small! Maximum number of entries " + "in a leaf node = " + (leafCapacity - 1));
}
// minimum entries per leaf node
leafMinimum = (int) Math.round((leafCapacity - 1) * settings.relativeMinEntries);
if (leafMinimum < 2) {
leafMinimum = 2;
}
dimensionality = exampleLeaf.getDimensionality();
if (getLogger().isVerbose()) {
getLogger().verbose("Directory Capacity: " + (dirCapacity - 1) + "\nDirectory minimum: " + dirMinimum + "\nLeaf Capacity: " + (leafCapacity - 1) + "\nLeaf Minimum: " + leafMinimum + "\nminimum fanout: " + settings.min_fanout);
}
}
use of de.lmu.ifi.dbs.elki.data.ModifiableHyperBoundingBox in project elki by elki-project.
the class AbstractXTree method calculateOverlapIncrease.
/**
* Celebrated by the Profiler as a lot faster than the previous variant: that
* used to calculate all overlaps of the old MBR and the new MBR with all
* other MBRs. Now: The overlaps are only calculated if necessary:<br>
* <ul>
* <li>the new MBR does not have to be tested on overlaps if the current
* dimension has never changed</li>
* <li>the old MBR does not have to be tested if the new MBR shows no overlaps
* </li>
* </ul>
* Furthermore tries to avoid rounding errors arising from large value ranges
* and / or larger dimensions. <br>
* <br>
* However: hardly any difference in real runtime!
*
* @param node Node
* @param ei current entry
* @param testMBR extended MBR of <code>ei</code>
* @return
*/
private double calculateOverlapIncrease(N node, SpatialEntry ei, SpatialComparable testMBR) {
ModifiableHyperBoundingBox eiMBR = new ModifiableHyperBoundingBox(ei);
ModifiableHyperBoundingBox testMBRModifiable = new ModifiableHyperBoundingBox(testMBR);
double[] lb = eiMBR.getMinRef();
double[] ub = eiMBR.getMaxRef();
double[] lbT = testMBRModifiable.getMinRef();
double[] ubT = testMBRModifiable.getMaxRef();
// next tested lower bounds
double[] lbNext = null;
// and upper bounds
double[] ubNext = null;
boolean[] dimensionChanged = new boolean[lb.length];
for (int i = 0; i < dimensionChanged.length; i++) {
if (lb[i] > lbT[i] || ub[i] < ubT[i]) {
dimensionChanged[i] = true;
}
}
double multiOverlapInc = 0, multiOverlapMult = 1, mOOld = 1, mONew = 1;
// dimensional overlap
double ol, olT;
for (int j = 0; j < node.getNumEntries(); j++) {
SpatialEntry ej = node.getEntry(j);
if (getPageID(ej) != getPageID(ei)) {
// is constant for a unchanged dimension
multiOverlapMult = 1;
// overlap for old MBR on changed dimensions
mOOld = 1;
// overlap on new MBR on changed dimension
mONew = 1;
ModifiableHyperBoundingBox ejMBR = new ModifiableHyperBoundingBox(ej);
lbNext = ejMBR.getMinRef();
ubNext = ejMBR.getMaxRef();
for (int i = 0; i < dimensionChanged.length; i++) {
if (dimensionChanged[i]) {
if (lbT[i] > ubNext[i] || ubT[i] < lbNext[i]) {
multiOverlapMult = 0;
// old MBR has no overlap either
break;
}
olT = (ubT[i] > ubNext[i] ? ubNext[i] : ubT[i]) - (lbT[i] < lbNext[i] ? lbNext[i] : lbT[i]);
mONew *= olT;
if (mOOld != 0) {
// else: no use in calculating overlap
ol = (ub[i] > ubNext[i] ? ubNext[i] : ub[i]) - (lb[i] < lbNext[i] ? lbNext[i] : lb[i]);
if (ol < 0) {
ol = 0;
}
mOOld *= ol;
}
} else {
if (lb[i] > ubNext[i] || ub[i] < lbNext[i]) {
multiOverlapMult = 0;
break;
}
ol = (ub[i] > ubNext[i] ? ubNext[i] : ub[i]) - (lb[i] < lbNext[i] ? lbNext[i] : lb[i]);
multiOverlapMult *= ol;
}
}
if (multiOverlapMult != 0) {
multiOverlapInc += multiOverlapMult * (mONew - mOOld);
}
}
}
return multiOverlapInc;
}
Aggregations