Esempio n. 1
0
def read_graph(filename: str) -> Graph:
    g_file = open(filename)

    first_line = g_file.readline()
    num_verts = int(first_line)

    g = Graph(num_verts)

    for line in g_file:
        u, v, w = map(int, line.split())
        g.add_edge(u, v, w)

    return g
Esempio n. 2
0
    def __init__(self, strataG):
        self.strataG = strataG
        self.sageG = Graph([list(range(1,
                                       strataG.num_vertices() + 1)), []],
                           multiedges=True,
                           loops=True)
        self.edge_label_to_edge = dict()
        self.vertex_to_marks = {
            v: []
            for v in range(1,
                           self.strataG.num_vertices() + 1)
        }
        self._has_marks = False

        for e in range(1, strataG.num_edges() + 1):
            edge_done = False
            if self.strataG.M[0, e] != 0:  #it is a half edge
                for v in range(1, strataG.num_vertices() + 1):
                    if self.strataG.M[v, e][0] == 1:
                        self.vertex_to_marks[v].append((e, self.strataG.M[0,
                                                                          e]))
                        edge_done = True
                        self._has_marks = True
                        break
            else:  #it is a whole edge

                vert_touching_e = []

                for v in range(1, strataG.num_vertices() + 1):
                    if strataG.M[v, e][0] == 2:
                        #add a loop
                        self.sageG.add_edge((v, v, e))
                        self.edge_label_to_edge[e] = (v, v, e)
                        edge_done = True
                        break
                    if strataG.M[v, e][0] == 1:
                        vert_touching_e.append(v)
                        if len(vert_touching_e) == 2:
                            break

            if edge_done:
                continue
            if len(vert_touching_e) == 2:
                self.sageG.add_edge(
                    (vert_touching_e[0], vert_touching_e[1], e))
                self.edge_label_to_edge[e] = (vert_touching_e[0],
                                              vert_touching_e[1], e)
            else:
                raise Exception("Unexpected here!")
Esempio n. 3
0
    def graph(self):
        """ Return a graphical representation of self.

        OUTPUT:

        G, vert_dict,

        where G is a graph object and vert_dict is a dictionary associating
        to a vertex of G the corresponding vertex of self.
        """

        G = Graph()
        G.add_vertex(0)
        vert_dict = {}
        create_graph_recursive(self, G, vert_dict, 0)
        return G, vert_dict
Esempio n. 4
0
def tree_to_graph(tree):
    """
	returns the corresponding cograph of the tree
	"""
    g = Graph()
    tree_to_graph_rec(tree, g)
    return g
    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
Esempio n. 6
0
 def sage_graph(self):
     sage_edges = [(e[0], e[1], {
         'weight': w,
         'sign': s,
         'index': i
     }) for (
         i, e), w, s in zip(enumerate(self.edges), self.weights, self.signs)
                   ]
     return Graph([list(range(self.nvertices)), sage_edges],
                  loops=True,
                  multiedges=True)
    def graph_with_same_edge_lengths(self, motion_types, plot=True):
        r"""
        Return a graph with edge labels corresponding to same edge lengths.

        INPUT:
        
        - `plot` -- if `True` (default), then plot of the graph is returned. 
        
        OUTPUT:
        
        The edge labels of the output graph are same for if the edge lengths
        are same due to `motion_types`. 
        """
        H = {self._edge_ordered(u,v):None for u,v in self._graph.edges(labels=False)}
        self._set_same_lengths(H, motion_types)
        G_labeled = Graph([[u,v,H[(u,v)]] for u,v in H])
        G_labeled._pos = self._graph._pos
        if plot:
            return G_labeled.plot(edge_labels=True, color_by_label=True)
        else:
            return G_labeled
Esempio n. 8
0
    def sage(self):
        from sage.all import Graph
        G = Graph(multiedges=True, loops=True)

        vertices = map(tuple, self.vertices())
        edges = map(tuple, self.edges())
        embedding = {}
        for vertex in vertices:
            vertex_order = []
            for label in vertex:
                for edge in edges:
                    if label in edge:
                        break
                G.add_edge(vertex, edge)
                vertex_order.append(edge)
            embedding[vertex] = vertex_order

        for edge in edges:
            edge_order = []
            for label in edge:
                for vertex in vertices:
                    if label in vertex:
                        break
                edge_order.append(vertex)
            embedding[edge] = edge_order

        G.set_embedding(embedding)
        return G
Esempio n. 9
0
    def __init__(self, strataG):
        #make the graph

        G = Graph()

        for v in range(1, strataG.num_vertices()):
            G.add_vertex(v)
            for expon, coef in strataG.M[v, 0].dict().items():
                if expon[0] == 1:
                    genus = coef
                else:
                    pass

        self.decorations = dict()

        dec_items = list(self.decorations.items())
        dec_items.sort(lambda x: x[1])

        parts = []
        prev = None
        dec_list = []

        for a in dec_items:
            if a != prev:
                dec_list.append(a[1])
                parts.append(new_part)
                new_part = [a[0]]
            else:
                new_part.append(a[0])

        self.dec_list = tuple(dec_list)

        self.graph, cert = graphUncan.canonical_labeling(parts).copy(
            immutable=True)

        self.parts = tuple(
            (tuple([cert[i] for i in part_j].sort) for part_j in parts))
Esempio n. 10
0
    def graph(self):
        r""" Return the weighted graph underlying this resolution graph.

        Output: An undirected, weighted Sage Graph.

        The vertices are labeled by the integers `0,\ldots,n-1`. The weight
        of an edge is the intersection number of the components corresponding
        to the vertices connected by the edge.

        """
        if not hasattr(self, "_graph"):
            M = copy(self._intersection_matrix)
            for i in self.components():
                M[i, i] = 0
            self._graph = Graph(M, format='weighted_adjacency_matrix')
        return self._graph
Esempio n. 11
0
    def labeled_graph(self):
        r""" Return the labeled graph underlying this resolution graph.

        OUTPUT: An undirected, weighted Sage Graph.

        The vertices are labeled by pairs `(i,-a_i)`, where `-a_i=E_i.E_i`
        is the self intersection number of the component `E_i`. The weight
        of an edge is the intersection number of the components corresponding
        to the vertices connected by the edge.

        """
        G = self.graph()
        a = [self.self_intersection(i) for i in self.components()]
        edges = G.edges()
        new_edges = []
        for i, j, w in edges:
            new_edges.append(((i, a[i]), (j, a[j]), w))
        return Graph(new_edges)
Esempio n. 12
0
    def is_NAC_coloring(self):
        r"""
        Return if the coloring is a NAC-coloring.

        The implementation uses Lemma 2.4 in [GLS2018]_.

        EXAMPLES::

            sage: from flexrilog import NACcoloring, GraphGenerator
            sage: G = GraphGenerator.SmallestFlexibleLamanGraph(); G
            SmallestFlexibleLamanGraph: FlexRiGraph with the vertices [0, 1, 2, 3, 4] and edges [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 4), (3, 4)]
            sage: delta = NACcoloring(G,[[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3)], [(2, 4), (3, 4)]], check=False)
            sage: delta.is_NAC_coloring()
            True

        NAC-coloring must be surjective::

            sage: delta = NACcoloring(G,[[], [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 4), (3, 4)]], check=False)
            sage: delta.is_NAC_coloring()
            False

        And it has to satisfy the cycle conditions::

            sage: delta = NACcoloring(G,[[(0, 1), (0, 2)], [(0, 3), (1, 2), (1, 3), (2, 4), (3, 4)]], check=False)
            sage: delta.is_NAC_coloring()
            False

        """
        self._check_edges()

        if len(self._red_edges) == 0 or len(self._blue_edges) == 0:
            return False
        for one_color_subgraph in [self.red_subgraph(), self.blue_subgraph()]:
            for component in one_color_subgraph.connected_components():
                if (len(
                        Graph(self._graph).subgraph(component).edges(
                            labels=False)) - len(
                                one_color_subgraph.subgraph(component).edges(
                                    labels=False))):
                    return False
        return True
Esempio n. 13
0
    def cycle_has_orthogonal_diagonals(self, cycle):
        r"""
        Return if the NAC-coloring implies orthogonal diagonals for a given 4-cycle.

        EXAMPLE::

            sage: from flexrilog import GraphGenerator
            sage: K33 = GraphGenerator.K33Graph()
            sage: [[delta.name(), [cycle for cycle in K33.four_cycles() if delta.cycle_has_orthogonal_diagonals(cycle)]] for delta in K33.NAC_colorings()]
            [['omega5', []],
             ['omega3', []],
             ['omega1', []],
             ['omega6', []],
             ['epsilon56', [(1, 2, 3, 4)]],
             ['epsilon36', [(1, 2, 5, 4)]],
             ['epsilon16', [(2, 3, 4, 5)]],
             ['omega4', []],
             ['epsilon45', [(1, 2, 3, 6)]],
             ['epsilon34', [(1, 2, 5, 6)]],
             ['epsilon14', [(2, 3, 6, 5)]],
             ['omega2', []],
             ['epsilon25', [(1, 4, 3, 6)]],
             ['epsilon23', [(1, 4, 5, 6)]],
             ['epsilon12', [(3, 4, 5, 6)]]]
        """
        if len(cycle) != 4:
            raise exceptions.ValueError('The cycle must be a 4-cycle.')
        if self.path_is_unicolor(list(cycle) + [cycle[0]]):
            if self.is_red(cycle[0], cycle[1]):
                subgraph = Graph([
                    self._graph.vertices(),
                    [list(e) for e in self.blue_edges()]
                ],
                                 format='vertices_and_edges')
            else:
                subgraph = Graph([
                    self._graph.vertices(),
                    [list(e) for e in self.red_edges()]
                ],
                                 format='vertices_and_edges')
            if subgraph.shortest_path(cycle[0],
                                      cycle[2]) and subgraph.shortest_path(
                                          cycle[1], cycle[3]):
                return True
            else:
                return False
        return False
