def test_circumsphere(): from numpy import allclose from numpy.random import normal, uniform from adaptive.learner.triangulation import circumsphere, fast_norm def generate_random_sphere_points(dim, radius=0): """https://math.stackexchange.com/a/1585996""" vec = [None] * (dim + 1) center = uniform(-100, 100, dim) radius = uniform(1.0, 100.0) if radius == 0 else radius for i in range(dim + 1): points = normal(0, size=dim) x = fast_norm(points) points = points / x * radius vec[i] = tuple(points + center) return radius, center, vec for dim in range(2, 10): radius, center, points = generate_random_sphere_points(dim) circ_center, circ_radius = circumsphere(points) err_msg = "" if not allclose(circ_center, center): err_msg += f"Calculated center ({circ_center}) differs from true center ({center})\n" if not allclose(radius, circ_radius): err_msg += ( f"Calculated radius {circ_radius} differs from true radius {radius}\n" ) if err_msg: raise AssertionError(err_msg)
def choose_point_in_simplex(simplex, transform=None): """Choose a new point in inside a simplex. Pick the center of the simplex if the shape is nice (that is, the circumcenter lies within the simplex). Otherwise take the middle of the longest edge. Parameters ---------- simplex : numpy array The coordinates of a triangle with shape (N+1, N). transform : N*N matrix The multiplication to apply to the simplex before choosing the new point. Returns ------- point : numpy array of length N The coordinates of the suggested new point. """ if transform is not None: simplex = np.dot(simplex, transform) # choose center if and only if the shape of the simplex is nice, # otherwise: the center the longest edge center, _radius = circumsphere(simplex) if point_in_simplex(center, simplex): point = np.average(simplex, axis=0) else: distances = scipy.spatial.distance.pdist(simplex) distance_matrix = scipy.spatial.distance.squareform(distances) i, j = np.unravel_index(np.argmax(distance_matrix), distance_matrix.shape) point = (simplex[i, :] + simplex[j, :]) / 2 if transform is not None: point = np.linalg.solve(transform, point) # undo the transform return point