def components(self): """ Returns a list of the connected components of the multicurve corresponding to the 1-cycle, each given as a OneCycle. Assumes for simplicity that the weights are at most one and the support of the cycle is a simple multicurve. """ assert all(abs(w) <= 1 for w in self.weights) D = self.cellulation G = Graph(multiedges=True) for edge in D.edges: if self.weights[edge.index] != 0: i, j = [v.index for v in edge.vertices] G.add_edge(i, j, edge.index) assert G.num_verts() == G.num_edges() ans = [] for H in G.connected_components_subgraphs(): weights = len(self.weights) * [0] for i in H.edge_labels(): weights[i] = self.weights[i] ans.append(OneCycle(self.cellulation, weights)) return ans
def check_orthogonal_diagonals(self, motion_types, active_NACs, extra_cycles_orthog_diag=[]): r""" Check the necessary conditions for orthogonal diagonals. TODO: return orthogonality_graph """ perp_by_NAC = [cycle for delta in active_NACs for cycle in self._orthogonal_diagonals[delta]] deltoids = [cycle for cycle, t in motion_types.items() if t in ['e','o']] orthogonalLines = [] for perpCycle in perp_by_NAC + deltoids + extra_cycles_orthog_diag: orthogonalLines.append(Set([Set([perpCycle[0],perpCycle[2]]), Set([perpCycle[1],perpCycle[3]])])) orthogonalityGraph = Graph(orthogonalLines, format='list_of_edges', multiedges=False) n_edges = -1 while n_edges != orthogonalityGraph.num_edges(): n_edges = orthogonalityGraph.num_edges() for perp_subgraph in orthogonalityGraph.connected_components_subgraphs(): isBipartite, partition = perp_subgraph.is_bipartite(certificate=True) if isBipartite: graph_0 = Graph([v.list() for v in partition if partition[v]==0]) graph_1 = Graph([v.list() for v in partition if partition[v]==1]) for comp_0 in graph_0.connected_components(): for comp_1 in graph_1.connected_components(): for e0 in Subsets(comp_0,2): for e1 in Subsets(comp_1,2): orthogonalityGraph.add_edge([Set(e0), Set(e1)]) else: raise exceptions.RuntimeError('A component of the orthogonality graph is not bipartite!') self._orthogonality_graph = orthogonalityGraph check_again = False H = {self._edge_ordered(u,v):None for u,v in self._graph.edges(labels=False)} self._set_same_lengths(H, motion_types) for c in motion_types: if not orthogonalityGraph.has_edge(Set([c[0],c[2]]),Set([c[1],c[3]])): continue if motion_types[c]=='a': # inconsistent since antiparallel motion cannot have orthogonal diagonals return False elif motion_types[c]=='p': # this cycle must be rhombus self._set_two_edge_same_lengths(H, c[0], c[1], c[2], c[3], 0) self._set_two_edge_same_lengths(H, c[0], c[1], c[1], c[2], 0) self._set_two_edge_same_lengths(H, c[0], c[1], c[0], c[3], 0) check_again = True for c in motion_types: if motion_types[c]=='g': labels = [H[self._edge_ordered(c[i-1],c[i])] for i in range(0,4)] if (not None in labels and ((len(Set(labels))==2 and labels.count(labels[0])==2) or len(Set(labels))==1)): return False if (orthogonalityGraph.has_edge(Set([c[0],c[2]]),Set([c[1],c[3]])) and True in [(H[self._edge_ordered(c[i-1], c[i])]==H[self._edge_ordered(c[i-2], c[i-1])] and H[self._edge_ordered(c[i-1],c[i])]!= None) for i in range(0,4)]): return False if check_again: for K23_edges in [Graph(self._graph).subgraph(k23_ver).edges(labels=False) for k23_ver in self._graph.induced_K23s()]: if MotionClassifier._same_edge_lengths(H, K23_edges): return False return True