Esempio n. 14
0
 def __init__(self, strataG):
     self.strataG = strataG
     self.sageG = Graph([range(1,strataG.num_vertices()+1),[]], multiedges=True, loops = True)
     self.edge_label_to_edge = dict()
     self.vertex_to_marks = {v:[] for v in range(1, self.strataG.num_vertices()+1)}
     self._has_marks = False
     
     for e in range(1, strataG.num_edges()+1):
         edge_done = False
         if self.strataG.M[0,e] != 0: #it is a half edge
             for v in range(1, strataG.num_vertices()+1):
                 if self.strataG.M[v,e][0] == 1:
                     self.vertex_to_marks[v].append((e,self.strataG.M[0,e]))
                     edge_done = True
                     self._has_marks = True
                     break
         else: #it is a whole edge           
                
             vert_touching_e = []
         
             for v in range(1, strataG.num_vertices()+1):
                 if strataG.M[v,e][0] == 2:
                     #add a loop
                     self.sageG.add_edge( (v,v,e) )
                     self.edge_label_to_edge[e] = (v,v,e)
                     edge_done = True
                     break
                 if strataG.M[v,e][0] == 1:
                     vert_touching_e.append(v)
                     if len(vert_touching_e) == 2:
                         break
                         
         if edge_done:
             continue
         if len(vert_touching_e) == 2:
             self.sageG.add_edge( (vert_touching_e[0], vert_touching_e[1],e) )
             self.edge_label_to_edge[e] = (vert_touching_e[0], vert_touching_e[1],e)
         else:
             raise Exception("Unexpected here!")
Esempio n. 15
0
 def CnSymmetricGridConstruction(cls, G, delta):
     def Cn_symmetric_k_points(n,k, alpha=Integer(1) ):   
         n = Integer(n)
         k = Integer(k) 
         if not mod(k,n) in [Integer(0) ,Integer(1) ]:
             raise ValueError('Only possible if k mod n in {{0,1}}, here {} mod {} = {}.'.format(k,n,mod(k,n)))
         res = {
                 i : vector([RR(cos(RR(Integer(2) *pi*i)/n)),RR(sin(RR(Integer(2) *pi*i)/n))]) for i in range(Integer(0) ,n)
             }
         N = k
         if mod(k,n)==Integer(1) :
             res[N-Integer(1) ] = vector([Integer(0) ,Integer(0) ])
             N = N-Integer(1) 
         for i in range(n,N):
             r = (i-i%n)/n +Integer(1) 
             res[i] = r*res[i%n]
         for i in res:
             res[i] = alpha*vector([res[i][Integer(0) ], res[i][Integer(1) ]])
         return [res[i] for i in sorted(res.keys())]
 
     n = delta.n
     a = Cn_symmetric_k_points(n, len(delta._noninvariant_components['red']))
     a += [vector([Integer(0) ,Integer(0) ]) for _ in range(len(delta._partially_invariant_components['red']))]
     b = Cn_symmetric_k_points(n, len(delta._noninvariant_components['blue']))
     b += [vector([Integer(0) ,Integer(0) ]) for _ in range(len(delta._partially_invariant_components['blue']))]
     ab = [b, a]
     M = GraphMotion.GridConstruction(G, delta,
          check=False, zigzag=ab,
          red_components_ordered=delta._noninvariant_components['red']+delta._partially_invariant_components['red'],
          blue_components_ordered=delta._noninvariant_components['blue']+delta._partially_invariant_components['blue'])
 
     for comp in delta._partially_invariant_components['red']+delta._partially_invariant_components['blue']:
         if len(comp)>Integer(1) :
             M.fix_edge(Graph(G).subgraph(comp).edges(labels=False)[Integer(0) ])
             break
     return M
Esempio n. 16
0
    def __init__(self, edges, loops, kappa):
        '''
        Construct a Labeled Stable Graph -- the canonical representative of the labeled stable graph given by edges, loops and           kappa, where:

        - ``edges``  -- tuple of triples, where a triple (v1,v2,m) means that the vertices v1 and v2 are connected by m edges
        - ``loops``  -- tuple, where an integer loops[i] is the number of loops associated to the vertex i
        - ``kappa``  -- tuple of tuples, a partition of stratum into subpartitions, where kappa[i] is a subpartition of orders of zeroes associated to the vertex i
        
        Lists can be used instead of tuples, as they will be automatically converted to be immutable.
        '''
        if not edges:
            graph = Graph(weighted=True, loops=False, multiedges=False)
            graph.add_vertex()
        else:
            graph = Graph(list(edges),
                          loops=False,
                          multiedges=False,
                          weighted=True)
        self.edges, self.loops, self.kappa, self.graph = canonical(
            graph.edges(), loops, kappa, graph)
        self.genera = [(sum(self.kappa[v]) - 2 * self.vertex_deg(v) -
                        4 * self.loops[v] + 4) / ZZ(4)
                       for v in self.graph.vertices()]
Esempio n. 17
0
class StrataWithSageGraph(object):
    def __init__(self, strataG):
        self.strataG = strataG
        self.sageG = Graph([list(range(1,
                                       strataG.num_vertices() + 1)), []],
                           multiedges=True,
                           loops=True)
        self.edge_label_to_edge = dict()
        self.vertex_to_marks = {
            v: []
            for v in range(1,
                           self.strataG.num_vertices() + 1)
        }
        self._has_marks = False

        for e in range(1, strataG.num_edges() + 1):
            edge_done = False
            if self.strataG.M[0, e] != 0:  #it is a half edge
                for v in range(1, strataG.num_vertices() + 1):
                    if self.strataG.M[v, e][0] == 1:
                        self.vertex_to_marks[v].append((e, self.strataG.M[0,
                                                                          e]))
                        edge_done = True
                        self._has_marks = True
                        break
            else:  #it is a whole edge

                vert_touching_e = []

                for v in range(1, strataG.num_vertices() + 1):
                    if strataG.M[v, e][0] == 2:
                        #add a loop
                        self.sageG.add_edge((v, v, e))
                        self.edge_label_to_edge[e] = (v, v, e)
                        edge_done = True
                        break
                    if strataG.M[v, e][0] == 1:
                        vert_touching_e.append(v)
                        if len(vert_touching_e) == 2:
                            break

            if edge_done:
                continue
            if len(vert_touching_e) == 2:
                self.sageG.add_edge(
                    (vert_touching_e[0], vert_touching_e[1], e))
                self.edge_label_to_edge[e] = (vert_touching_e[0],
                                              vert_touching_e[1], e)
            else:
                raise Exception("Unexpected here!")

    def has_marks(self):
        return self._has_marks

    def marks_on_v(self, v):
        return self.vertex_to_marks[v]

    def edges_incident(self, v):
        for v1, v2, e in self.sageG.edges_incident(v):
            yield e

    def edges_labels_between_vertex_sets(self, vs1, vs2):
        #problem here when overlap........
        result = []
        for v1, v2, e in self.sageG.edges():
            if v1 in vs1 and v2 in vs2:
                result.append(e)
            elif v1 in vs2 and v2 in vs1:
                result.append(e)
        return result

        #some probably garbage...
        #v1sedges = set()
        #v2sedges = set()
        #for v1 in vs1:
        #    for e in self.edges_incident(v1):
        #        v1sedges.add(e)
        #for v2 in vs2:
        #    for e in self.edges_incident(v2):
        #        v2sedges.add(e)

        #return v1sedges.intersection(v2sedges)

    def edges(self):
        """
        Returns a list of triples!
        """
        return self.sageG.edges()

    def vertices(self):
        return self.sageG.vertices()

    def num_vertices(self):
        return self.strataG.num_vertices()

    def v_genus(self, v):
        """
        Returns the genus of the vertex v.
        """
        return self.strataG.M[v, 0][0]

    def subgraph(self, vertices, edge_labels):
        #print self.edge_label_to_edge
        #print self.sageG.edges()
        return self.sageG.subgraph(
            vertices, [self.edge_label_to_edge[l] for l in edge_labels])

    def edge_is_incident(self, e, v):
        #print "is_inc", e,v
        #print self.strataG
        #print
        return self.strataG.M[v, e][0] > 0

    def is_loop(self, e):
        v1, v2, ep = self.edge_label_to_edge[e]
        return v1 == v2
        1: [3, 4, 5],
        2: [1],
        3: [2, 4, 5],
        4: [2],
        5: [4, 2],
        6: [7, 8, 9, 10],
        7: [8, 9, 10],
        8: [9, 10],
        10: [11, 12, 13, 14],
        11: [9, 10, 14],
        12: [9, 10, 11, 13],
        13: [9, 10, 11, 12],
        14: [9, 10, 11]
    }
    G = DiGraph(d)
    Gs = Graph()
    Gd = Graph()
    H = Graph()
    find_sym_struct(G, Gs, Gd, H)
    TGs = modular_decomposition(Gs)
    TGd = modular_decomposition(Gd)
    Th = modular_decomposition(H)
    print TGs
    print TGd
    print Th
    # modular decomposition of Gs, Gd
    # factorizing permutation of the graph G is 1,...,14
    nodes = range(1, 15)
    parenthesized_fact_perm(nodes, G)
    print(" ")
    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
