def move_around_face(grid, vertices, visual_params): """ Move around the vertices of the given face in order, by continuously moving across darts connecting consecutive vertices. :param grid: Grid graph to compute MSSP :param vertices: face vertices given in order :return: All the shortest path distances for each vertex in the vertices list. """ # Ensure there is at least one vertex when computing SSSP for each vertex in vertices. assert (len(vertices) > 1) s1 = vertices[0] # first source vertex holy_tree = fast_initial_tree(grid, grid.genus, s1) print("---Initial tree---\n{}".format(holy_tree)) print(holy_tree.is_holy_tree(grid, "Root {}".format(s1))) print("----------------------") for i in range(len(vertices)): s1 = vertices[i] s2 = vertices[(i + 1) % len(vertices)] # Source will move from s1 -> s2, updating pred and dist dictionaries. move_across_dart(grid, s1, s2, holy_tree, visual_params) # For sanity check, at the end of the cycle, holy tree should be exactly same as the initial holy tree. initial_holy_tree = fast_initial_tree(grid, grid.genus, vertices[0]) assert initial_holy_tree == holy_tree, holy_tree.report_difference(initial_holy_tree)
def test_holy_tree(self): g1 = grid.g1() # Source vertex. vertex = g1.get_vertex((1, 1)) fast_holy_tree = initial_holy_tree.fast_initial_tree(g1, vertex) slow_holy_tree = initial_holy_tree.bellman_ford_initial_tree(g1, vertex) self.assertEqual(fast_holy_tree, slow_holy_tree)
def test_initial_tree_g2(self): # NOTE(lkhamsurenl): Following line is needed if copying graph is too deep, when using copy.deepcopy sys.setrecursionlimit(10000) grid2 = Grid(2, 6, 6) # Source vertex. vertex = grid2.get_vertex((1, 1)) fast_start = time.time() fast_holy_tree = initial_holy_tree.fast_initial_tree(grid2, vertex) fast_end = time.time() slow_holy_tree = initial_holy_tree.bellman_ford_initial_tree(grid2, vertex) slow_end = time.time() print("g = 2 \n fast: {}, slow: {}".format(fast_end - fast_start, slow_end - fast_end)) self.assertEqual(fast_holy_tree, slow_holy_tree)
def move_across_dart(grid, s1, s2, holy_tree, visual_params): """ Move across dart s1 -> s2, changing holy_tree through series of pivots. :param grid: :param holy_tree: Holy tree rooted at s1. :param s1: Source vertex. :param s2: Destination vertex. :param visual_params: (vertex_mapping, face_mapping, primal_pdf, dual_pdf). :return: """ # Original value of the edge s1 -> s2. dart = copy.deepcopy(s1.neighbors[s2]) # Distance from s to s1. lambda_weight = Weight(homology=[0 for _ in range(2 * grid.genus)]) s = grid.add_vertex((-1, -1)) # special vertex to walk along the s1 -> s2. holy_tree.dist[s] = Weight(homology=[0 for _ in range(2 * grid.genus)]) Dart(s, s1, Weight(0, [0 for _ in range(2 * grid.genus)], 0), dart.right, dart.left) Dart(s, s2, copy.deepcopy(dart.weight), dart.left, dart.right) # Remove edge between s1, s2. __remove_edge__(s1, s2) # Fix pred pointers. holy_tree.pred[s] = None holy_tree.pred[s1] = s holy_tree.pred[s2] = s # Set dist to s2. holy_tree.dist[s2] = s.neighbors[s2].weight # Reduce distance to both s1 and s2 form s by same value: Weight(0, -homology, -leafmost) Dart(s, s1, Weight(0, [-h for h in dart.weight.homology], -dart.weight.leafmost), dart.right, dart.left) holy_tree.add_subtree(s1, Weight(0, [-h for h in dart.weight.homology], -dart.weight.leafmost)) Dart(s, s2, Weight(1, [0 for _ in range(2 * grid.genus)], 0), dart.left, dart.right) holy_tree.add_subtree(s2, Weight(0, [-h for h in dart.weight.homology], -dart.weight.leafmost)) while True: # Get all the active darts. active = {} (blue, red) = __active_darts__(s1, s2, holy_tree.pred) for u in grid.vertices: for v in u.neighbors: if u.name in blue and v.name in red: active[u.neighbors[v]] = holy_tree.dist[u] + u.neighbors[v].weight - holy_tree.dist[v] # Do pivot on dart with minimum slack. minimum_slack = Weight(length=float('inf')) min_dart = None for d in active.keys(): if minimum_slack > active[d]: min_dart = d minimum_slack = active[d] # Check the value of the min_slack / 2 would not result in s "go over" s2. if min_dart is not None and Weight(float(minimum_slack.length) / 2, [float(i) / 2 for i in minimum_slack.homology], float(minimum_slack.leafmost) / 2) + lambda_weight <= \ Weight(1, [0 for _ in range(2 * grid.genus)], 0): # Get darts that are pivoting in and pivoting out. pivot_in = min_dart pivot_out = holy_tree.pivot_out(pivot_in) # Draw primal and dual graphs for visualization. draw_primal(grid, (s1.name,s2.name), blue, red, holy_tree.pred, visual_params[0], pivot_in, pivot_out, visual_params[2]) # In dual graph, dual of the reverse of the pivot_out will pivot in. draw_dual(grid, blue, red, holy_tree.pred, visual_params[1], pivot_out.reverse, pivot_in, visual_params[3]) # w represents the value to move s from s1 to s2. w = Weight(float(minimum_slack.length) / 2, [float(i) / 2 for i in minimum_slack.homology], float(minimum_slack.leafmost) / 2) lambda_weight += w # Keep track of the current progress. if holy_tree.pred[s1] == s: s.neighbors[s1].weight += w holy_tree.add_subtree(s1, w) if holy_tree.pred[s2] == s: s.neighbors[s2].weight -= w holy_tree.add_subtree(s2, -w) # Update dist and pred pointers respectively for the vertices. holy_tree.pred[min_dart.head] = min_dart.tail # here, if we check the values, it should still be the holy tree print("-------------------------------") print(holy_tree.is_holy_tree(grid, "Pivot: {}, slack: {}".format(min_dart, minimum_slack))) else: # no more pivot, move the values dart.weight - lambda_weight, then make the s2 new pivot draw_primal(grid, (s1.name,s2.name), blue, red, holy_tree.pred, visual_params[0], None, None, visual_params[2]) draw_dual(grid, blue, red, holy_tree.pred, visual_params[1], None, None, visual_params[3]) delta = Weight(1, [0 for _ in range(2 * grid.genus)], 0) - lambda_weight holy_tree.add_subtree(s2, -delta) print("When moved all the way to {0}, distance to {0}: {1}".format(s2, holy_tree.dist[s2])) holy_tree.add_subtree(s1, delta) print("When moved all the way to {0}, distance to {1}: {2}, dart: {3}".format(s2, s1, holy_tree.dist[s1], dart.weight)) break # Remove s. grid.remove_vertex(s.name) del holy_tree.pred[s] del holy_tree.dist[s] # Insert back the edge between s1 and s2. src.model.edge.Edge(s1, s2, copy.deepcopy(dart.weight), dart.left, dart.right) # s2 is the new root. holy_tree.pred[s2] = None holy_tree.pred[s1] = s2 # Ensure that there is no tense dart at the end of the root move. print(holy_tree.is_holy_tree(grid, "Root {}".format(s2))) # Compute correct holy tree rooted at s2, ensure it is equal to the current holy tree. correct_holy_tree = fast_initial_tree(grid, grid.genus, s2) assert correct_holy_tree == holy_tree, holy_tree.report_difference(correct_holy_tree) print("done with {0} -> {1}. New root is {1}".format(s1, s2))