Skip to content

Commit 7984b73

Browse files
committed
BallTree WIP
1 parent 27e4494 commit 7984b73

File tree

9 files changed

+1784
-0
lines changed

9 files changed

+1784
-0
lines changed

src/main/java/org/tinspin/index/balltree/BTNode.java

Lines changed: 445 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
/*
2+
* Copyright 2016-2017 Tilmann Zaeschke
3+
*
4+
* This file is part of TinSpin.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.tinspin.index.balltree;
19+
20+
import org.tinspin.index.Index;
21+
import org.tinspin.index.PointDistance;
22+
23+
import java.util.ArrayList;
24+
import java.util.Arrays;
25+
26+
import static org.tinspin.index.Index.BoxEntry;
27+
28+
class BTUtil {
29+
30+
static final double EPS_MUL = 1.000000001;
31+
32+
private BTUtil() {
33+
}
34+
35+
public static boolean isPointEnclosed(double[] point, double[] min, double[] max) {
36+
for (int d = 0; d < min.length; d++) {
37+
if (point[d] < min[d] || point[d] > max[d]) {
38+
return false;
39+
}
40+
}
41+
return true;
42+
}
43+
44+
45+
/**
46+
* The tests for inclusion with UPPER BOUNDARY EXCLUSIVE!
47+
* I.e. it firs only if point is SMALLER than (center + radius).
48+
*/
49+
public static boolean fitsIntoNode(double[] point, double[] center, double radius) {
50+
return PointDistance.l2(point, center) <= radius;
51+
}
52+
53+
public static boolean isPointEqual(double[] p1, double[] p2) {
54+
for (int d = 0; d < p1.length; d++) {
55+
if (p1[d] != p2[d]) {
56+
return false;
57+
}
58+
}
59+
return true;
60+
}
61+
62+
// public static boolean isRectEqual(double[] p1L, double[] p1U, double[] p2L, double[] p2U) {
63+
// return isPointEqual(p1L, p2L) && isPointEqual(p1U, p2U);
64+
// }
65+
//
66+
// public static <T> boolean isRectEqual(BoxEntry<T> e, double[] keyL, double[] keyU) {
67+
// return isRectEqual(e.min(), e.max(), keyL, keyU);
68+
// }
69+
//
70+
// public static <T> boolean isRectEqual(BoxEntry<T> e, BoxEntry<T> e2) {
71+
// return isRectEqual(e.min(), e.max(), e2.min(), e2.max());
72+
// }
73+
//
74+
// public static boolean overlap(double[] min, double[] max, double[] min2, double[] max2) {
75+
// for (int d = 0; d < min.length; d++) {
76+
// if (max[d] < min2[d] || min[d] > max2[d]) {
77+
// return false;
78+
// }
79+
// }
80+
// return true;
81+
// }
82+
83+
public static boolean overlap(double[] min, double[] max, double[] center, double radius) {
84+
for (int d = 0; d < min.length; d++) {
85+
if (max[d] < center[d] - radius || min[d] > center[d] + radius) {
86+
return false;
87+
}
88+
}
89+
return true;
90+
}
91+
92+
// public static boolean isRectEnclosed(double[] minEnclosed, double[] maxEnclosed, double[] minOuter, double[] maxOuter) {
93+
// for (int d = 0; d < minOuter.length; d++) {
94+
// if (maxOuter[d] < maxEnclosed[d] || minOuter[d] > minEnclosed[d]) {
95+
// return false;
96+
// }
97+
// }
98+
// return true;
99+
// }
100+
//
101+
// /**
102+
// * The tests for inclusion with UPPER BOUNDARY EXCLUSIVE!
103+
// * I.e. it firs only if maxEnclosed is SMALLER than (center + radius).
104+
// */
105+
// public static boolean fitsIntoNode(double[] minEnclosed, double[] maxEnclosed, double[] centerNode, double radiusNode) {
106+
// double r2 = 0;
107+
// for (int d = 0; d < centerNode.length; d++) {
108+
// double r = centerNode[d] -
109+
// r2
110+
// if ((centerNode[d] + radiusNode) <= maxEnclosed[d] || (centerNode[d] - radiusNode) > minEnclosed[d]) {
111+
// return false;
112+
// }
113+
// }
114+
// return true;
115+
// }
116+
117+
public static boolean isNodeEnclosed(double[] centerEnclosed, double radiusEnclosed, double[] centerOuter, double radiusOuter) {
118+
return PointDistance.l2(centerEnclosed, centerOuter) + radiusEnclosed <= radiusOuter;
119+
}
120+
121+
public static <T> double[][] orderCoordinates(ArrayList<Index.PointEntry<T>> points) {
122+
if (points.isEmpty()) {
123+
return new double[0][0];
124+
}
125+
int dim = points.get(0).point().length;
126+
double[][] sorted = new double[dim][points.size()];
127+
for (int i = 0; i < points.size(); i++) {
128+
double[] v = points.get(i).point();
129+
for (int d = 0; d < dim; d++) {
130+
sorted[d][i] = v[d];
131+
}
132+
}
133+
for (int d = 0; d < dim; d++) {
134+
Arrays.sort(sorted[d]);
135+
}
136+
return sorted;
137+
}
138+
139+
public static <T> double calcBoundingSphere(ArrayList<Index.PointEntry<T>> points, double[] center) {
140+
PointDistance dist = PointDistance.L2;
141+
// TODO alternative approach:
142+
// - use orderCoordinates -> avg min/max -> center point.
143+
// - Increase radius until all points are included.
144+
// -> Traverses all points 2 times. -> 1 x min/max calculation + 1x distance calculation
145+
146+
// Default approach: Ritter's bounding sphere Algorithm
147+
// - random point, then find furthest, then find furthest again -> center is halfway distance
148+
// - Traverse all points again to ensure they are all included
149+
// Adjust radius and center. -> Center is moved by half of radius adjustment
150+
// -> This covers the worst case where another extreme point is exactly on the other side of the center
151+
// -> traverse all points 3 times. -> 3 x distance calculation
152+
double maxDist = -1;
153+
int posMaxDist = 0;
154+
// initial random point -> find furthest neighbor
155+
double[] p0 = points.get(0).point();
156+
for (int i = 1; i < points.size(); i++) {
157+
double d = dist.dist(p0, points.get(i));
158+
if (d > maxDist) {
159+
maxDist = d;
160+
posMaxDist = i;
161+
}
162+
}
163+
double[] pFurthest0 = points.get(posMaxDist).point();
164+
165+
maxDist = -1;
166+
for (int i = 0; i < points.size(); i++) {
167+
double d = dist.dist(pFurthest0, points.get(i));
168+
if (d > maxDist) {
169+
maxDist = d;
170+
posMaxDist = i;
171+
}
172+
}
173+
double[] pFurthest1 = points.get(posMaxDist).point();
174+
double radius = maxDist / 2.0;
175+
176+
// center
177+
int dim = pFurthest0.length;
178+
for (int d = 0; d < dim; d++) {
179+
center[d] = (pFurthest0[d] + pFurthest1[d]) / 2.;
180+
}
181+
182+
for (int i = 0; i < points.size(); i++) {
183+
double d = dist.dist(center, points.get(i));
184+
if (d > radius) {
185+
radius = d;
186+
// TODO adjust center, see https://www.researchgate.net/profile/Jack-Ritter/publication/242453691_An_Efficient_Bounding_Sphere/links/56e9d24e08ae95bddc2a2358/An-Efficient-Bounding-Sphere
187+
// double delta = (d - radius) / 2.;
188+
// radius += delta;
189+
}
190+
}
191+
return radius;
192+
}
193+
}

0 commit comments

Comments
 (0)