Esempio n. 20
0
    def height_function(self, vertex_edge_collisions, extra_layers=0, edge_edge_collisions=[]):
        r"""
        Return a height function of edges if possible for given vertex-edge collisions.

        WARNING:
        
        Costly, since it runs through all edge-colorings.
        """
        def e2s(e):
            return Set(e)
        for v in vertex_edge_collisions:
            vertex_edge_collisions[v] = Set([e2s(e) for e in vertex_edge_collisions[v]])
        collision_graph = Graph([[e2s(e) for e in self._graph.edges(labels=False)],[]],format='vertices_and_edges')
        for u in self._graph.vertices():
            collision_graph.add_edges([[e2s([u,v]),e2s([u,w]),''] for v,w in Subsets(self._graph.neighbors(u),2)])
        for e in collision_graph.vertices():
            for v in vertex_edge_collisions:
                if v in e:
                    for f in vertex_edge_collisions[v]:
                        collision_graph.add_edge([e2s(f), e2s(e), 'col'])
        for e, f in edge_edge_collisions:
            collision_graph.add_edge([e2s(f), e2s(e), 'e-e_col'])
        from sage.graphs.graph_coloring import all_graph_colorings
        optimal = False
        chrom_number = collision_graph.chromatic_number()
        for j in range(0, extra_layers + 1):
            i = 1
            res = []
            num_layers = chrom_number + j
            min_s = len(self._graph.vertices())*num_layers
            for col in all_graph_colorings(collision_graph,num_layers):
                if len(Set(col.keys()))<num_layers:
                    continue
                layers = {}
                for h in col:
                    layers[h] = [u for e in col[h] for u in e]
                col_free = True
                A = []
                for v in vertex_edge_collisions:
                    A_min_v = min([h for h in layers if v in layers[h]])
                    A_max_v = max([h for h in layers if v in layers[h]])
                    A.append([A_min_v, A_max_v])
                    for h in range(A_min_v+1,A_max_v):
                        if v not in layers[h]:
                            if len(Set(col[h]).intersection(vertex_edge_collisions[v]))>0:
                                col_free = False
                                break
                    if not col_free:
                        break
                if col_free:
                    s = 0
                    for v in self._graph.vertices():
                        A_min_v = min([h for h in layers if v in layers[h]])
                        A_max_v = max([h for h in layers if v in layers[h]])
                        s += A_max_v - A_min_v
                    if s<min_s:
                        min_s = s
                        res.append((col, s, A))
                        i += 1
                        if s==2*len(self._graph.edges())-len(self._graph.vertices()):
                            optimal = True
                            break
            if optimal:
                break
        if not res:
            return None
        vertex_coloring = min(res, key = lambda t: t[1])[0]
        h = {}
        for layer in  vertex_coloring:
            for e in vertex_coloring[layer]:
                h[e] = layer
        return h
Esempio n. 21
0
def zeta_function(type,
                  L,
                  objects=None,
                  optimise_basis=False,
                  ncpus=None,
                  alt_ncpus=None,
                  strategy=None,
                  profile=None,
                  verbose=False,
                  optlevel=None,
                  addmany_dispatcher=None,
                  mode=None,
                  debug=None,
                  **kwargs):

    if type not in ['p-adic', 'topological']:
        raise ValueError('Unknown type of zeta function')

    if type == 'p-adic':
        if common.count is None:
            raise RuntimeError(
                'LattE/count is required in order to compute p-adic zeta functions'
            )
        elif __SERIES_BUG:
            raise RuntimeError(
                'power series expansions in this version of Sage cannot be trusted'
            )

    # Multiprocessing.
    if ncpus is None:
        ncpus = Infinity
    from multiprocessing import cpu_count
    common.ncpus = min(ncpus, cpu_count())

    if alt_ncpus is None:
        alt_ncpus = common.ncpus
    common._alt_ncpus = alt_ncpus

    if addmany_dispatcher is None:
        addmany_dispatcher = 'numerator'
    common.addmany_dispatcher = addmany_dispatcher

    common.debug = False if debug is None else debug

    if optlevel is None:
        optlevel = 1
    common.optimisation_level = optlevel

    # Reduction strategies.
    if strategy is None:
        strategy = Strategy.NORMAL

    # Memory profiles.
    if profile is None:
        profile = Profile.NORMAL
    if profile not in [Profile.SAVE_MEMORY, Profile.NORMAL, Profile.SPEED]:
        raise ValueError('Invalid profile')
    if profile == Profile.SAVE_MEMORY:
        common.save_memory = True
        common.plumber = True
    elif profile == Profile.NORMAL:
        common.save_memory = False
        common.plumber = True
    elif profile == Profile.SPEED:
        common.save_memory = False
        common.plumber = False

    if verbose:
        from logging import INFO, DEBUG
        loglevels = [
            (logger, INFO),
            (smurf.logger, INFO),
            (surf.logger, INFO),
            (torus.logger, INFO),
            (abstract.logger, DEBUG),
            (cycrat.logger, INFO),
            (triangulate.logger, INFO),
            (reps.logger, INFO),
            (subobjects.logger, INFO),
            (ask.logger, INFO),
            (cico.logger, DEBUG),
            (addmany.logger, INFO),
        ]
        oldlevels = []

        for m, level in loglevels:
            old = m.getEffectiveLevel()
            oldlevels.append(old)
            m.setLevel(min(old, level))

    if util.is_graph(L):
        if L.has_multiple_edges():
            raise ValueError('parallel edges not supported')

    if (util.is_matrix(L) or
            util.is_graph(L)) and objects not in ['ask', 'cico', 'adj', 'inc']:
        raise ValueError('invalid objects specified for given input')

    elif util.is_polynomial(L):
        # Turn a polynomial into a list of polynomials.
        L = [L]
    elif util.is_string(L):
        L = lookup(L)

    if objects in ['poly', 'igusa']:
        proc = IgusaProcessor(*L)
    elif objects in ['subalgebras', 'ideals']:
        proc = SubobjectZetaProcessor(L, objects, strategy=strategy)
    elif objects == 'reps':
        proc = RepresentationProcessor(L)
    elif objects == 'ask':
        if util.is_graph(L):
            signs = kwargs.get('signs', -1)
            if signs not in [+1, -1]:
                raise ValueError('invalid signs')
            proc = AskProcessor(
                util.graph_to_generic_matrix(
                    L, 'antisymmetric' if signs == -1 else 'symmetric'))
        else:
            proc = AskProcessor(L, mode=mode)
    elif objects == 'cico':
        proc = CicoProcessor(L, **kwargs)
    elif objects == 'adj':
        if not util.is_graph(L) and util.is_matrix(L):
            try:
                L = Graph(L)
            except:
                raise ValueError(
                    'input is not a graph or an adjacency matrix of a graph')
        proc = CicoProcessor(L, **kwargs)
    elif objects == 'inc':
        try:
            n = int(L)
            mu = kwargs.get('mu', {})
            A = cico.incidence_matrix_from_multiplicities(n, mu)
        except:
            A = Matrix(L)

        proc = IncidenceProcessor(A)
    elif objects == 'orbits':
        # NOTE: we don't currently check if L really spans a matrix Lie algebra
        proc = AskProcessor(util.matlist_to_mat(
            util.basis_of_matrix_algebra(L, product='Lie')),
                            mode=mode)
    elif objects == 'cc':
        if not L.is_Lie() and not L.is_nilpotent():
            logger.warning('not a nilpotent Lie algebra')
            # raise ValueError('need a nilpotent Lie algebra in order to enumerate conjugacy classes')
        proc = AskProcessor(util.matlist_to_mat(L._adjoint_representation()),
                            mode=mode)
    else:
        raise ValueError('unknown objects [%s]' % objects)

    if optimise_basis:
        logger.info('Searching for a good basis...')
        proc.optimise()
        logger.info('Picked a basis.')

    if verbose:
        print(proc)

    try:
        if type == 'p-adic':
            return proc.padically_evaluate(shuffle=True)
        elif type == 'topological':
            return proc.topologically_evaluate(shuffle=True)
    finally:
        if verbose:
            for ((m, _), level) in zip(loglevels, oldlevels):
                m.setLevel(level)
Esempio n. 22
0
    def Q1Graph(old_labeling=False):
        r"""
        Return the graph $Q_1$.

        EXAMPLE::

            sage: from flexrilog import GraphGenerator
            sage: GraphGenerator.Q1Graph()
            Q_1: FlexRiGraph with 7 vertices and 11 edges

        .. PLOT::
            :scale: 70

            from flexrilog import GraphGenerator
            G = GraphGenerator.Q1Graph()
            sphinx_plot(G)
        """
        if old_labeling:
            return FlexRiGraph(
                [(0, 1), (0, 2), (0, 6), (1, 2), (1, 4), (1, 5), (2, 3),
                 (3, 4), (3, 5), (4, 6), (5, 6)],
                pos={
                    5: (0.500, 0.866),
                    4: (-0.500, 0.866),
                    6: (-1.00, 0.000),
                    3: (1.00, 0.000),
                    2: (0.500, -0.866),
                    0: (-0.500, -0.866),
                    1: (0.000, 0.000)
                },
                name='Q_1')
        G = FlexRiGraph(
            [[5, 6], [5, 7], [6, 7], [1, 5], [2, 6], [2, 4], [1, 3], [3, 7],
             [4, 7], [1, 4], [2, 3]],
            pos={
                4: (0.500, 0.866),
                3: (-0.500, 0.866),
                1: (-1.00, 0.000),
                2: (1.00, 0.000),
                6: (0.500, -0.866),
                5: (-0.500, -0.866),
                7: (0.000, 0.000)
            },
            name='Q_1')
        for cls in G.NAC_colorings_isomorphism_classes():
            if len(cls) == 1:
                delta = cls[0]
                if len(delta.blue_edges()) in [4, 7]:
                    delta.set_name('eta')
                else:
                    delta.set_name('zeta')
            else:
                for delta in cls:
                    for edges in [delta.red_edges(), delta.blue_edges()]:
                        if len(cls) == 4 and len(edges) == 7:
                            u, v = [
                                comp
                                for comp in Graph([list(e) for e in edges
                                                   ]).connected_components()
                                if len(comp) == 2
                            ][0]
                            delta.set_name('epsilon' + (
                                str(u) + str(v) if u < v else str(v) + str(u)))
                            break
                        if len(edges) == 3:
                            vertex = edges[0].intersection(
                                edges[1]).intersection(edges[2])[0]
                            name = 'phi' if [
                                w for w in G.neighbors(vertex)
                                if G.degree(w) == 4
                            ] else 'psi'
                            delta.set_name(name + str(vertex))
                            break
                        if len(edges) == 5:
                            u, v = [
                                comp
                                for comp in Graph([list(e) for e in edges
                                                   ]).connected_components()
                                if len(comp) == 2
                            ][0]
                            delta.set_name('gamma' + str(min(u, v)))
                            break
        return G
Esempio n. 23
0
 def runTest(self):
     g = Graph(multiedges=True, loops=True)
     g.add_edge(1, 1)
     p = PebbleGame(g.vertices(), 2, 2)
     self.assertFalse(p.run(g))
Esempio n. 24
0
 def XXXrunTest(self):
     g = Graph()
     g.add_edges([(1, 3), (5, 6), (3, 5), (1, 6), (1, 5), (3, 6)])
     l = OrientedRotationSystem.from_graph(g)
     self.assertItemsEqual(l[0].vertices(), [1, 3, 5, 6])
