def test_solution(): for i in range(100): T1 = random_shape(3) T2 = random_shape(3) target, r1, refl, perm = triangle_solution(T1, T2) r2 = TriangleMMD(T1, T2) assert(np.isclose(r1, r2))
def test_metric(): for i in range(1000): T1 = random_shape(3) T2 = random_shape(3) T3 = random_shape(3) TriangleMetric(T1, T2) _T1 = np.copy(T1) _T2 = np.copy(T2) _T3 = np.copy(T3) fail = False #non-negativity T1T2 = TriangleMetric(T1, T2) if T1T2 >= 0.0: print(f'non-negativity: PASS') else: fail = True print(f'non-negativity: FAIL - {T1T2}') # identity T1T1 = TriangleMetric(T1, T1) if np.isclose(T1T1, 0.0): print(f'identity: PASS') else: fail = True print(f'identity: FAIL - {T1T1}') # symmetry T2T1 = TriangleMetric(T2, T1) if np.isclose(T1T2, T2T1): print(f'symmetry: PASS') else: fail = True print(f'symmetry: FAIL - {T1T2} != {T2T1}') # triangle inequality T2T3 = TriangleMetric(T2, T3) T1T3 = TriangleMetric(T1, T3) if np.isclose(T1T3, T1T2 + T2T3) or T1T3 < T1T2 + T2T3: print(f'triangle inequality: PASS') else: fail = True print(f'triangle inequality: FAIL - {T1T3} !<= {T1T2} + {T2T3} ({T1T2 + T2T3})') if fail: print(f'T1: {T1}') print(f'T2: {T2}') print(f'T3: {T3}') break
def test_less_equals(self): '''This test generates a random shape, extends it, and asserts that the random shape is <= the extension''' for x in range(0,n): random_shape = shapes.random_shape() extension = random_shape.extend() self.assertTrue(random_shape <= extension) if x % 100 == 0: print(x)
def test_four_circles(): """Tests the conjecture that at most four must travel the solution""" pos = random_shape(4, 0.0, 1.0) shp = random_shape(4, 0.0, 1.0) shp = regular_shape(4) rep, radiuses = replication_spanner_circles(shp, pos[0], pos[1], 0.1) ax: plt.Axes fig, ax = plt.subplots() ax.set_aspect('equal', 'box') ax.scatter(*zip(*pos), color='black') ax.scatter(*zip(*rep), color='blue') patches = [plt.Circle(c, radius) for c, radius in zip(rep[2:], radiuses[2:])] ax.add_collection(PatchCollection(patches, alpha=0.4)) plt.show()
def test_equals(self): '''This test generates a random shape, creates a random example of it, retraces the example and asserts that the two shapes are equal.''' for x in range(0,n): random_shape = shapes.random_shape() imprint = random_shape.generate() imprint_shape = shapes.factory(imprint) self.assertEqual(random_shape, imprint_shape) if x % 100 == 0: print(x)
def random_positions(plot_radius: bool = False): fig: plt.Figure ax: plt.Axes fig, ax = plt.subplots() plt.subplots_adjust(bottom=0.25) ax.axis('equal') axslider = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor='lightgoldenrodyellow') axbutton = plt.axes([0.25, 0.15, 0.65, 0.03], facecolor='lightgoldenrodyellow') bnew = Button(axbutton, 'New') num_slider = Slider(axslider, 'Robots', 3, 7, valinit=3, valstep=1) # Initalize formation = regular_shape(int(num_slider.val)) positions = random_shape(len(formation)) target, radius = approximation(positions, formation) colors = get_colors(len(formation)) arr = np.arange(positions.shape[0]) srcs = ax.scatter(positions[:,0], positions[:,1], marker='o', color=colors) dsts = ax.scatter(target[:,0], target[:,1], marker='x', color=colors) def get_circles(positions: np.array, radius: float) -> List[plt.Circle]: return [plt.Circle(position, radius) for position in positions] circles = PatchCollection(get_circles(positions, radius), alpha=0.4) circles.set_color(colors) ax.add_collection(circles) def update(event): formation = regular_shape(int(num_slider.val)) positions = random_shape(len(formation)) target, radius = approximation(positions, formation) srcs.set_offsets(positions) dsts.set_offsets(target) circles.set_paths(get_circles(positions, radius)) colors = get_colors(positions.shape[0]) srcs.set_color(colors) dsts.set_color(colors) circles.set_color(colors) # Set Axis Scale points = np.concatenate([positions, target]) llim, hlim = points.min() - radius, points.max() + radius ax.set_xlim(llim, hlim) ax.set_ylim(llim, hlim) ax.autoscale_view() fig.canvas.draw_idle() bnew.on_clicked(update) num_slider.on_changed(update) ax.autoscale_view() plt.show()
def update(event=None): p = random_shape(n, 0.0, 1.0) # print('pos:', p) scatter_p.set_offsets(p) formation = random_shape(n, 0.0, 1.0) q_sol = solution(p, formation) # print('sol:', np.linalg.norm(p - q_sol, axis=1)) scatter_sol.set_offsets(q_sol) q_opt, _, _ = convex_solution(p, formation) r_opt = np.linalg.norm(p - q_opt, axis=1) print(f'Ours: {is_similar(q_sol, formation)}') print(f'Theirs: {is_similar(q_opt, formation)}') # print('opt:', r_opt) scatter_opt.set_offsets(q_opt) fig.canvas.draw_idle()
def test_greater_equals(self): for x in range(0,n): random_shape = shapes.random_shape() reduction = random_shape.shrink() try: self.assertTrue(random_shape >= reduction) except AssertionError: print(random_shape, '\n', reduction) raise if x % 100 == 0: print(x)
def test_assignment(): import matplotlib.pyplot as plt from matplotlib import collections as mc for i in range(100): T1 = random_shape(3) T2 = random_shape(3) # Assignment T1 = T1[np.argsort(to_angles(T1))] T2 = T2[np.argsort(to_angles(T2))] target, r1, refl, perm = triangle_solution(T1, T2) _target, _r1, _refl = triangle_solution(T1, T2, do_perm=False) if not np.isclose(r1, _r1): print(f'r1: {r1}, _r1: {_r1}') fig: plt.Figure ax: plt.Axes fig, ax = plt.subplots() ax.axis('equal') colors = np.array(list('rgb')) ax.scatter(T1[:,0], T1[:,1], c=colors, marker='o') ax.scatter(target[:,0], target[:,1], c=colors[np.argsort(to_angles(target))], marker='x') ax.scatter(_target[:,0], _target[:,1], c=colors, marker='.') lines = mc.LineCollection( [ *zip(T1.tolist(), np.roll(T1, 1, axis=0).tolist()), *zip(target.tolist(), np.roll(target, 1, axis=0).tolist()), *zip(_target.tolist(), np.roll(_target, 1, axis=0).tolist()), ], # linewidths=2, colors='black' ) ax.add_collection(lines) plt.show()
def new_positions(val=None): nonlocal positions, formation positions = random_shape(number) formation = regular_shape(number) scatter_positions.set_offsets(positions) # Set Axis Scale points = np.concatenate([positions, formation]) llim, hlim = points.min() - 1, points.max() + 1 ax.set_xlim(llim, hlim) ax.set_ylim(llim, hlim) ax.autoscale_view() update()
def update(event): formation = regular_shape(int(num_slider.val)) positions = random_shape(len(formation)) target, radius = approximation(positions, formation) srcs.set_offsets(positions) dsts.set_offsets(target) circles.set_paths(get_circles(positions, radius)) colors = get_colors(positions.shape[0]) srcs.set_color(colors) dsts.set_color(colors) circles.set_color(colors) # Set Axis Scale points = np.concatenate([positions, target]) llim, hlim = points.min() - radius, points.max() + radius ax.set_xlim(llim, hlim) ax.set_ylim(llim, hlim) ax.autoscale_view() fig.canvas.draw_idle()
def new_positions(event): nonlocal positions, focuses, target positions = random_shape(3) target, radius = triangle_solution(positions, formation) focus = get_intersect(positions[0], target[0], positions[1], target[1]) focuses = [focus]
def test_same_solution(positions: Optional[np.array] = None, formation: Optional[np.array] = None, speed: float = 0.002): if positions is None: positions = random_shape(3) print(positions) if formation is None: formation = regular_shape(3) fig: plt.Figure ax: plt.Axes fig, ax = plt.subplots() plt.subplots_adjust(bottom=0.25) ax.axis('equal') axslider = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor='lightgoldenrodyellow') axbutton = plt.axes([0.25, 0.15, 0.65, 0.03], facecolor='lightgoldenrodyellow') bnew = Button(axbutton, 'New') speed_slider = Slider(axslider, 'Speed', 0, 0.05, valinit=speed) # Intial computation target, radius = triangle_solution(positions, formation) directions = (target - positions) / np.linalg.norm(target - positions, axis=1)[:, np.newaxis] * speed focuses = [] focus = get_intersect(positions[0], target[0], positions[1], target[1]) focuses.append(focus) # Create scatter plots pos_scatter = ax.scatter(positions[:, 0], positions[:, 1], c='red') tar_scatter = ax.scatter(target[:, 0], target[:, 1], c='blue') foc_scatter = ax.scatter([focus[0]], [focus[1]], c='green') def init(): ax.set_xlim(-2, 2) ax.set_ylim(-2, 2) return pos_scatter, tar_scatter, foc_scatter def new_positions(event): nonlocal positions, focuses, target positions = random_shape(3) target, radius = triangle_solution(positions, formation) focus = get_intersect(positions[0], target[0], positions[1], target[1]) focuses = [focus] bnew.on_clicked(new_positions) def new_speed(event): nonlocal speed, directions speed = speed_slider.val directions = np.linalg.norm(directions, axis=0) * speed speed_slider.on_changed(new_speed) def update(frame): # Gets called for every frame in animation nonlocal target, positions, directions, speed _target, _ = triangle_solution(positions, formation) # switch direction only when a new target is found if not np.allclose(_target, target): target = _target directions = (target - positions) / np.linalg.norm(target - positions, axis=1)[:, np.newaxis] * speed focus = get_intersect(positions[0], target[0], positions[1], target[1]) # foc_scatter.set_offsets([focus]) focuses.append(focus) foc_scatter.set_offsets(focuses) positions += directions pos_scatter.set_offsets(positions) tar_scatter.set_offsets(target) return pos_scatter, tar_scatter, foc_scatter ani = FuncAnimation(fig, update, frames=None, init_func=init, blit=True, repeat=False, interval=1, cache_frame_data=False) plt.show()
def test_replications( formation: Optional[np.array] = None, radius_range: Tuple[float, float] = (0.0, 0.5)) -> None: fig, ax = plt.subplots() plt.subplots_adjust(bottom=0.3) ax.axis('equal') number = 3 positions = random_shape(number) if not formation: formation = regular_shape(number) init_radius = radius_range[1] ax_radius = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor='lightgoldenrodyellow') ax_button = plt.axes([0.25, 0.15, 0.65, 0.03], facecolor='lightgoldenrodyellow') ax_number = plt.axes([0.25, 0.2, 0.65, 0.03], facecolor='lightgoldenrodyellow') num_slider = Slider(ax_number, 'Robots', 3, 7, valinit=3, valstep=1) s_radius = Slider(ax_radius, 'Radius', *radius_range, valinit=init_radius) b_random = Button(ax_button, 'New') scatter_positions = ax.scatter(x=positions[:, 0], y=positions[:, 1], color='black') def get_shapes(radius): c_positions = list(combinations(range(len(positions)), 2)) c_formations = list(combinations(range(len(formation)), 2)) combs = list(product(c_positions, c_formations)) patches = [] colors = get_colors(len(combs)) for color, ((i_pos1, i_pos2), (i_for1, i_for2) )in zip(colors, combs): repl, radiuses = replication_spanner_circles( formation, positions[i_pos1], positions[i_pos2], radius, *sorted([i_for1, i_for2]) ) patches.append(plt.Polygon(repl, color=color, fill=False)) for i, _radius in enumerate(radiuses): # if i in (i_pos1, i_pos2): # continue patches.append(plt.Circle(repl[i], _radius, color=color, fill=False)) for position in positions: patches.append(plt.Circle(position, radius, color='black', fill=False)) return patches collection = PatchCollection(get_shapes(init_radius), match_original=True) ax.add_collection(collection) def update(val=None): collection.set_paths(get_shapes(s_radius.val)) # collection.set_edgecolor(get_colors(len(positions) * (len(positions) - 1))) # collection.set_array(np.array(list(range(len(positions))))) fig.canvas.draw_idle() def new_positions(val=None): nonlocal positions, formation positions = random_shape(number) formation = regular_shape(number) scatter_positions.set_offsets(positions) # Set Axis Scale points = np.concatenate([positions, formation]) llim, hlim = points.min() - 1, points.max() + 1 ax.set_xlim(llim, hlim) ax.set_ylim(llim, hlim) ax.autoscale_view() update() def update_number(val=None): nonlocal number number = int(num_slider.val) new_positions() s_radius.on_changed(update) b_random.on_clicked(new_positions) num_slider.on_changed(update_number) ax.autoscale_view() plt.show()