def tree(self): r""" Returns the Huffman tree corresponding to the current encoding. INPUT: - None. OUTPUT: - The binary tree representing a Huffman code. EXAMPLES:: sage: from sage.coding.source_coding.huffman import Huffman sage: str = "Sage is my most favorite general purpose computer algebra system" sage: h = Huffman(str) sage: T = h.tree(); T Digraph on 39 vertices sage: T.show(figsize=[20,20]) <BLANKLINE> """ from sage.graphs.digraph import DiGraph g = DiGraph() g.add_edges(self._generate_edges(self._tree)) return g
def Circuit(self, n): r""" Returns the circuit on `n` vertices The circuit is an oriented ``CycleGraph`` EXAMPLE: A circuit is the smallest strongly connected digraph:: sage: circuit = digraphs.Circuit(15) sage: len(circuit.strongly_connected_components()) == 1 True """ g = DiGraph(n) g.name("Circuit") if n == 0: return g elif n == 1: g.allow_loops(True) g.add_edge(0, 0) return g else: g.add_edges([(i, i + 1) for i in xrange(n - 1)]) g.add_edge(n - 1, 0) return g
def tree(self): r""" Returns the Huffman tree corresponding to the current encoding. INPUT: - None. OUTPUT: - The binary tree representing a Huffman code. EXAMPLES:: sage: from sage.coding.source_coding.huffman import Huffman sage: str = "Sage is my most favorite general purpose computer algebra system" sage: h = Huffman(str) sage: T = h.tree(); T Digraph on 39 vertices sage: T.show(figsize=[20,20]) <BLANKLINE> """ from sage.graphs.digraph import DiGraph g = DiGraph() g.add_edges(self._generate_edges(self._tree)) return g
def Circuit(self, n): r""" Returns the circuit on `n` vertices The circuit is an oriented ``CycleGraph`` EXAMPLE: A circuit is the smallest strongly connected digraph:: sage: circuit = digraphs.Circuit(15) sage: len(circuit.strongly_connected_components()) == 1 True """ if n < 0: raise ValueError( "The number of vertices must be a positive integer.") g = DiGraph() g.name("Circuit on " + str(n) + " vertices") if n == 0: return g elif n == 1: g.allow_loops(True) g.add_edge(0, 0) return g else: g.add_edges([(i, i + 1) for i in xrange(n - 1)]) g.add_edge(n - 1, 0) return g
def Circuit(self,n): r""" Returns the circuit on `n` vertices The circuit is an oriented ``CycleGraph`` EXAMPLE: A circuit is the smallest strongly connected digraph:: sage: circuit = digraphs.Circuit(15) sage: len(circuit.strongly_connected_components()) == 1 True """ g = DiGraph(n) g.name("Circuit") if n==0: return g elif n == 1: g.allow_loops(True) g.add_edge(0,0) return g else: g.add_edges([(i,i+1) for i in xrange(n-1)]) g.add_edge(n-1,0) return g
def Circuit(self,n): r""" Returns the circuit on `n` vertices The circuit is an oriented ``CycleGraph`` EXAMPLE: A circuit is the smallest strongly connected digraph:: sage: circuit = digraphs.Circuit(15) sage: len(circuit.strongly_connected_components()) == 1 True """ if n<0: raise ValueError("The number of vertices must be a positive integer.") g = DiGraph() g.name("Circuit on "+str(n)+" vertices") if n==0: return g elif n == 1: g.allow_loops(True) g.add_edge(0,0) return g else: g.add_edges([(i,i+1) for i in xrange(n-1)]) g.add_edge(n-1,0) return g
def Circulant(self, n, integers): r""" Returns a circulant digraph on `n` vertices from a set of integers. INPUT: - ``n`` (integer) -- number of vertices. - ``integers`` -- the list of integers such that there is an edge from `i` to `j` if and only if ``(j-i)%n in integers``. EXAMPLE:: sage: digraphs.Circulant(13,[3,5,7]) Circulant graph ([3, 5, 7]): Digraph on 13 vertices TESTS:: sage: digraphs.Circulant(13,[3,5,7,"hey"]) Traceback (most recent call last): ... ValueError: The list must contain only relative integers. sage: digraphs.Circulant(-2,[3,5,7,3]) Traceback (most recent call last): ... ValueError: n must be a positive integer sage: digraphs.Circulant(3,[3,5,7,3.4]) Traceback (most recent call last): ... ValueError: The list must contain only relative integers. """ from sage.graphs.graph_plot import _circle_embedding from sage.rings.integer_ring import ZZ # Bad input and loops loops = False if not n in ZZ or n <= 0: raise ValueError("n must be a positive integer") for i in integers: if not i in ZZ: raise ValueError( "The list must contain only relative integers.") if (i % n) == 0: loops = True G = DiGraph(n, name="Circulant graph (" + str(integers) + ")", loops=loops) _circle_embedding(G, range(n)) for v in range(n): G.add_edges([(v, (v + j) % n) for j in integers]) return G
def Circulant(self,n,integers): r""" Returns a circulant digraph on `n` vertices from a set of integers. INPUT: - ``n`` (integer) -- number of vertices. - ``integers`` -- the list of integers such that there is an edge from `i` to `j` if and only if ``(j-i)%n in integers``. EXAMPLE:: sage: digraphs.Circulant(13,[3,5,7]) Circulant graph ([3, 5, 7]): Digraph on 13 vertices TESTS:: sage: digraphs.Circulant(13,[3,5,7,"hey"]) Traceback (most recent call last): ... ValueError: The list must contain only relative integers. sage: digraphs.Circulant(-2,[3,5,7,3]) Traceback (most recent call last): ... ValueError: n must be a positive integer sage: digraphs.Circulant(3,[3,5,7,3.4]) Traceback (most recent call last): ... ValueError: The list must contain only relative integers. """ from sage.graphs.graph_plot import _circle_embedding from sage.rings.integer_ring import ZZ # Bad input and loops loops = False if not n in ZZ or n <= 0: raise ValueError("n must be a positive integer") for i in integers: if not i in ZZ: raise ValueError("The list must contain only relative integers.") if (i%n) == 0: loops = True G=DiGraph(n, name="Circulant graph ("+str(integers)+")", loops=loops) _circle_embedding(G, range(n)) for v in range(n): G.add_edges([(v,(v+j)%n) for j in integers]) return G
def shard_preorder_graph(runs): """ Return the preorder attached to a tuple of decreasing runs. This is a directed graph, whose vertices correspond to the runs. There is an edge from a run `R` to a run `S` if `R` is before `S` in the list of runs and the two intervals defined by the initial and final indices of `R` and `S` overlap. This only depends on the initial and final indices of the runs. For this reason, this input can also be given in that shorten way. INPUT: - a tuple of tuples, the runs of a permutation, or - a tuple of pairs `(i,j)`, each one standing for a run from `i` to `j`. OUTPUT: a directed graph, with vertices labelled by integers EXAMPLES:: sage: from sage.combinat.shard_order import shard_preorder_graph sage: s = Permutation([2,8,3,9,6,4,5,1,7]) sage: def cut(lr): ....: return tuple((r[0], r[-1]) for r in lr) sage: shard_preorder_graph(cut(s.decreasing_runs())) Digraph on 5 vertices sage: s = Permutation([9,4,3,2,8,6,5,1,7]) sage: P = shard_preorder_graph(s.decreasing_runs()) sage: P.is_isomorphic(digraphs.TransitiveTournament(3)) True """ N = len(runs) dg = DiGraph(N) dg.add_edges((i, j) for i in range(N - 1) for j in range(i + 1, N) if runs[i][-1] < runs[j][0] and runs[j][-1] < runs[i][0]) return dg
def line_graph(self, labels=True): """ Returns the line graph of the (di)graph. INPUT: - ``labels`` (boolean) -- whether edge labels should be taken in consideration. If ``labels=True``, the vertices of the line graph will be triples ``(u,v,label)``, and pairs of vertices otherwise. This is set to ``True`` by default. The line graph of an undirected graph G is an undirected graph H such that the vertices of H are the edges of G and two vertices e and f of H are adjacent if e and f share a common vertex in G. In other words, an edge in H represents a path of length 2 in G. The line graph of a directed graph G is a directed graph H such that the vertices of H are the edges of G and two vertices e and f of H are adjacent if e and f share a common vertex in G and the terminal vertex of e is the initial vertex of f. In other words, an edge in H represents a (directed) path of length 2 in G. .. NOTE:: As a :class:`Graph` object only accepts hashable objects as vertices (and as the vertices of the line graph are the edges of the graph), this code will fail if edge labels are not hashable. You can also set the argument ``labels=False`` to ignore labels. .. SEEALSO:: - The :mod:`line_graph <sage.graphs.line_graph>` module. - :meth:`~sage.graphs.graph_generators.GraphGenerators.line_graph_forbidden_subgraphs` -- the forbidden subgraphs of a line graph. - :meth:`~Graph.is_line_graph` -- tests whether a graph is a line graph. EXAMPLES:: sage: g = graphs.CompleteGraph(4) sage: h = g.line_graph() sage: h.vertices() [(0, 1, None), (0, 2, None), (0, 3, None), (1, 2, None), (1, 3, None), (2, 3, None)] sage: h.am() [0 1 1 1 1 0] [1 0 1 1 0 1] [1 1 0 0 1 1] [1 1 0 0 1 1] [1 0 1 1 0 1] [0 1 1 1 1 0] sage: h2 = g.line_graph(labels=False) sage: h2.vertices() [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] sage: h2.am() == h.am() True sage: g = DiGraph([[1..4],lambda i,j: i<j]) sage: h = g.line_graph() sage: h.vertices() [(1, 2, None), (1, 3, None), (1, 4, None), (2, 3, None), (2, 4, None), (3, 4, None)] sage: h.edges() [((1, 2, None), (2, 3, None), None), ((1, 2, None), (2, 4, None), None), ((1, 3, None), (3, 4, None), None), ((2, 3, None), (3, 4, None), None)] Tests: :trac:`13787`:: sage: g = graphs.KneserGraph(7,1) sage: C = graphs.CompleteGraph(7) sage: C.is_isomorphic(g) True sage: C.line_graph().is_isomorphic(g.line_graph()) True """ self._scream_if_not_simple() if self._directed: from sage.graphs.digraph import DiGraph G = DiGraph() G.add_vertices(self.edges(labels=labels)) for v in self: # Connect appropriate incident edges of the vertex v G.add_edges([(e,f) for e in self.incoming_edge_iterator(v, labels=labels) \ for f in self.outgoing_edge_iterator(v, labels=labels)]) return G else: from sage.graphs.all import Graph G = Graph() # We must sort the edges' endpoints so that (1,2,None) is seen as # the same edge as (2,1,None). # # We do so by comparing hashes, just in case all the natural order # (<) on vertices would not be a total order (for instance when # vertices are sets). If two adjacent vertices have the same hash, # then we store the pair in the dictionary of conflicts conflicts = {} # 1) List of vertices in the line graph elist = [] for e in self.edge_iterator(labels=labels): if hash(e[0]) < hash(e[1]): elist.append(e) elif hash(e[0]) > hash(e[1]): elist.append((e[1], e[0]) + e[2:]) else: # Settle the conflict arbitrarily conflicts[e] = e conflicts[(e[1], e[0]) + e[2:]] = e elist.append(e) G.add_vertices(elist) # 2) adjacencies in the line graph for v in self: elist = [] # Add the edge to the list, according to hashes, as previously for e in self.edge_iterator(v, labels=labels): if hash(e[0]) < hash(e[1]): elist.append(e) elif hash(e[0]) > hash(e[1]): elist.append((e[1], e[0]) + e[2:]) else: elist.append(conflicts[e]) # Alls pairs of elements in elist are edges of the # line graph while elist: x = elist.pop() for y in elist: G.add_edge(x, y) return G
def line_graph(self, labels=True): """ Returns the line graph of the (di)graph. INPUT: - ``labels`` (boolean) -- whether edge labels should be taken in consideration. If ``labels=True``, the vertices of the line graph will be triples ``(u,v,label)``, and pairs of vertices otherwise. This is set to ``True`` by default. The line graph of an undirected graph G is an undirected graph H such that the vertices of H are the edges of G and two vertices e and f of H are adjacent if e and f share a common vertex in G. In other words, an edge in H represents a path of length 2 in G. The line graph of a directed graph G is a directed graph H such that the vertices of H are the edges of G and two vertices e and f of H are adjacent if e and f share a common vertex in G and the terminal vertex of e is the initial vertex of f. In other words, an edge in H represents a (directed) path of length 2 in G. .. NOTE:: As a :class:`Graph` object only accepts hashable objects as vertices (and as the vertices of the line graph are the edges of the graph), this code will fail if edge labels are not hashable. You can also set the argument ``labels=False`` to ignore labels. .. SEEALSO:: - The :mod:`line_graph <sage.graphs.line_graph>` module. - :meth:`~sage.graphs.graph_generators.GraphGenerators.line_graph_forbidden_subgraphs` -- the forbidden subgraphs of a line graph. - :meth:`~Graph.is_line_graph` -- tests whether a graph is a line graph. EXAMPLES:: sage: g = graphs.CompleteGraph(4) sage: h = g.line_graph() sage: h.vertices() [(0, 1, None), (0, 2, None), (0, 3, None), (1, 2, None), (1, 3, None), (2, 3, None)] sage: h.am() [0 1 1 1 1 0] [1 0 1 1 0 1] [1 1 0 0 1 1] [1 1 0 0 1 1] [1 0 1 1 0 1] [0 1 1 1 1 0] sage: h2 = g.line_graph(labels=False) sage: h2.vertices() [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] sage: h2.am() == h.am() True sage: g = DiGraph([[1..4],lambda i,j: i<j]) sage: h = g.line_graph() sage: h.vertices() [(1, 2, None), (1, 3, None), (1, 4, None), (2, 3, None), (2, 4, None), (3, 4, None)] sage: h.edges() [((1, 2, None), (2, 3, None), None), ((1, 2, None), (2, 4, None), None), ((1, 3, None), (3, 4, None), None), ((2, 3, None), (3, 4, None), None)] Tests: :trac:`13787`:: sage: g = graphs.KneserGraph(7,1) sage: C = graphs.CompleteGraph(7) sage: C.is_isomorphic(g) True sage: C.line_graph().is_isomorphic(g.line_graph()) True """ self._scream_if_not_simple() if self._directed: from sage.graphs.digraph import DiGraph G=DiGraph() G.add_vertices(self.edges(labels=labels)) for v in self: # Connect appropriate incident edges of the vertex v G.add_edges([(e,f) for e in self.incoming_edge_iterator(v, labels=labels) \ for f in self.outgoing_edge_iterator(v, labels=labels)]) return G else: from sage.graphs.all import Graph G=Graph() # We must sort the edges' endpoints so that (1,2,None) is seen as # the same edge as (2,1,None). # # We do so by comparing hashes, just in case all the natural order # (<) on vertices would not be a total order (for instance when # vertices are sets). If two adjacent vertices have the same hash, # then we store the pair in the dictionary of conflicts conflicts = {} # 1) List of vertices in the line graph elist = [] for e in self.edge_iterator(labels = labels): if hash(e[0]) < hash(e[1]): elist.append(e) elif hash(e[0]) > hash(e[1]): elist.append((e[1],e[0])+e[2:]) else: # Settle the conflict arbitrarily conflicts[e] = e conflicts[(e[1],e[0])+e[2:]] = e elist.append(e) G.add_vertices(elist) # 2) adjacencies in the line graph for v in self: elist = [] # Add the edge to the list, according to hashes, as previously for e in self.edge_iterator(v, labels=labels): if hash(e[0]) < hash(e[1]): elist.append(e) elif hash(e[0]) > hash(e[1]): elist.append((e[1],e[0])+e[2:]) else: elist.append(conflicts[e]) # Alls pairs of elements in elist are edges of the # line graph while elist: x = elist.pop() for y in elist: G.add_edge(x,y) return G