Esempio n. 25
0
    def __init__(self, p_list):
        
        # punc => +-1 ~ +- inf
        # pant_name => idx

        try:
            preparser(False)
        except:
            raise ValueError('Sage preparser issue')

        num_pants = len(p_list)
        punc_map = {}
        edge_ls = []
        #gluing_cnt = 0
        gluing_set = set()
        non_ori_punc_set = set()


        for i in range(len(p_list)):
            pant = p_list[i]
            if len(pant) != 3:
                raise ValueError('One pant should have three punctures')
            for punc in pant:
                if punc == 0:
                    raise ValueError('Punctures should be named as non-zero integer')
                punc_key = abs(punc)
                if punc in punc_map.keys() and punc_map[punc][0]:
                    weight = 1
                    non_ori_punc_set.add(punc)
                else:
                    weight = 0
                if punc_key in punc_map.keys():
                    if punc_map[punc_key][1] != None and punc_map[punc_key][0] != None:
                        raise ValueError("Each puncture can only be glued once")
                    #gluing_cnt += 1
                    gluing_set.add(punc_key)
                    if punc < 0:
                        punc_map[punc_key][1] = i
                    else:
                        punc_map[punc_key][0] = i
                    edge_ls.append((punc_map[punc_key][0], punc_map[punc_key][1], weight))
                    gluing_set.add(punc_key)
                else:
                    if punc < 0:
                        punc_map[punc_key] = [None, i]
                    else:
                        punc_map[punc_key] = [i, None]

        # check for connectedness
        #print edge_ls
        g = Graph(edge_ls)

        print g

        if not g.is_connected():
            raise ValueError('Invalid input. Surface should be connect')

        # orientation
        orientable = True ### DEBUG
        #orientable = PantsDecomposition._is_orientable(g) ### DEBUG

        euler_char = -1*num_pants 
        num_puncture = num_pants*3 - 2*len(gluing_set)
        super(PantsDecomposition,self).__init__(euler_char = euler_char, num_punctures = num_puncture, is_orientable = orientable)
        #print self.__repr__()
        self._p_list = p_list
        self._p_map = punc_map
        self._gluing_set = gluing_set
        self._non_ori_punc_set = non_ori_punc_set
    def consistent_motion_types(self):#, cycles=[]):
        r"""
        Return the list of motion types consistent with 4-cycles.
        """
#         if cycles==[]:
        cycles = self.four_cycles_ordered()

        k23s = [Graph(self._graph).subgraph(k23_ver).edges(labels=False) for k23_ver in self._graph.induced_K23s()]

        aa_pp = [('a', 'a'), ('p', 'p')]
        ao = [('a','o'), ('o','a')]
        ae = [('a','e'), ('e','a')]
        oe = [('o', 'e'), ('e', 'o')]
        oo_ee = [('e','e'), ('o','o')]

        H = {self._edge_ordered(u,v):None for u,v in self._graph.edges(labels=False)}
        types_prev=[[{}, []]]
        
        self._num_tested_combinations = 0

        for i, new_cycle in enumerate(cycles):
            types_ext = []
            new_cycle_neighbors = [[c2,
                                    new_cycle.index(self._four_cycle_graph.edge_label(new_cycle, c2)),
                                    c2.index(self._four_cycle_graph.edge_label(new_cycle, c2)),
                                   ] for c2 in self._four_cycle_graph.neighbors(new_cycle) if c2 in cycles[:i]]
            for types_original, ramification_eqs_prev in types_prev:
                for type_new_cycle in ['g','a','p','o','e']:
                    self._num_tested_combinations +=1
                    types = deepcopy(types_original)
                    types[tuple(new_cycle)] = type_new_cycle
    #                 H = deepcopy(orig_graph)
                    inconsistent = False

                    for c2, new_index, c2_index in new_cycle_neighbors:
                        type_pair = (types[new_cycle], types[c2])
                        if (type_pair in aa_pp
                                or (type_pair in oe and new_index%2 == c2_index%2)
                                or (type_pair in oo_ee and new_index%2 != c2_index%2)):
                            inconsistent = True
                            break
                        if type_pair in ao:
                            ind_o = type_pair.index('o')
                            if [new_index, c2_index][ind_o] % 2 == 1:
                            # odd deltoid (1,2,3,4) is consistent with 'a' if the common vertex is odd,
                            # but Python lists are indexed from 0
                                inconsistent = True
                                break
                        if type_pair in ae:
                            ind_e = type_pair.index('e')
                            if [new_index, c2_index][ind_e] % 2 == 0:
                                inconsistent = True
                                break
                    if inconsistent:
                        continue

                    self._set_same_lengths(H, types)
                    for c in types:
                        if 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)):
                                inconsistent = True
                                break
                    if inconsistent:
                        continue
                    for K23_edges in k23s:
                        if MotionClassifier._same_edge_lengths(H, K23_edges):
                            inconsistent = True
                            break
                    if inconsistent:
                        continue

                    ramification_eqs = ramification_eqs_prev + self.ramification_formula(new_cycle, type_new_cycle)
                    zero_variables, ramification_eqs = self.consequences_of_nonnegative_solution_assumption(ramification_eqs)
                    for cycle in types:
                        if inconsistent:
                            break
                        for t in self.motion_types2NAC_types(types[cycle]):
                            has_necessary_NAC_type = False
                            for delta in self._restriction_NAC_types[cycle][t]:
                                if not self.mu(delta) in zero_variables:
                                    has_necessary_NAC_type = True
                                    break
                            if not has_necessary_NAC_type:
                                inconsistent = True
                                break
                    if inconsistent:
                        continue

                    types_ext.append([types, ramification_eqs])

            types_prev=types_ext

        return [t for t, _ in types_prev]
Esempio n. 27
0
    Zqhat_recurse(G, q, FrozenBitset([], capacity=n),
                  FrozenBitset([], capacity=n), BEST_LOWER_BOUND=BEST_LOWER_BOUND, BEST_LOOPS=BEST_LOOPS, CACHE=set(), G_info=G_info)
    if return_loops:
        return BEST_LOWER_BOUND[0], BEST_LOOPS
    else:
        return BEST_LOWER_BOUND[0]

def Zq_compute(G,q):
    return Zq_bitset(G,q,push_zeros=push_zeros)

def Zplus(G):
   return Zq_compute(G,0)

from sage.all import Graph, graphs
G=Graph()
G.add_edges([[1,2],[2,3],[3,4],[4,5],[5,6],[6,1],[1,4],[2,5],[3,6],[7,1],[7,2],[7,3]])

G2=graphs.CompleteGraph(4)
G2.subdivide_edges(G2.edges(),1)


def check_trees(start,end):
    for i in range(start,end):
        print "working on %s vertices"%i
        list(check_tree(list(graphs.trees(i))))

@parallel            
def check_tree(g):
    if not inertia_set(g,f)==Zq_inertia_lower_bound(g):
        if not inertia_set(g,f)==Zq_inertia_lower_bound(g, zero_forcing_function=Zqhat):
Esempio n. 28
0
 def edge_graph(self):
     G = Graph()
     G.add_edges([[v.index for v in e.vertices] for e in self.edges])
     return G
class MotionClassifier(SageObject):
    r"""
    This class implements the functionality for determining possible motions of a graph.
    """
    def __init__(self, graph, four_cycles=[], separator='', edges_ordered=[]):
        if not (isinstance(graph, FlexRiGraph) or 'FlexRiGraph' in str(type(graph))):
            raise exceptions.TypeError('The graph must be of the type FlexRiGraph.')
        self._graph = graph

        if four_cycles == []:
            self._four_cycles = self._graph.four_cycles(only_with_NAC=True) 
        else:
            self._four_cycles = four_cycles

        if not self._graph.are_NAC_colorings_named():
            self._graph.set_NAC_colorings_names()

#        -----Polynomial Ring for leading coefficients-----
        ws = []
        zs = []
        lambdas = []
        ws_latex = []
        zs_latex = []
        lambdas_latex = []
        
        if edges_ordered==[]:
            edges_ordered = self._graph.edges(labels=False)
        else:
            if (Set([self._edge2str(e) for e in edges_ordered]) !=
                Set([self._edge2str(e) for e in self._graph.edges(labels=False)])):
                raise ValueError('The provided ordered edges do not match the edges of the graph.')

        for e in edges_ordered:
            ws.append('w' + self._edge2str(e))
            zs.append('z' + self._edge2str(e))
            lambdas.append('lambda' + self._edge2str(e))
            ws_latex.append('w_{' + self._edge2str(e).replace('_', separator) + '}')
            zs_latex.append('z_{' + self._edge2str(e).replace('_', separator) + '}')
            lambdas_latex.append('\\lambda_{' + self._edge2str(e).replace('_', separator) + '}')

        self._ringLC = PolynomialRing(QQ, names=lambdas+ws+zs) #, order='lex')
        self._ringLC._latex_names = lambdas_latex + ws_latex + zs_latex
        self._ringLC_gens = self._ringLC.gens_dict()

        self._ring_lambdas = PolynomialRing(QQ, names=lambdas + ['u'])
        self._ring_lambdas._latex_names = lambdas_latex + ['u']
        self._ring_lambdas_gens = self._ring_lambdas.gens_dict()
        self.aux_var = self._ring_lambdas_gens['u']
        
        xs = []
        ys = []
        xs_latex = []
        ys_latex = []
        for v in self._graph.vertices():
            xs.append('x' + str(v))
            ys.append('y' + str(v))
            xs_latex.append('x_{' + str(v) + '}')
            ys_latex.append('y_{' + str(v) + '}')
            
        self._ring_coordinates = PolynomialRing(QQ, names=lambdas+xs+ys)
        self._ring_coordinates._latex_names = lambdas_latex + xs_latex + ys_latex
        self._ring_coordinates_gens = self._ring_coordinates.gens_dict()
        
        
#        ----Ramification-----
#         if len(self._graph.NAC_colorings()) > 1: 
        self._ring_ramification = PolynomialRing(QQ,
                                                 [col.name() for col in self._graph.NAC_colorings()],
                                                 len(self._graph.NAC_colorings()))
#         else:
#             self._ring_ramification = PolynomialRing(QQ, self._graph.NAC_colorings()[0].name())
        self._ring_ramification_gens = self._ring_ramification.gens_dict()
        self._restriction_NAC_types = self.NAC_coloring_restrictions()

