|
|
@@ -92,140 +92,6 @@ def norms(points):
|
|
|
return L.Concatenate()([m, nsq]).numpy()
|
|
|
|
|
|
|
|
|
-
|
|
|
-class Ball:
|
|
|
- def __init__(self, points=None, indices=None, parent=None, center=None):
|
|
|
- if center is not None:
|
|
|
- self.center = center
|
|
|
- elif points is not None:
|
|
|
- self.center = calculateCenter(np.array(points))
|
|
|
- else:
|
|
|
- raise ParameterError("Missing points or center")
|
|
|
- self.radius = 0
|
|
|
- self.points = []
|
|
|
- self.indices = set()
|
|
|
- self.childs = []
|
|
|
- self.parent = parent
|
|
|
-
|
|
|
- if points is not None and indices is not None:
|
|
|
- for (i, r) in zip(indices, distancesToPoint(self.center, points)):
|
|
|
- self.add(i, r)
|
|
|
- elif points is not None:
|
|
|
- raise ParameterError("Missing indices")
|
|
|
-
|
|
|
- def findIt(self, r):
|
|
|
- if r == self.points[0][1]:
|
|
|
- return 0
|
|
|
-
|
|
|
- upper = len(self.points) - 1
|
|
|
- lower = 0
|
|
|
- while upper > lower + 1:
|
|
|
- h = (upper + lower) // 2
|
|
|
- if self.points[h][1] >= r:
|
|
|
- upper = h
|
|
|
- else:
|
|
|
- lower = h
|
|
|
- return upper
|
|
|
-
|
|
|
-
|
|
|
- def add(self, xi, r):
|
|
|
- if xi in self.indices:
|
|
|
- return False
|
|
|
-
|
|
|
- # Here we know, that x is not in points.
|
|
|
- newEntry = (xi, r)
|
|
|
- self.indices.add(xi)
|
|
|
-
|
|
|
- # Special case: empty list or new element will extend the radius:
|
|
|
- # Here we can avoid the search
|
|
|
- if self.points == [] or r >= self.radius:
|
|
|
- self.points.append(newEntry)
|
|
|
- self.radius = r
|
|
|
- return True
|
|
|
-
|
|
|
- # Special case: r <= min radius
|
|
|
- # Here we can avoid the search
|
|
|
- if self.points[0][1] >= r:
|
|
|
- self.points = [newEntry] + self.points
|
|
|
- return True
|
|
|
-
|
|
|
- # Here we know that min radius < r < max radius.
|
|
|
- # So len(points) >= 2.
|
|
|
-
|
|
|
- pos = self.findIt(r)
|
|
|
-
|
|
|
- # here shoul be: r(pos) >= r > r(pos - 1)
|
|
|
- self.points = self.points[:pos] + [newEntry] + self.points[pos: ]
|
|
|
-
|
|
|
- return True
|
|
|
-
|
|
|
- def remove(self, xi, r):
|
|
|
- if xi not in self.indices:
|
|
|
- return False
|
|
|
-
|
|
|
-
|
|
|
- # special case: remove the element with the heighest radius:
|
|
|
- if self.points[-1][0] == xi:
|
|
|
- self.indices.remove(xi)
|
|
|
- self.points = self.points[: -1]
|
|
|
- if self.points == []:
|
|
|
- self.radius = 0.0
|
|
|
- else:
|
|
|
- self.radius = self.points[-1][1]
|
|
|
- return True
|
|
|
-
|
|
|
- pos = self.findIt(r)
|
|
|
- nPoints = len(self.points)
|
|
|
- # pos is the smalest position with:
|
|
|
- # r(pos - 1) < r <= r(pos)
|
|
|
-
|
|
|
- # Just in case: check that we remove the correct index.
|
|
|
- while pos < nPoints and r == self.points[pos]:
|
|
|
- if self.points[pos][0] == xi:
|
|
|
- self.indices.remove(xi)
|
|
|
- self.points = self.points[:pos] + self.points[(pos + 1): ]
|
|
|
- return True
|
|
|
- pos += 1
|
|
|
-
|
|
|
- return False
|
|
|
-
|
|
|
- def divideBall(self, X):
|
|
|
- indices = [i for (i, _r) in self.points]
|
|
|
- points = np.array([X[i] for i in indices])
|
|
|
-
|
|
|
- distances = tf.keras.layers.Dot(axes=(1,1))([points, points]).numpy()
|
|
|
- ball = Ball(points, indices, center=np.zeros(len(points[0])))
|
|
|
-
|
|
|
- h = len(ball) // 2
|
|
|
- indicesA = [i for (i, _) in ball.points[:h]]
|
|
|
- indicesB = [i for (i, _) in ball.points[h:]]
|
|
|
- pointsA = np.array([X[i] for i in indicesA])
|
|
|
- pointsB = np.array([X[i] for i in indicesB])
|
|
|
-
|
|
|
- self.childs = []
|
|
|
-
|
|
|
- print(f"{len(points)} -> <{len(pointsA)}|{len(pointsB)}>")
|
|
|
- self.childs.append(Ball(pointsA, indicesA, self))
|
|
|
- self.childs.append(Ball(pointsB, indicesB, self))
|
|
|
-
|
|
|
- return self.childs
|
|
|
-
|
|
|
- def __len__(self):
|
|
|
- return len(self.points)
|
|
|
-
|
|
|
- def smalestBallFor(self, i):
|
|
|
- if i not in self.indices:
|
|
|
- return None
|
|
|
-
|
|
|
- for c in self.childs:
|
|
|
- b = c.smalestBallFor(i)
|
|
|
- if b is not None:
|
|
|
- return b
|
|
|
-
|
|
|
- return self
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
class NNSearch:
|
|
|
def __init__(self, nebSize=5, timingDict=None):
|
|
|
self.nebSize = nebSize
|