def __init__(self, N, G_in=None, init_empty=False): G.__init__(self, N, G_in=G_in) self.hash_value = None if not init_empty: if G_in is None: G.new_vertex_property(self, "orientation", dtype="vector<double>") G.new_vertex_property(self, "position", dtype="vector<double>") G.new_vertex_property(self, "partner", dtype="long long") G.new_vertex_property(self, "selected", dtype="bool", value=False) G.new_vertex_property(self, "solved", dtype="bool", value=False) G.new_edge_property(self, "selected", dtype="bool", value=False) G.new_edge_property(self, "solved", dtype="bool", value=False) G.new_edge_property(self, "edge_cost", dtype="double", value=0.0) for v in G.get_vertex_iterator(self): self.set_partner(v, -1) # NOTE: Start/End dummy node and edge are implicit self.edge_index_map = G.get_edge_index_map(self)
def get_edge_combination_cost_curvature(self, comb_angle_factor, comb_angle_prior=0.0, return_edges_to_middle=False): edge_index_map = G.get_edge_index_map(self) """ Only collect the indices for each edge combination in the loop and perform cost calculation later in vectorized form. """ middle_indices = [] edges_to_middle = {} end_indices = [] edges = [] cost = [] prior_cost = {} edge_combination_cost = {} """ Problem: The indices are derived from the vertices in the graph. The graphs are filtered versions of a bigger graph where the vertices have not been enumerated newly. Thus we expect vertices to have random indices, not corresponding to the number of vertices in the sub graph. If we try to acces the position matrix with these indices we get out of bounds errors because the position matrix has only the entries of the filtered subgraph. We need to map vertex indices in the range [0, N_vertices_subgraph - 1] """ index_map = {} for n, v in enumerate(G.get_vertex_iterator(self)): incident_edges = G.get_incident_edges(self, v) index_map[v] = n for e1 in incident_edges: for e2 in incident_edges + [self.START_EDGE]: e1_id = self.get_edge_id(e1, edge_index_map) e2_id = self.get_edge_id(e2, edge_index_map) if e1_id >= e2_id and e2_id != self.START_EDGE.id(): continue if e2_id == self.START_EDGE.id(): """ Always append edges together with cost s.t. zip(edges, cost) is a correct mapping of edges to cost. """ prior_cost[(e1, e2)] = comb_angle_prior edges_to_middle[(e1, e2)] = int(v) else: """ Here we only save indices. How to secure a proper matching between cost that we calculate later and the corresponding edges? 1. Middle vertex is v -> index_map[v] in [0, N-1] 2. Append the middle_vertex twice to a list. 3. Append the distinct end vertices (2) to end vertices 4. Append the corresponding edges to a list. -> We end up with 3 lists of the following form: edges = [(e1, e2), (e3, e4), ...] m_ind = [ m1, m1 , m2, m2 , ...] e_ind = [ v1, v2 , v3, v4 , ...] p_arr = [ p(m1) , p(m2) , ...] index_map: m1 -> 0, m2 -> 1, m3 -> 2, ... --> p_arr[m1] = p(m1), p_arr[m2] = p(m2) """ middle_vertex = int(v) middle_indices.extend([middle_vertex, middle_vertex]) end_vertices = [ int(e1.source()), int(e1.target()), int(e2.source()), int(e2.target()) ] end_vertices.remove(middle_vertex) end_vertices.remove(middle_vertex) ordered_points = [None, None, None] ordered_points[0] = np.array( self.get_position(end_vertices[0])) ordered_points[2] = np.array( self.get_position(end_vertices[1])) ordered_points[1] = np.array( self.get_position(middle_vertex)) energy = get_energy_from_ordered_points(ordered_points, n_samples=1000) edge_combination_cost[(e1, e2)] = (energy * comb_angle_factor)**2 end_indices.extend(list(end_vertices)) edges.append((e1, e2)) edges_to_middle[(e1, e2)] = int(v) """ (e1, e2) -> end_indices, middle_indices """ edge_combination_cost.update(prior_cost) logger.info("edge_combination_cost: " + str(edge_combination_cost)) if return_edges_to_middle: return edge_combination_cost, edges_to_middle else: return edge_combination_cost
def get_edge_combination_cost_angle(self, comb_angle_factor, comb_angle_prior=0.0, return_edges_to_middle=False): edge_index_map = G.get_edge_index_map(self) """ Only collect the indices for each edge combination in the loop and perform cost calculation later in vectorized form. """ middle_indices = [] edges_to_middle = {} end_indices = [] edges = [] cost = [] prior_cost = {} """ Problem: The indices are derived from the vertices in the graph. The graphs are filtered versions of a bigger graph where the vertices have not been enumerated newly. Thus we expect vertices to have random indices, not corresponding to the number of vertices in the sub graph. If we try to acces the position matrix with these indices we get out of bounds errors because the position matrix has only the entries of the filtered subgraph. We need to map vertex indices in the range [0, N_vertices_subgraph - 1] """ index_map = {} for n, v in enumerate(G.get_vertex_iterator(self)): incident_edges = G.get_incident_edges(self, v) index_map[v] = n for e1 in incident_edges: for e2 in incident_edges + [self.START_EDGE]: e1_id = self.get_edge_id(e1, edge_index_map) e2_id = self.get_edge_id(e2, edge_index_map) if e1_id >= e2_id and e2_id != self.START_EDGE.id(): continue if e2_id == self.START_EDGE.id(): """ Always append edges together with cost s.t. zip(edges, cost) is a correct mapping of edges to cost. """ prior_cost[(e1, e2)] = comb_angle_prior edges_to_middle[(e1, e2)] = int(v) else: """ Here we only save indices. How to secure a proper matching between cost that we calculate later and the corresponding edges? 1. Middle vertex is v -> index_map[v] in [0, N-1] 2. Append the middle_vertex twice to a list. 3. Append the distinct end vertices (2) to end vertices 4. Append the corresponding edges to a list. -> We end up with 3 lists of the following form: edges = [(e1, e2), (e3, e4), ...] m_ind = [ m1, m1 , m2, m2 , ...] e_ind = [ v1, v2 , v3, v4 , ...] p_arr = [ p(m1) , p(m2) , ...] index_map: m1 -> 0, m2 -> 1, m3 -> 2, ... --> p_arr[m1] = p(m1), p_arr[m2] = p(m2) """ middle_vertex = int(v) middle_indices.extend([middle_vertex, middle_vertex]) end_vertices = set([ int(e1.source()), int(e1.target()), int(e2.source()), int(e2.target()) ]) end_vertices.remove(middle_vertex) end_indices.extend(list(end_vertices)) edges.append((e1, e2)) edges_to_middle[(e1, e2)] = int(v) """ (e1, e2) -> end_indices, middle_indices """ if middle_indices: pos_array = self.get_position_array() end_indices = np.array([index_map[v] for v in end_indices]) middle_indices = np.array([index_map[v] for v in middle_indices]) v = (pos_array[:, end_indices] - pos_array[:, middle_indices]).T norm = np.sum(np.abs(v)**2, axis=-1)**(1. / 2.) u = v / np.clip(norm[:, None], a_min=10**(-8), a_max=None) angles = np.arccos(np.clip(inner1d(u[::2], u[1::2]), -1.0, 1.0)) angles = np.pi - angles cost = cost + list((angles * comb_angle_factor)**2) edge_combination_cost = dict(itertools.izip(edges, cost)) edge_combination_cost.update(prior_cost) if return_edges_to_middle: return edge_combination_cost, edges_to_middle else: return edge_combination_cost