#        -----Graph of 4-cycles-----
        self._four_cycle_graph = Graph([self._four_cycles,[]], format='vertices_and_edges')

        for c1, c2 in Subsets(self._four_cycle_graph.vertices(), 2):
            intersection = self.cycle_edges(c1, sets=True).intersection(self.cycle_edges(c2, sets=True))
            if len(intersection)>=2 and len(intersection[0].intersection(intersection[1]))==1:
                common_vert = intersection[0].intersection(intersection[1])[0]
                self._four_cycle_graph.add_edge(c1, c2, common_vert)

#        -----Cycle with orthogonal diagonals due to NAC-----
        self._orthogonal_diagonals = {
                delta.name(): [cycle for cycle in self._four_cycle_graph if delta.cycle_has_orthogonal_diagonals(cycle)]
                for delta in self._graph.NAC_colorings()}

    @doc_index("Constraints on edge lengths")
    def four_cycles_ordered(self):
        r"""
        Heuristic order of 4-cycles.
        """
        cliques = self._four_cycle_graph.cliques_maximal()
        cycles = max(cliques,
                     key=lambda clique: sum([self._four_cycle_graph.degree(v) for v in clique]))
        missing_cliques = {tuple(clique):0 for clique in cliques}
        missing_cliques.pop(tuple(cycles))
        while missing_cliques:
            next_clique = max(missing_cliques.keys(),
                             key=lambda clique:sum([1 for c in clique for c2 in self._four_cycle_graph.neighbors(c) if c2 in cycles]))
            missing_cliques.pop(next_clique)
            missing_cycles = {c:0 for c in next_clique if not c in cycles}
            while missing_cycles:
                next_cycle = max(missing_cycles.keys(),
                                key=lambda c:sum([1 for c2 in self._four_cycle_graph.neighbors(c) if c2 in cycles]))
                cycles.append(next_cycle)
                missing_cycles.pop(next_cycle)

        missing_cycles = {c:0 for c in self._four_cycle_graph.vertices() if not c in cycles}
        while missing_cycles:
            next_cycle = max(missing_cycles.keys(),
                            key=lambda c:sum([1 for c2 in self._four_cycle_graph.neighbors(c) if c2 in cycles]))
            cycles.append(next_cycle)
            missing_cycles.pop(next_cycle)
        return cycles

    def _repr_(self):
        return 'Motion Classifier of ' + str(self._graph)

    @staticmethod
    def _edge2str(e):
        if e[0]<e[1]:
            return str(e[0]) + '_' + str(e[1])
        else:
            return str(e[1]) + '_' + str(e[0])

    
    @staticmethod
    @doc_index("Other")
    def cycle_edges(cycle, sets=False):
        r"""
        Return edges of a 4-cycle.
        """
        if sets:
            return Set([Set(list(e)) for e in zip(cycle, list(cycle[1:])+[cycle[0]])])
        else:
            return [list(e) for e in zip(cycle, list(cycle[1:])+[cycle[0]])]

    @staticmethod
    @doc_index("Other")
    def four_cycle_normal_form(cycle, motion_type):
        r"""
        Return a 4-cycle with a motion type in the normal form.
        """
        i = cycle.index(min(cycle))
        oe =  ['o', 'e']
        if i % 2 == 1 and motion_type in oe:
            motion_type = oe[1 - oe.index(motion_type)]
        tmp_c = cycle[i:]+cycle[:i]
        if tmp_c[1]<tmp_c[3]:
            return tmp_c,  motion_type
        else:
            return (tmp_c[0], tmp_c[3], tmp_c[2], tmp_c[1]), motion_type

    @staticmethod
    @doc_index("Other")
    def normalized_motion_types(motion_types):
        r"""
        Return motion types in the normal form.
        """
        res = {}
        for c, t in motion_types.items():
            norm_c, norm_t = MotionClassifier.four_cycle_normal_form(c, t)
            res[norm_c] = norm_t
        return res

    def _w(self, e):
        if e[0] < e[1]:
            return self._ringLC_gens['w'+self._edge2str(e)]
        else:
            return -self._ringLC_gens['w'+self._edge2str(e)]

    def _z(self, e):
        if e[0] < e[1]:
            return self._ringLC_gens['z'+self._edge2str(e)]
        else:
            return -self._ringLC_gens['z'+self._edge2str(e)]

    def _lam(self, e):
        return self._ringLC_gens['lambda'+self._edge2str(e)]
    
    @doc_index("Constraints on edge lengths")
    def lam(self, u,v):
        r"""
        Return the variable for edge length in the ring of edge lengths.
        """
        return self._ring_lambdas_gens['lambda'+self._edge2str([u,v])]

    @doc_index("Motion types consistent with 4-cycles")
    def mu(self, delta):
        r"""
        Return the variable for a given NAC-coloring.
        """
        if type(delta)==str:
            return self._ring_ramification_gens[delta]
        else:
            return self._ring_ramification_gens[delta.name()]

    @doc_index("System of equations for coordinates")
    def x(self, v):
        r"""
        Return the variable for x coordinate of a vertex. 
        """
        return self._ring_coordinates_gens['x'+str(v)]

    @doc_index("System of equations for coordinates")
    def y(self, v):
        r"""
        Return the variable for y coordinate of a vertex. 
        """
        return self._ring_coordinates_gens['y'+str(v)]

    @doc_index("System of equations for coordinates")
    def l(self, u,v):
        r"""
        Return the variable for edge length in the ring with coordinates.
        """
        return self._ring_coordinates_gens['lambda'+self._edge2str([u,v])]

    @doc_index("Constraints on edge lengths")
    def equations_from_leading_coefs(self, delta, extra_eqs=[], check=True):
        r"""
        Return equations for edge lengths from leading coefficients system.

        EXAMPLES::

            sage: from flexrilog import GraphGenerator, MotionClassifier
            sage: K33 = GraphGenerator.K33Graph()
            sage: M = MotionClassifier(K33)
            sage: M.equations_from_leading_coefs('epsilon56')
            [lambda1_2^2 - lambda1_4^2 - lambda2_3^2 + lambda3_4^2]

        ::

            sage: M.equations_from_leading_coefs('omega1')
            Traceback (most recent call last):
            ...
            ValueError: The NAC-coloring must be a singleton.

        ::

            sage: M.equations_from_leading_coefs('omega1', check=False)
            [lambda2_5^2*lambda3_4^2 - lambda2_5^2*lambda3_6^2 - lambda2_3^2*lambda4_5^2 + lambda3_6^2*lambda4_5^2 + lambda2_3^2*lambda5_6^2 - lambda3_4^2*lambda5_6^2]
        """

        if type(delta) == str:
            delta = self._graph.name2NAC_coloring(delta)

        if check:
            if not delta.is_singleton():
                raise exceptions.ValueError('The NAC-coloring must be a singleton.')
        eqs_lengths=[]
        for e in self._graph.edges():
            eqs_lengths.append(self._z(e)*self._w(e) - self._lam(e)**_sage_const_2)


        eqs_w=[]
        eqs_z=[]
        for T in self._graph.spanning_trees():
            for e in self._graph.edges():
                eqw = 0
                eqw_all = 0
                eqz = 0
                eqz_all = 0
                path = T.shortest_path(e[0],e[1])
                for u,v in zip(path, path[1:]+[path[0]]):
                    if delta.is_red(u,v):
                        eqz+=self._z([u,v])
                    else:
                        eqw+=self._w([u,v])
                    eqw_all+=self._w([u,v])
                    eqz_all+=self._z([u,v])
                if eqw:
                    eqs_w.append(eqw)
                else:
                    eqs_w.append(eqw_all)
                if eqz:
                    eqs_z.append(eqz)
                else:
                    eqs_z.append(eqz_all)

        equations = (ideal(eqs_w).groebner_basis()
                     + ideal(eqs_z).groebner_basis()
                     + eqs_lengths
                     + [self._ringLC(eq) for eq in extra_eqs])
        return [self._ring_lambdas(eq)
                for eq in ideal(equations).elimination_ideal(flatten(
                    [[self._w(e), self._z(e)] for e in self._graph.edges()])).basis
                ]

    @staticmethod
    def _pair_ordered(u,v):
        if u<v:
            return (u, v)
        else:
            return (v, u)

    @staticmethod
    def _edge_ordered(u,v):
        return MotionClassifier._pair_ordered(u, v)

