Skip to content

Commit

Permalink
Fix root-node precision problems
Browse files Browse the repository at this point in the history
  • Loading branch information
tzaeschke committed Jun 23, 2024
1 parent 93df62c commit fdb6c7e
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 8 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Fixed tree consistency (nValues) -> verify
- Fixed bug in qt2.contains()
- Fixed tree inconsistency after root resizing after insert(). [#42](https://github.com/tzaeschke/tinspin-indexes/issues/42)
- CLean up calls to checkMerge() -> call leaf-merge only in leaf!
- What is going on with root expansion? Why does it not fail in tests?
Essentially, we enforce all radii and thecenter of the root to be a power of two.
This should immensely reduce and problems with precision errors.
- check qt0

## [2.1.3] - 2023-11-19
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/tinspin/index/qthypercube2/QNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ void checkNode(QStats s, QNode<T> parent, int depth) {
if (parent != null) {
if (!QUtil.isNodeEnclosed(center, radius, parent.center, parent.radius*QUtil.EPS_MUL)) {
System.out.println("Outer: " + parent.radius + " " + Arrays.toString(parent.center));
System.out.println("Child: " + radius + " " + Arrays.toString(center));
System.out.println("Child(" + depth + "): " + radius + " " + Arrays.toString(center));
for (int d = 0; d < center.length; d++) {
double parentMax = parent.center[d] + parent.radius;
double childMax = center[d] + radius;
Expand Down
43 changes: 38 additions & 5 deletions src/main/java/org/tinspin/index/qthypercube2/QuadTreeKD2.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public void insert(double[] key, T value) {
PointEntry<T> e = new PointEntry<>(key, value);
if (root == null) {
// We calculate a better radius when adding a second point.
root = new QNode<>(key.clone(), INITIAL_RADIUS);
root = new QNode<>(normalizeCopy(key), INITIAL_RADIUS);
}
if (root.getRadius() == INITIAL_RADIUS) {
adjustRootSize(key);
Expand All @@ -127,15 +127,34 @@ private void adjustRootSize(double[] key) {
return;
}
if (root.getRadius() == INITIAL_RADIUS) {
double dist = PointDistance.L2.dist(key, root.getCenter());
if (dist > 0) {
root.adjustRadius(2 * dist);
double dMax = maxOrthoDistance(key, root.getCenter());
for (int i = 0; i < root.getValueCount(); i++) {
dMax = Math.max(dMax, maxOrthoDistance(root.getValues()[i].point(), root.getCenter()));
}
double radius = normalize(dMax) * 2;
if (radius > 0) {
root.adjustRadius(radius);
} else if (root.getValueCount() >= maxNodeSize - 1) {
// we just set an arbitrary radius here
// all entries have (approximately?) the same coordinates. We just set an arbitrary radius here.
root.adjustRadius(1000);
}
// double dist = PointDistance.L2.dist(key, root.getCenter());
// if (dist > 0) {
// root.adjustRadius(2 * dist);
// } else if (root.getValueCount() >= maxNodeSize - 1) {
// // we just set an arbitrary radius here
// root.adjustRadius(1000);
// }
}
}

private static double maxOrthoDistance(double[] v1, double[] v2) {
double dMax = 0;
for (int i = 0; i < v1.length; i++) {
dMax = Math.max(dMax, Math.abs(v1[i] - v2[i]));
}
return dMax;
}

/**
* Check whether a given key exists.
Expand Down Expand Up @@ -260,6 +279,20 @@ public T updateIf(double[] oldKey, double[] newKey, Predicate<PointEntry<T>> con
return e.value();
}

private static double normalize(double d) {
// Set fraction to "0".
return Double.longBitsToDouble(Double.doubleToRawLongBits(d) & 0xFFF0_0000_0000_0000L);
}

private static double[] normalizeCopy(double[] d) {
double[] d2 = new double[d.length];
for (int i = 0; i < d.length; i++) {
d2[i] = normalize(d[i]);
}
// System.out.println("NORM: " + Arrays.toString(d) + " -> " + Arrays.toString(d2));
return d2;
}

/**
* Ensure that the tree covers the entry.
* @param e Entry to cover.
Expand Down
7 changes: 7 additions & 0 deletions src/test/java/org/tinspin/index/test/PointMultimapTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ private void smokeTest(List<Entry> data) {
for (Entry e : data) {
tree.insert(e.p, e);
}

// Check consistency
tree.getStats();

// System.out.println(tree.toStringTree());
for (Entry e : data) {
PointIterator<Entry> it = tree.queryExactPoint(e.p);
Expand All @@ -167,6 +171,9 @@ private void smokeTest(List<Entry> data) {
assertEquals(data.size(), nExtent);
}

//System.out.println(tree.toStringTree());
tree.getStats();

for (Entry e : data) {
// System.out.println("query: " + Arrays.toString(e.p));
PointIterator<Entry> iter = tree.query(e.p, e.p);
Expand Down

0 comments on commit fdb6c7e

Please sign in to comment.