#    @staticmethod
    def _set_two_edge_same_lengths(self, H, u, v, w, y, k):
        if H[self._edge_ordered(u,v)]==None and H[self._edge_ordered(w,y)]==None:
            H[self._edge_ordered(u,v)] = k
            H[self._edge_ordered(w,y)] = k
            return 1
        elif H[self._edge_ordered(u,v)]==None:
            H[self._edge_ordered(u,v)] = H[self._edge_ordered(w,y)]
            return 0
        elif H[self._edge_ordered(w,y)]==None:
            H[self._edge_ordered(w,y)] = H[self._edge_ordered(u,v)]
            return 0
        elif H[self._edge_ordered(u,v)]!=H[self._edge_ordered(w,y)]:
            col= H[self._edge_ordered(u,v)]
            for u,v in H.keys():
                if H[(u,v)]==col:
                    H[(u,v)] = H[self._edge_ordered(w,y)]
            return 0
        return 0

    def _set_same_lengths(self, H, types):
        for u,v in H.keys():
            H[(u,v)] = None
        k=1
        for c in types:
            motion = types[c]
            if motion=='a' or motion=='p':
                k += self._set_two_edge_same_lengths(H, c[0], c[1], c[2], c[3], k)
                k += self._set_two_edge_same_lengths(H, c[1], c[2], c[0], c[3], k)
            elif motion=='o':
                k += self._set_two_edge_same_lengths(H, c[0], c[1], c[1], c[2], k)
                k += self._set_two_edge_same_lengths(H, c[2], c[3], c[0], c[3], k)
            elif motion=='e':
                k += self._set_two_edge_same_lengths(H, c[1], c[2], c[2], c[3], k)
                k += self._set_two_edge_same_lengths(H, c[0], c[1], c[0], c[3], k)

    @doc_index("Constraints on edge lengths")
    def motion_types2same_edge_lenghts(self, motion_types):
        r"""
        Return the dictionary of same edge lengths enforced by given motion types.
        """
        H = {self._edge_ordered(u,v):None for u,v in self._graph.edges(labels=False)}
        self._set_same_lengths(H, motion_types)
        return H

    @doc_index("Motion types consistent with 4-cycles")
    def NAC_coloring_restrictions(self):
        r"""
        Return types of restrictions of NAC-colorings to 4-cycles.

        EXAMPLE::

            sage: from flexrilog import MotionClassifier, GraphGenerator
            sage: MC = MotionClassifier(GraphGenerator.K33Graph())
            sage: MC.NAC_coloring_restrictions()
            {(1, 2, 3, 4): {'L': ['omega3', 'omega1', 'epsilon36', 'epsilon16'],
              'O': ['epsilon34', 'epsilon14', 'epsilon23', 'epsilon12'],
              'R': ['omega4', 'epsilon45', 'omega2', 'epsilon25']},
            ...
             (3, 4, 5, 6): {'L': ['omega5', 'omega3', 'epsilon25', 'epsilon23'],
              'O': ['epsilon56', 'epsilon36', 'epsilon45', 'epsilon34'],
              'R': ['omega6', 'epsilon16', 'omega4', 'epsilon14']}}
        """
        res = {cycle:{'O':[], 'L':[], 'R':[]} for cycle in self._four_cycles}
        for delta in self._graph.NAC_colorings():
            for cycle in self._four_cycles:
                colors = [delta.color(e) for e in self.cycle_edges(cycle)]
                if colors[0]==colors[1]:
                    if colors[0]!=colors[2]:
                        res[cycle]['R'].append(delta.name())
                elif colors[1]==colors[2]:
                    res[cycle]['L'].append(delta.name())
                else:
                    res[cycle]['O'].append(delta.name())
        return res

    @doc_index("Motion types consistent with 4-cycles")
    def ramification_formula(self, cycle, motion_type):
        r"""
        Return ramification formula for a given 4-cycle and motion type.

        EXAMPLES::

            sage: from flexrilog import MotionClassifier, GraphGenerator
            sage: MC = MotionClassifier(GraphGenerator.K33Graph())
            sage: MC.ramification_formula((1,2,3,4), 'a')
            [epsilon34,
             epsilon14,
             epsilon23,
             epsilon12,
             omega3 + omega1 + epsilon36 + epsilon16 - omega4 - epsilon45 - omega2 - epsilon25]
        """
        eqs_present = []
        eqs_zeros = []
        NAC_types = self.motion_types2NAC_types(motion_type)
        for t in ['L','O','R']:
            if t in NAC_types:
                eqs_present.append(sum([self.mu(delta) for delta in self._restriction_NAC_types[cycle][t]]))
            else:
                eqs_zeros += [self.mu(delta) for delta in self._restriction_NAC_types[cycle][t]]
        
        if 0 in eqs_present:
            return [self.mu(delta) for delta in self._graph.NAC_colorings()]
        if len(eqs_present)==2:
            return eqs_zeros + [eqs_present[0] - eqs_present[1]]
        elif len(eqs_present)==3:
            return eqs_zeros + [eqs_present[0] - eqs_present[1], eqs_present[1] - eqs_present[2]]
        else:
            return eqs_zeros

    @staticmethod
    @doc_index("Other")
    def motion_types2NAC_types(m):
        r"""
        Return NAC-coloring types for a given motion type.
        """
        if m=='g':
            return ['L','R','O']
        if m=='a':
            return ['L','R']
        if m=='p':
            return ['O']
        if m=='e':
            return ['R','O']
        if m=='o':
            return ['L','O']

    @staticmethod
    @doc_index("Other")
    def NAC_types2motion_type(t):
        r"""
        Return the motion type for given types of NAC-colorings.
        """
        if Set(t)==Set(['L','R','O']):
            return 'g'
        if Set(t)==Set(['L','R']):
            return 'a'
        if Set(t)==Set(['O']):
            return 'p'
        if Set(t)==Set(['R','O']):
            return 'e'
        if Set(t)==Set(['L','O']):
            return 'o'
    
    @doc_index("Other")
    def active_NACs2motion_types(self, active):
        r"""
        Return the motion types of 4-cycles for a given set of active NAC-colorings. 
        """
        motion_types = {cycle:[] for cycle in self._four_cycles}
        for delta in active:
            if type(delta)!=str:
                delta = delta.name()
            for cycle in motion_types:
                motion_types[cycle] += [t for t, colorings 
                                        in self._restriction_NAC_types[cycle].items()
                                        if delta in colorings]
        for cycle in motion_types:
            motion_types[cycle] = self.NAC_types2motion_type(motion_types[cycle])
        return motion_types

    @staticmethod
    def _same_edge_lengths(K, edges_to_check):
        if edges_to_check:
            length = K[MotionClassifier._edge_ordered(edges_to_check[0][0], edges_to_check[0][1])]
            if length==None:
                return False
            for u,v in edges_to_check:
                if length!=K[MotionClassifier._edge_ordered(u,v)]:
                    return False
            return True
        else:
            return True

    @doc_index("Motion types consistent with 4-cycles")
    def consequences_of_nonnegative_solution_assumption(self, eqs):
        r"""
        Return equations implied by the assumption of the existence of nonnegative solutions.
        """
        n_zeros_prev = -1
        zeros = []
        gb = eqs
        while n_zeros_prev!=len(zeros):
            n_zeros_prev = len(zeros)
            gb = self._ring_ramification.ideal(gb + zeros).groebner_basis()
#             gb = self._ring_ramification.ideal(gb + zeros).groebner_basis()
            zeros = []
            for eq in gb:
                coefs = eq.coefficients()
                if sum([sgn(a)*sgn(b) for a,b in zip(coefs[:-1],coefs[1:])])==len(coefs)-1:
                    zeros += eq.variables()
        return [zeros, gb]

#    @staticmethod
#    def consequences_of_nonnegative_solution_assumption(eqs):
#        n_zeros_prev = -1
#        zeros = {}
#        gb = ideal(eqs).groebner_basis()
#        while n_zeros_prev!=len(zeros):
#            n_zeros_prev = len(zeros)
#            gb = [eq.substitute(zeros) for eq in gb if eq.substitute(zeros)!=0]
#            for eq in gb:
#                coefs = eq.coefficients()
#                if sum([sgn(a)*sgn(b) for a,b in zip(coefs[:-1],coefs[1:])])==len(coefs)-1:
#                    for zero_var in eq.variables():
#                        zeros[zero_var] = 0
#        return [zeros.keys(), gb]

    @doc_index("Motion types consistent with 4-cycles")
    def consistent_motion_types(self):#, cycles=[]):
        r"""
        Return the list of motion types consistent with 4-cycles.
        """
#         if cycles==[]:
        cycles = self.four_cycles_ordered()

        k23s = [Graph(self._graph).subgraph(k23_ver).edges(labels=False) for k23_ver in self._graph.induced_K23s()]

        aa_pp = [('a', 'a'), ('p', 'p')]
        ao = [('a','o'), ('o','a')]
        ae = [('a','e'), ('e','a')]
        oe = [('o', 'e'), ('e', 'o')]
        oo_ee = [('e','e'), ('o','o')]

        H = {self._edge_ordered(u,v):None for u,v in self._graph.edges(labels=False)}
        types_prev=[[{}, []]]
        
        self._num_tested_combinations = 0

        for i, new_cycle in enumerate(cycles):
            types_ext = []
            new_cycle_neighbors = [[c2,
                                    new_cycle.index(self._four_cycle_graph.edge_label(new_cycle, c2)),
                                    c2.index(self._four_cycle_graph.edge_label(new_cycle, c2)),
                                   ] for c2 in self._four_cycle_graph.neighbors(new_cycle) if c2 in cycles[:i]]
            for types_original, ramification_eqs_prev in types_prev:
                for type_new_cycle in ['g','a','p','o','e']:
                    self._num_tested_combinations +=1
                    types = deepcopy(types_original)
                    types[tuple(new_cycle)] = type_new_cycle
    #                 H = deepcopy(orig_graph)
                    inconsistent = False

                    for c2, new_index, c2_index in new_cycle_neighbors:
                        type_pair = (types[new_cycle], types[c2])
                        if (type_pair in aa_pp
                                or (type_pair in oe and new_index%2 == c2_index%2)
                                or (type_pair in oo_ee and new_index%2 != c2_index%2)):
                            inconsistent = True
                            break
                        if type_pair in ao:
                            ind_o = type_pair.index('o')
                            if [new_index, c2_index][ind_o] % 2 == 1:
                            # odd deltoid (1,2,3,4) is consistent with 'a' if the common vertex is odd,
                            # but Python lists are indexed from 0
                                inconsistent = True
                                break
                        if type_pair in ae:
                            ind_e = type_pair.index('e')
                            if [new_index, c2_index][ind_e] % 2 == 0:
                                inconsistent = True
                                break
                    if inconsistent:
                        continue

                    self._set_same_lengths(H, types)
                    for c in types:
                        if 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)):
                                inconsistent = True
                                break
                    if inconsistent:
                        continue
                    for K23_edges in k23s:
                        if MotionClassifier._same_edge_lengths(H, K23_edges):
                            inconsistent = True
                            break
                    if inconsistent:
                        continue

                    ramification_eqs = ramification_eqs_prev + self.ramification_formula(new_cycle, type_new_cycle)
                    zero_variables, ramification_eqs = self.consequences_of_nonnegative_solution_assumption(ramification_eqs)
                    for cycle in types:
                        if inconsistent:
                            break
                        for t in self.motion_types2NAC_types(types[cycle]):
                            has_necessary_NAC_type = False
                            for delta in self._restriction_NAC_types[cycle][t]:
                                if not self.mu(delta) in zero_variables:
                                    has_necessary_NAC_type = True
                                    break
                            if not has_necessary_NAC_type:
                                inconsistent = True
                                break
                    if inconsistent:
                        continue

                    types_ext.append([types, ramification_eqs])

            types_prev=types_ext

        return [t for t, _ in types_prev]

    @doc_index("Other")
    def active_NAC_coloring_names(self, motion_types):
        r"""
        Return the names of active NAC-colorings for given motion types.
        """
        return [delta.name() for delta in self.motion_types2active_NACs(motion_types)]
        
    @doc_index("Motion types consistent with 4-cycles")
    def motion_types2active_NACs(self, motion_types):
        r"""
        Return the active NAC-colorings for given motion types, if uniquely determined.
        """
        zeros, eqs = self.consequences_of_nonnegative_solution_assumption(
            flatten([self.ramification_formula(c, motion_types[c]) for c in motion_types]))

        if self._ring_ramification.ideal(eqs).dimension()==1:
            return [delta for delta in self._graph.NAC_colorings() if not self.mu(delta) in zeros]
        else:
            raise NotImplementedError('There might be more solutions (dim '+str(
                self._ring_ramification.ideal(eqs).dimension()) + ')')

    @doc_index("General methods")
    def motion_types_equivalent_classes(self,  motion_types_list):
        r"""
        Split a list of motion types into isomorphism classes.
        """
        aut_group = self._graph.automorphism_group()
        classes = [
            [( motion_types_list[0],
              self.normalized_motion_types( motion_types_list[0]),
              Counter([('d' if t in ['e','o'] else t) for c, t in  motion_types_list[0].items()]))]
        ]
        for next_motion in  motion_types_list[1:]:
            added = False
            next_sign = Counter([('d' if t in ['e','o'] else t) for c, t in next_motion.items()])
            for cls in classes:
                repr_motion_types = cls[0][1]
                if cls[0][2]!=next_sign:
                    continue
                for sigma in aut_group:
                    next_motion_image = self.normalized_motion_types({tuple(sigma(v) for v in c): t
                                                        for c,t in next_motion.items()})
                    for c in repr_motion_types:
                        if repr_motion_types[c]!=next_motion_image[c]:
                            break
                    else:
                        cls.append([next_motion])
                        added = True
                        break
#                    if not False in [repr_motion_types[c]==next_motion_image[c] for c in repr_motion_types]:
#                        cls.append(next_motion)
#                        added = True
#                        break
                if added:
                    break
            else:
                classes.append([(next_motion, self.normalized_motion_types(next_motion), next_sign)])
        return [[t[0] for t in cls] for cls in classes]

    @doc_index("General methods")
    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

    @doc_index("General methods")
    def possible_motion_types_and_active_NACs(self,
                                              comments = {},
                                              show_table=True,
                                              one_representative=True,
                                              tab_rows=False,
                                              keep_orth_failed=False,
                                              equations=False):
        r"""
        Wraps the function for consistent motion types, conditions on orthogonality of diagonals and splitting into equivalence classes.
        """
        types = self.consistent_motion_types()
        classes = self.motion_types_equivalent_classes(types)
        valid_classes = []
        
        motions = [ 'g','a','p','d']
        if one_representative:
            header = [['index', '#', 'motion types'] + motions + ['active NACs', 'comment']]
        else:
            header = [['index', '#', 'elem.', 'motion types'] + motions + ['active NACs', 'comment']]
        if equations:
            header[0].append('equations')
        rows = []
        for i, cls in enumerate(classes):
            rows_cls = []
            to_be_appended = True
            for j, t in enumerate(cls):
                row = [i, len(cls)]
                if not one_representative:
                    row.append(j)
                row.append(' '.join([t[c] for c in self.four_cycles_ordered()]))
                row += [Counter([('d' if s in ['e','o'] else s) for c, s in t.items()])[m] for m in motions]
                try:
                    active = self.active_NAC_coloring_names(t)
                    row.append([self.mu(name) for name in sorted(active)])
                    if self.check_orthogonal_diagonals(t, active):
                        row.append(comments.get(i,''))
                    else:
                        to_be_appended = False
                        if not keep_orth_failed:
                            continue
                        else:
                            row.append('orthogonality check failed' + str(comments.get(i,'')))
                            
                except NotImplementedError as e:
                    zeros, eqs = self.consequences_of_nonnegative_solution_assumption(
                        flatten([self.ramification_formula(c, t[c]) for c in t]))
                    row.append([eq for eq in eqs if not eq in zeros])
                    row.append(str(comments.get(i,'')) + str(e))
                    
                if equations:
                    zeros, eqs = self.consequences_of_nonnegative_solution_assumption(
                        flatten([self.ramification_formula(c, t[c]) for c in t]))
                    row.append([eq for eq in eqs if not eq in zeros])
                    
                rows_cls.append(row)
                
                if one_representative:
                    break
            if to_be_appended or keep_orth_failed:
                valid_classes.append(cls)
                if one_representative:
                    rows += rows_cls
                else:
                    rows.append(rows_cls)
        if show_table:
            if one_representative:
                T = table(header + rows)
            else:
                T = table(header + [row for rows_cls in rows for row in rows_cls])
            T.options()['header_row'] = True
            display(T)

        if tab_rows:
            return valid_classes, rows
        return valid_classes
        

    @doc_index("Constraints on edge lengths")
    def motion_types2equations(self, motion_types,
                                           active_NACs=None,
                                           groebner_basis=True,
                                           extra_eqs=[]):
        r"""
        Return equations enforced by edge lengths and singleton active NAC-colorings.
        """
        if active_NACs==None:
            active_NACs = self.motion_types2active_NACs(motion_types)
        
        eqs_same_lengths = self.motion_types2same_lengths_equations(motion_types)
        eqs = flatten([self.equations_from_leading_coefs(delta, check=False,
                                                 extra_eqs=eqs_same_lengths + extra_eqs)
                    for delta in active_NACs if delta.is_singleton(active_NACs)
                ])
        if groebner_basis:
            return ideal(eqs).groebner_basis()
        else:
            return eqs
    
    @doc_index("General methods")
    def degenerate_triangle_equation(self, u, v, w):
        r"""
        Return the equation for a degenerate triangle.
        """
        return self.lam(u,v) - self.lam(u,w) - self.lam(w,v)
        

    @doc_index("Constraints on edge lengths")
    def motion_types2same_lengths_equations(self, motion_types):
        r"""
        Return the equations for edge lengths enforced by motion types.
        """
        eqs = []
        for c, motion in motion_types.items():
            if motion=='a' or motion=='p':
                eqs.append(self.lam(c[0], c[1]) - self.lam(c[2], c[3]))
                eqs.append(self.lam(c[1], c[2]) - self.lam(c[0], c[3]))
            elif motion=='o':
                eqs.append(self.lam(c[0], c[1]) - self.lam(c[1], c[2]))
                eqs.append(self.lam(c[2], c[3]) - self.lam(c[0], c[3]))
            elif motion=='e':
                eqs.append(self.lam(c[1], c[2]) - self.lam(c[2], c[3]))
                eqs.append(self.lam(c[0], c[1]) - self.lam(c[0], c[3]))
        return [eq for eq in ideal(eqs).groebner_basis()] if eqs else []


    @doc_index("Constraints on edge lengths")
    def graph_with_same_edge_lengths(self, motion_types, plot=True):
        r"""
        Return a graph with edge labels corresponding to same edge lengths.

        INPUT:
        
        - `plot` -- if `True` (default), then plot of the graph is returned. 
        
        OUTPUT:
        
        The edge labels of the output graph are same for if the edge lengths
        are same due to `motion_types`. 
        """
        H = {self._edge_ordered(u,v):None for u,v in self._graph.edges(labels=False)}
        self._set_same_lengths(H, motion_types)
        G_labeled = Graph([[u,v,H[(u,v)]] for u,v in H])
        G_labeled._pos = self._graph._pos
        if plot:
            return G_labeled.plot(edge_labels=True, color_by_label=True)
        else:
            return G_labeled

    @doc_index("Constraints on edge lengths")
    def singletons_table(self, active_NACs=None):
        r"""
        Return table whether (active) NAC-colorings are singletons.
        """
        rows = [['NAC-coloring', 'is singleton']]
        if active_NACs==None:
            active_NACs = self._graph.NAC_colorings()
            only_active = False
        else:
            only_active = True
            rows[0].append('is singleton w.r.t. active')

        for delta in active_NACs:
            rows.append([delta.name(), delta.is_singleton()])
            if only_active:
                rows[-1].append(delta.is_singleton(active_NACs))
        T = table(rows)
        T.options()['header_row'] = True
        return T
    
    @doc_index("System of equations for coordinates")
    def edge_equations_ideal(self, fixed_edge, eqs_lamdas=[], extra_eqs=[], show_input=False):
        r"""
        Return the ideal of equations for coordinates of vertices and given edge constraints.
        """
        equations = []
        for u,v in self._graph.edges(labels=False):
            equations.append((self.x(u)-self.x(v))**_sage_const_2 + (self.y(u)-self.y(v))**_sage_const_2 - self.l(u,v)**_sage_const_2)
        equations += [
            self.x(fixed_edge[0]),
            self.y(fixed_edge[0]),
            self.y(fixed_edge[1]),
            self.x(fixed_edge[1]) - self.l(fixed_edge[0], fixed_edge[1]),
            ] + [
                self._ring_coordinates(eq) for eq in list(eqs_lamdas) + list(extra_eqs)
                ]
        if show_input:
            for eq in equations:
                show(eq)
        return ideal(equations)
    
    @doc_index("General methods")
    def edge_lengths_dimension(self, eqs_lambdas):
        r"""
        Return the dimension of the variaty of edge lengths.
        """
        return ideal(eqs_lambdas + [self.aux_var]).dimension()
    
    @doc_index("Other")
    def edge_lengts_dict2eqs(self, edge_lengths):
        r"""
        Return equations with asigned edge lengths.
        """
        return [self.lam(e[0],e[1]) - QQ(edge_lengths[e]) for e in edge_lengths ]

    @doc_index("General methods")
    def edge_lengths_satisfy_eqs(self, eqs, edge_lengths, print_values=False):
        r"""
        Check if a given dictionary of edge lengths satisfy given equations.
        """
        I = ideal(self.edge_lengts_dict2eqs(edge_lengths))
        if print_values:
            print([(eq.reduce(I)) for eq in eqs])
        return sum([(eq.reduce(I))**2 for eq in eqs])==0

    
    @staticmethod
    @doc_index("Other")
    def show_factored_eqs(eqs, only_print=False, numbers=False,
                          variables=False, print_latex=False,
                          print_eqs=True):
        r"""
        Show given equations factored.
        """
        for i, eq in enumerate(eqs):
            factors = factor(eq)
            if numbers:
                print(i)
            if variables:
                print(latex(eq.variables()))
            if print_latex:
                print(latex(factors) + '=0\,, \\\\')
            if print_eqs:
                if only_print:
                    print(factors)
                else:
                    show(factors)
    
    @staticmethod
    @doc_index("General methods")
    def is_subcase(eqs_a, eqs_b):
        r"""
        Return if `eqs_a` is a subcase of `eqs_b`, i.e., the ideal of `eqs_a` contains the ideal of `eqs_b`.
        """
        I_a = ideal(eqs_a)
        for eq in eqs_b:
            if not eq in I_a:
                return False
        return True
    
    @doc_index("Other")
    def motion_types2tikz(self,
                          motion_types,
                          color_names=[]
                          , vertex_style='lnodesmall',
                          none_gray=False,
                          ):
        r"""
        Return TikZ code for the graph with edges colored according to the lengths enforced by motion types.
        """
        H = {self._edge_ordered(u,v):None for u,v in self._graph.edges(labels=False)}
        self._set_same_lengths(H, motion_types)
        edge_partition = [[e for e in H if H[e]==el] for el in Set(H.values()) if el!=None]
        if none_gray:
            edge_partition.append([e for e in H if H[e]==None]) 
        else:
            edge_partition += [[e] for e in H if H[e]==None]
        if color_names==[]:
            color_names = ['edge, col{}'.format(i) for i in range(1,len(edge_partition)+1)]
        if none_gray:
            color_names[-1] = 'edge'

        self._graph.print_tikz(colored_edges= edge_partition,
                               color_names=color_names[:len(edge_partition)],
                               vertex_style=vertex_style)
Esempio n. 30
0
 def red_subgraph(self):
     return Graph(
         [self._graph.vertices(), [list(e) for e in self._red_edges]],
         format='vertices_and_edges')
Esempio n. 31
0
class StrataWithSageGraph(object):
    def __init__(self, strataG):
        self.strataG = strataG
        self.sageG = Graph([range(1,strataG.num_vertices()+1),[]], multiedges=True, loops = True)
        self.edge_label_to_edge = dict()
        self.vertex_to_marks = {v:[] for v in range(1, self.strataG.num_vertices()+1)}
        self._has_marks = False
        
        for e in range(1, strataG.num_edges()+1):
            edge_done = False
            if self.strataG.M[0,e] != 0: #it is a half edge
                for v in range(1, strataG.num_vertices()+1):
                    if self.strataG.M[v,e][0] == 1:
                        self.vertex_to_marks[v].append((e,self.strataG.M[0,e]))
                        edge_done = True
                        self._has_marks = True
                        break
            else: #it is a whole edge           
                   
                vert_touching_e = []
            
                for v in range(1, strataG.num_vertices()+1):
                    if strataG.M[v,e][0] == 2:
                        #add a loop
                        self.sageG.add_edge( (v,v,e) )
                        self.edge_label_to_edge[e] = (v,v,e)
                        edge_done = True
                        break
                    if strataG.M[v,e][0] == 1:
                        vert_touching_e.append(v)
                        if len(vert_touching_e) == 2:
                            break
                            
            if edge_done:
                continue
            if len(vert_touching_e) == 2:
                self.sageG.add_edge( (vert_touching_e[0], vert_touching_e[1],e) )
                self.edge_label_to_edge[e] = (vert_touching_e[0], vert_touching_e[1],e)
            else:
                raise Exception("Unexpected here!")
    
    def has_marks(self):
        return self._has_marks
        
    def marks_on_v(self,v):
        return self.vertex_to_marks[v]
                 
    def edges_incident(self,v):
        for v1,v2,e in self.sageG.edges_incident(v):
            yield e
            
    def edges_labels_between_vertex_sets(self,vs1,vs2):
        #problem here when overlap........
        result = []
        for v1,v2, e in self.sageG.edges():
            if v1 in vs1 and v2 in vs2:
                result.append(e)
            elif v1 in vs2 and v2 in vs1:
                result.append(e)
        return result
        
        #some probably garbage...
        #v1sedges = set()
        #v2sedges = set()
        #for v1 in vs1:
        #    for e in self.edges_incident(v1):
        #        v1sedges.add(e)
        #for v2 in vs2:
        #    for e in self.edges_incident(v2):
        #        v2sedges.add(e)
                
        #return v1sedges.intersection(v2sedges)
        
    def edges(self):
        """
        Returns a list of triples!
        """
        return self.sageG.edges()
        
    def vertices(self):
        return self.sageG.vertices()
        
    def num_vertices(self):
        return self.strataG.num_vertices()
        
    def v_genus(self,v):
        """
        Returns the genus of the vertex v.
        """
        return self.strataG.M[v,0][0]
        
    def subgraph(self,vertices, edge_labels): 
        #print self.edge_label_to_edge
        #print self.sageG.edges()
        return self.sageG.subgraph(vertices, [self.edge_label_to_edge[l] for l in edge_labels])
        
    def edge_is_incident(self,e,v):
        #print "is_inc", e,v
        #print self.strataG
        #print
        return self.strataG.M[v,e][0] > 0
        
    def is_loop(self, e):
        v1,v2, ep = self.edge_label_to_edge[e]
        return v1==v2
Esempio n. 32
0
        new_x, new_y = pt
        if new_x < curr_x - 1:
            not_in_inertia.update([(i, curr_y)
                                   for i in range(new_x + 1, curr_x)])
            not_in_inertia.update([(curr_y, i)
                                   for i in range(new_x + 1, curr_x)])
        curr_x, curr_y = new_x, new_y
    return not_in_inertia


def Zplus(G):
    return Z_pythonBitset(G, q=0)


from sage.all import Graph, graphs
G = Graph()
G.add_edges([[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 1], [1, 4], [2, 5],
             [3, 6], [7, 1], [7, 2], [7, 3]])

G2 = graphs.CompleteGraph(4)
G2.subdivide_edges(G2.edges(), 1)

from sage.all import points


def plot_inertia_lower_bound(g):
    return points(list(Zq_inertia_lower_bound(g)),
                  pointsize=40,
                  gridlines=True,
                  ticks=[range(g.order()), range(g.order())],
                  aspect_ratio=1)
    def __init__(self, graph, four_cycles=[], separator='', edges_ordered=[]):
        if not (isinstance(graph, FlexRiGraph) or 'FlexRiGraph' in str(type(graph))):
            raise exceptions.TypeError('The graph must be of the type FlexRiGraph.')
        self._graph = graph

        if four_cycles == []:
            self._four_cycles = self._graph.four_cycles(only_with_NAC=True) 
        else:
            self._four_cycles = four_cycles

        if not self._graph.are_NAC_colorings_named():
            self._graph.set_NAC_colorings_names()

#        -----Polynomial Ring for leading coefficients-----
        ws = []
        zs = []
        lambdas = []
        ws_latex = []
        zs_latex = []
        lambdas_latex = []
        
        if edges_ordered==[]:
            edges_ordered = self._graph.edges(labels=False)
        else:
            if (Set([self._edge2str(e) for e in edges_ordered]) !=
                Set([self._edge2str(e) for e in self._graph.edges(labels=False)])):
                raise ValueError('The provided ordered edges do not match the edges of the graph.')

        for e in edges_ordered:
            ws.append('w' + self._edge2str(e))
            zs.append('z' + self._edge2str(e))
            lambdas.append('lambda' + self._edge2str(e))
            ws_latex.append('w_{' + self._edge2str(e).replace('_', separator) + '}')
            zs_latex.append('z_{' + self._edge2str(e).replace('_', separator) + '}')
            lambdas_latex.append('\\lambda_{' + self._edge2str(e).replace('_', separator) + '}')

        self._ringLC = PolynomialRing(QQ, names=lambdas+ws+zs) #, order='lex')
        self._ringLC._latex_names = lambdas_latex + ws_latex + zs_latex
        self._ringLC_gens = self._ringLC.gens_dict()

        self._ring_lambdas = PolynomialRing(QQ, names=lambdas + ['u'])
        self._ring_lambdas._latex_names = lambdas_latex + ['u']
        self._ring_lambdas_gens = self._ring_lambdas.gens_dict()
        self.aux_var = self._ring_lambdas_gens['u']
        
        xs = []
        ys = []
        xs_latex = []
        ys_latex = []
        for v in self._graph.vertices():
            xs.append('x' + str(v))
            ys.append('y' + str(v))
            xs_latex.append('x_{' + str(v) + '}')
            ys_latex.append('y_{' + str(v) + '}')
            
        self._ring_coordinates = PolynomialRing(QQ, names=lambdas+xs+ys)
        self._ring_coordinates._latex_names = lambdas_latex + xs_latex + ys_latex
        self._ring_coordinates_gens = self._ring_coordinates.gens_dict()
        
        
#        ----Ramification-----
#         if len(self._graph.NAC_colorings()) > 1: 
        self._ring_ramification = PolynomialRing(QQ,
                                                 [col.name() for col in self._graph.NAC_colorings()],
                                                 len(self._graph.NAC_colorings()))
#         else:
#             self._ring_ramification = PolynomialRing(QQ, self._graph.NAC_colorings()[0].name())
        self._ring_ramification_gens = self._ring_ramification.gens_dict()
        self._restriction_NAC_types = self.NAC_coloring_restrictions()

#        -----Graph of 4-cycles-----
        self._four_cycle_graph = Graph([self._four_cycles,[]], format='vertices_and_edges')

        for c1, c2 in Subsets(self._four_cycle_graph.vertices(), 2):
            intersection = self.cycle_edges(c1, sets=True).intersection(self.cycle_edges(c2, sets=True))
            if len(intersection)>=2 and len(intersection[0].intersection(intersection[1]))==1:
                common_vert = intersection[0].intersection(intersection[1])[0]
                self._four_cycle_graph.add_edge(c1, c2, common_vert)

#        -----Cycle with orthogonal diagonals due to NAC-----
        self._orthogonal_diagonals = {
                delta.name(): [cycle for cycle in self._four_cycle_graph if delta.cycle_has_orthogonal_diagonals(cycle)]
                for delta in self._graph.NAC_colorings()}