def irreducible_component_index_sets(self): r""" Return a list containing the index sets of the irreducible components of ``self`` as finite reflection groups. EXAMPLES:: sage: W = ReflectionGroup([1,1,3], [3,1,3], 4); W # optional - gap3 Reducible complex reflection group of rank 7 and type A2 x G(3,1,3) x ST4 sage: sorted(W.irreducible_component_index_sets()) # optional - gap3 [[1, 2], [3, 4, 5], [6, 7]] ALGORITHM: Take the connected components of the graph on the index set with edges (i,j) where s[i] and s[j] don't commute. """ I = self.index_set() s = self.simple_reflections() from sage.graphs.graph import Graph G = Graph([I, [[i,j] for i,j in itertools.combinations(I,2) if s[i]*s[j] != s[j]*s[i] ]], format="vertices_and_edges") return G.connected_components()
def coxeter_diagram(self): """ Returns a Coxeter diagram for type H. EXAMPLES:: sage: ct = CartanType(['H',3]) sage: ct.coxeter_diagram() Graph on 3 vertices sage: sorted(ct.coxeter_diagram().edges()) [(1, 2, 3), (2, 3, 5)] sage: ct.coxeter_matrix() [1 3 2] [3 1 5] [2 5 1] sage: ct = CartanType(['H',4]) sage: ct.coxeter_diagram() Graph on 4 vertices sage: sorted(ct.coxeter_diagram().edges()) [(1, 2, 3), (2, 3, 3), (3, 4, 5)] sage: ct.coxeter_matrix() [1 3 2 2] [3 1 3 2] [2 3 1 5] [2 2 5 1] """ from sage.graphs.graph import Graph n = self.n g = Graph(multiedges=False) for i in range(1, n): g.add_edge(i, i+1, 3) g.set_edge_label(n-1, n, 5) return g
def __classcall_private__(cls, G): """ Normalize input to ensure a unique representation. TESTS:: sage: G1 = RightAngledArtinGroup(graphs.CycleGraph(5)) sage: Gamma = Graph([(0,1),(1,2),(2,3),(3,4),(4,0)]) sage: G2 = RightAngledArtinGroup(Gamma) sage: G3 = RightAngledArtinGroup([(0,1),(1,2),(2,3),(3,4),(4,0)]) sage: G1 is G2 and G2 is G3 True Handle the empty graph:: sage: RightAngledArtinGroup(Graph()) Traceback (most recent call last): ... ValueError: the graph must not be empty """ if not isinstance(G, Graph): G = Graph(G, immutable=True) else: G = G.copy(immutable=True) if G.num_verts() == 0: raise ValueError("the graph must not be empty") return super(RightAngledArtinGroup, cls).__classcall__(cls, G)
def hamiltonian_cycle(self, algorithm = "tsp", *largs, **kargs): store = lookup(kargs, "store", default = discretezoo.WRITE_TO_DB, destroy = True) cur = lookup(kargs, "cur", default = None, destroy = True) default = len(largs) + len(kargs) == 0 and \ algorithm in ["tsp", "backtrack"] if default: if algorithm == "tsp": try: out = Graph.hamiltonian_cycle(self, algorithm, *largs, **kargs) h = True except EmptySetError as out: h = False elif algorithm == "backtrack": out = Graph.hamiltonian_cycle(self, algorithm, *largs, **kargs) h = out[0] try: lookup(self._graphprops, "is_hamiltonian") except KeyError: if store: self._update_rows(ZooGraph, {"is_hamiltonian": h}, {self._spec["primary_key"]: self._zooid}, cur = cur) update(self._graphprops, "is_hamiltonian", h) if isinstance(out, BaseException): raise out else: return out else: return Graph.hamiltonian_cycle(self, algorithm, *largs, **kargs)
def edge_coloring(self): r""" Compute a proper edge-coloring. A proper edge-coloring is an assignment of colors to the sets of the incidence structure such that two sets with non-empty intersection receive different colors. The coloring returned minimizes the number of colors. OUTPUT: A partition of the sets into color classes. EXAMPLES:: sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{4,5,6}]); H Incidence structure with 6 points and 4 blocks sage: C = H.edge_coloring() sage: C # random [[[3, 4, 5]], [[2, 3, 4]], [[4, 5, 6], [1, 2, 3]]] sage: Set(map(Set,sum(C,[]))) == Set(map(Set,H.blocks())) True """ from sage.graphs.graph import Graph blocks = self.blocks() blocks_sets = map(frozenset,blocks) g = Graph([range(self.num_blocks()),lambda x,y : len(blocks_sets[x]&blocks_sets[y])],loops = False) return [[blocks[i] for i in C] for C in g.coloring(algorithm="MILP")]
def CompleteMultipartiteGraph(l): r""" Returns a complete multipartite graph. INPUT: - ``l`` -- a list of integers : the respective sizes of the components. EXAMPLE: A complete tripartite graph with sets of sizes `5, 6, 8`:: sage: g = graphs.CompleteMultipartiteGraph([5, 6, 8]); g Multipartite Graph with set sizes [5, 6, 8]: Graph on 19 vertices It clearly has a chromatic number of 3:: sage: g.chromatic_number() 3 """ g = Graph() for i in l: g = g + CompleteGraph(i) g = g.complement() g.name("Multipartite Graph with set sizes "+str(l)) return g
def coxeter_diagram(self): """ Return the Coxeter diagram for ``self``. EXAMPLES:: sage: cd = CartanType("A2xB2xF4").coxeter_diagram() sage: cd Graph on 8 vertices sage: cd.edges() [(1, 2, 3), (3, 4, 4), (5, 6, 3), (6, 7, 4), (7, 8, 3)] sage: CartanType("F4xA2").coxeter_diagram().edges() [(1, 2, 3), (2, 3, 4), (3, 4, 3), (5, 6, 3)] sage: cd = CartanType("A1xH3").coxeter_diagram(); cd Graph on 4 vertices sage: cd.edges() [(2, 3, 3), (3, 4, 5)] """ from sage.graphs.graph import Graph relabelling = self._index_relabelling g = Graph(multiedges=False) g.add_vertices(self.index_set()) for i,t in enumerate(self._types): for [e1, e2, l] in t.coxeter_diagram().edges(): g.add_edge(relabelling[i,e1], relabelling[i,e2], label=l) return g
def to_bipartite_graph(self, with_partition=False): r""" Returns the associated bipartite graph INPUT: - with_partition -- boolean (default: False) OUTPUT: - a graph or a pair (graph, partition) EXAMPLES:: sage: H = designs.steiner_triple_system(7).blocks() sage: H = Hypergraph(H) sage: g = H.to_bipartite_graph(); g Graph on 14 vertices sage: g.is_regular() True """ from sage.graphs.graph import Graph G = Graph() domain = list(self.domain()) G.add_vertices(domain) for s in self._sets: for i in s: G.add_edge(s, i) if with_partition: return (G, [domain, list(self._sets)]) else: return G
def cluster_in_box(self, m, pt=None): r""" Return the cluster (as a list) in the primal box [-m,m]^d containing the point pt. INPUT: - ``m`` - integer - ``pt`` - tuple, point in Z^d. If None, pt=zero is considered. EXAMPLES:: sage: from slabbe import BondPercolationSample sage: S = BondPercolationSample(0.3,2) sage: S.cluster_in_box(2) # random [(-2, -2), (-2, -1), (-1, -2), (-1, -1), (-1, 0), (0, 0)] """ G = Graph() G.add_edges(self.edges_in_box(m)) if pt is None: pt = self.zero() if pt in G: return G.connected_component_containing_vertex(pt) else: return []
def edge_coloring(self): r""" Compute a proper edge-coloring. A proper edge-coloring is an assignment of colors to the sets of the hypergraph such that two sets with non-empty intersection receive different colors. The coloring returned minimizes the number of colors. OUTPUT: A partition of the sets into color classes. EXAMPLES:: sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{4,5,6}]); H Hypergraph on 6 vertices containing 4 sets sage: C = H.edge_coloring() sage: C # random [[{3, 4, 5}], [{4, 5, 6}, {1, 2, 3}], [{2, 3, 4}]] sage: Set(sum(C,[])) == Set(H._sets) True """ from sage.graphs.graph import Graph g = Graph([self._sets,lambda x,y : len(x&y)],loops = False) return g.coloring(algorithm="MILP")
def coxeter_graph(self): """ Return the Coxeter graph of ``self``. EXAMPLES:: sage: C = CoxeterMatrix(['A',3]) sage: C.coxeter_graph() Graph on 3 vertices sage: C = CoxeterMatrix([['A',3],['A',1]]) sage: C.coxeter_graph() Graph on 4 vertices """ n = self.rank() I = self.index_set() val = lambda x: infinity if x == -1 else x G = Graph( [ (I[i], I[j], val((self._matrix)[i, j])) for i in range(n) for j in range(i) if self._matrix[i, j] not in [1, 2] ] ) G.add_vertices(I) return G.copy(immutable=True)
def to_undirected_graph(self): r""" Return the undirected graph obtained from the tree nodes and edges. The graph is endowed with an embedding, so that it will be displayed correctly. EXAMPLES:: sage: t = OrderedTree([]) sage: t.to_undirected_graph() Graph on 1 vertex sage: t = OrderedTree([[[]],[],[]]) sage: t.to_undirected_graph() Graph on 5 vertices If the tree is labelled, we use its labelling to label the graph. This will fail if the labels are not all distinct. Otherwise, we use the graph canonical labelling which means that two different trees can have the same graph. EXAMPLES:: sage: t = OrderedTree([[[]],[],[]]) sage: t.canonical_labelling().to_undirected_graph() Graph on 5 vertices TESTS:: sage: t.canonical_labelling().to_undirected_graph() == t.to_undirected_graph() False sage: OrderedTree([[],[]]).to_undirected_graph() == OrderedTree([[[]]]).to_undirected_graph() True sage: OrderedTree([[],[],[]]).to_undirected_graph() == OrderedTree([[[[]]]]).to_undirected_graph() False """ from sage.graphs.graph import Graph g = Graph() if self in LabelledOrderedTrees(): relabel = False else: self = self.canonical_labelling() relabel = True roots = [self] g.add_vertex(name=self.label()) emb = {self.label(): []} while roots: node = roots.pop() children = reversed([child.label() for child in node]) emb[node.label()].extend(children) for child in node: g.add_vertex(name=child.label()) emb[child.label()] = [node.label()] g.add_edge(child.label(), node.label()) roots.append(child) g.set_embedding(emb) if relabel: g = g.canonical_label() return g
def import_graphs(file, cl = ZooGraph, db = None, format = "sparse6", index = "index", verbose = False): r""" Import graphs from ``file`` into the database. This function is used to import new censuses of graphs and is not meant to be used by users of DiscreteZOO. To properly import the graphs, all graphs of the same order must be together in the file, and no graph of this order must be present in the database. INPUT: - ``file`` - the filename containing a graph in each line. - ``cl`` - the class to be used for imported graphs (default: ``ZooGraph``). - ``db`` - the database to import into. The default value of ``None`` means that the default database should be used. - ``format`` - the format the graphs are given in. If ``format`` is ``'graph6'`` or ``'sparse6'`` (default), then the graphs are read as strings, otherwised they are evaluated as Python expressions before being passed to Sage's ``Graph``. - ``index``: the name of the parameter of the constructor of ``cl`` to which the serial number of the graph of a given order is passed. - ``verbose``: whether to print information about the progress of importing (default: ``False``). """ info = ZooInfo(cl) if db is None: db = info.getdb() info.initdb(db = db, commit = False) previous = 0 i = 0 cur = db.cursor() with open(file) as f: for line in f: data = line.strip() if format not in ["graph6", "sparse6"]: data = eval(data) g = Graph(data) n = g.order() if n > previous: if verbose and previous > 0: print "Imported %d graphs of order %d" % (i, previous) previous = n i = 0 i += 1 cl(graph = g, order = n, cur = cur, db = db, **{index: i}) if verbose: print "Imported %d graphs of order %d" % (i, n) f.close() cur.close() db.commit()
def create_graph_from_model(self, solver, model): """ Given a model from the SAT solver, construct the graph. """ g = Graph() on_vertices = solver.get_objects_in_model(model, self, self.internal_graph.vertices()) on_edges = solver.get_objects_in_model(model, self, self.internal_graph.edges(labels=False)) g.add_vertices(on_vertices) g.add_edges(on_edges) return g
def coxeter_graph(self): """ Return the Coxeter graph of ``self``. EXAMPLES:: sage: W = CoxeterGroup(['H',3], implementation="reflection") sage: G = W.coxeter_graph(); G Graph on 3 vertices sage: G.edges() [(1, 2, None), (2, 3, 5)] sage: CoxeterGroup(G) is W True sage: G = Graph([(0, 1, 3), (1, 2, oo)]) sage: W = CoxeterGroup(G) sage: W.coxeter_graph() == G True sage: CoxeterGroup(W.coxeter_graph()) is W True """ G = Graph() G.add_vertices(self.index_set()) for i, row in enumerate(self._matrix.rows()): for j, val in enumerate(row[i + 1 :]): if val == 3: G.add_edge(self._index_set[i], self._index_set[i + 1 + j]) elif val > 3: G.add_edge(self._index_set[i], self._index_set[i + 1 + j], val) elif val == -1: # FIXME: Hack because there is no ZZ\cup\{\infty\} G.add_edge(self._index_set[i], self._index_set[i + 1 + j], infinity) return G
def CircularLadderGraph(n): """ Returns a circular ladder graph with 2\*n nodes. A Circular ladder graph is a ladder graph that is connected at the ends, i.e.: a ladder bent around so that top meets bottom. Thus it can be described as two parallel cycle graphs connected at each corresponding node pair. This constructor depends on NetworkX numeric labels. PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the circular ladder graph is displayed as an inner and outer cycle pair, with the first n nodes drawn on the inner circle. The first (0) node is drawn at the top of the inner-circle, moving clockwise after that. The outer circle is drawn with the (n+1)th node at the top, then counterclockwise as well. EXAMPLES: Construct and show a circular ladder graph with 26 nodes :: sage: g = graphs.CircularLadderGraph(13) sage: g.show() # long time Create several circular ladder graphs in a Sage graphics array :: sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.CircularLadderGraph(i+3) ....: g.append(k) sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = sage.plot.graphics.GraphicsArray(j) sage: G.show() # long time """ pos_dict = {} for i in range(n): x = float(cos((pi/2) + ((2*pi)/n)*i)) y = float(sin((pi/2) + ((2*pi)/n)*i)) pos_dict[i] = [x,y] for i in range(n,2*n): x = float(2*(cos((pi/2) + ((2*pi)/n)*(i-n)))) y = float(2*(sin((pi/2) + ((2*pi)/n)*(i-n)))) pos_dict[i] = (x,y) G = Graph(pos=pos_dict, name="Circular Ladder graph") G.add_vertices( range(2*n) ) G.add_cycle( range(n) ) G.add_cycle( range(n,2*n) ) G.add_edges( (i,i+n) for i in range(n) ) return G
def __init__( self, data=None, zooid=None, props=None, graph=None, vertex_labels=None, name=None, cur=None, db=None, **kargs ): ZooObject.__init__(self, db) kargs["immutable"] = True kargs["data_structure"] = "static_sparse" if isinteger(data): zooid = Integer(data) data = None elif isinstance(data, GenericGraph): graph = data data = None elif isinstance(data, dict): props = data data = None if props is not None: if "id" in props: zooid = props["id"] if "data" in props: data = props["data"] props = {k: v for k, v in props.items() if k not in ["id", "data"]} if graph is not None: if not isinstance(graph, GenericGraph): raise TypeError("not a graph") data = graph if name is None: name = graph.name() if isinstance(graph, ZooGraph): zooid = graph._zooid self._props = graph._props if cur is not None: if self._props is None: self._props = {} self._props["diameter"] = graph.diameter() self._props["girth"] = graph.girth() self._props["order"] = graph.order() elif zooid is None: raise IndexError("graph id not given") else: cur = None if props is not None: self._props = self._todict(props, skip=ZooGraph._spec["skip"], fields=ZooGraph._spec["fields"]) self._zooid = zooid if data is None: data = self._db_read()["data"] if vertex_labels is not None: data = Graph(data).relabel(vertex_labels, inplace=False) Graph.__init__(self, data=data, name=name, **kargs) if cur is not None: self._db_write(cur)
def _polar_graph(m, q, g, intersection_size=None): r""" The helper function to build graphs `(D)U(m,q)` and `(D)Sp(m,q)` Building a graph on an orbit of a group `g` of `m\times m` matrices over `GF(q)` on the points (or subspaces of dimension ``m//2``) isotropic w.r.t. the form `F` left invariant by the group `g`. The only constraint is that the first ``m//2`` elements of the standard basis must generate a totally isotropic w.r.t. `F` subspace; this is the case with these groups coming from GAP; namely, `F` has the anti-diagonal all-1 matrix. INPUT: - ``m`` -- the dimension of the underlying vector space - ``q`` -- the size of the field - ``g`` -- the group acting - ``intersection_size`` -- if ``None``, build the graph on the isotropic points, with adjacency being orthogonality w.r.t. `F`. Otherwise, build the graph on the maximal totally isotropic subspaces, with adjacency specified by ``intersection_size`` being as given. TESTS:: sage: from sage.graphs.generators.classical_geometries import _polar_graph sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2)) Graph on 45 vertices sage: _polar_graph(4, 4, libgap.GeneralUnitaryGroup(4, 2), intersection_size=1) Graph on 27 vertices """ from sage.libs.gap.libgap import libgap from itertools import combinations W=libgap.FullRowSpace(libgap.GF(q), m) # F_q^m B=libgap.Elements(libgap.Basis(W)) # the standard basis of W V = libgap.Orbit(g,B[0],libgap.OnLines) # orbit on isotropic points gp = libgap.Action(g,V,libgap.OnLines) # make a permutation group s = libgap.Subspace(W,[B[i] for i in range(m//2)]) # a totally isotropic subspace # and the points there sp = [libgap.Elements(libgap.Basis(x))[0] for x in libgap.Elements(s.Subspaces(1))] h = libgap.Set(map(lambda x: libgap.Position(V, x), sp)) # indices of the points in s L = libgap.Orbit(gp, h, libgap.OnSets) # orbit on these subspaces if intersection_size == None: G = Graph() for x in L: # every pair of points in the subspace is adjacent to each other in G G.add_edges(combinations(x, 2)) return G else: return Graph([L, lambda i,j: libgap.Size(libgap.Intersection(i,j))==intersection_size], loops=False)
def CayleyGraph(vspace, gens, directed=False): """ Generate a Cayley Graph over given vector space with edges generated by given generators. The graph is optionally directed. Try e.g. CayleyGraph(VectorSpace(GF(2), 3), [(1,0,0), (0,1,0), (0,0,1)]) """ G = Graph() for v in vspace: G.add_vertex(tuple(v)) for g in gens: g2 = vspace(g) G.add_edge(tuple(v), tuple(v + g2)) return G
def graph6_to_plot(graph6): """ Constructs a graph from a graph6 string and returns a Graphics object with arguments preset for show function. EXAMPLE:: sage: from sage.graphs.graph_database import graph6_to_plot sage: type(graph6_to_plot('D??')) <class 'sage.plot.graphics.Graphics'> """ g = Graph(str(graph6)) return g.plot(layout='circular',vertex_size=30,vertex_labels=False,graph_border=False)
def IntersectionGraph(S): r""" Returns the intersection graph of the family `S` The intersection graph of a family `S` is a graph `G` with `V(G)=S` such that two elements `s_1,s_2\in S` are adjacent in `G` if and only if `s_1\cap s_2\neq \emptyset`. INPUT: - ``S`` -- a list of sets/tuples/iterables .. NOTE:: The elements of `S` must be finite, hashable, and the elements of any `s\in S` must be hashable too. EXAMPLE:: sage: graphs.IntersectionGraph([(1,2,3),(3,4,5),(5,6,7)]) Intersection Graph: Graph on 3 vertices TESTS:: sage: graphs.IntersectionGraph([(1,2,[1])]) Traceback (most recent call last): ... TypeError: The elements of S must be hashable, and this one is not: (1, 2, [1]) """ from itertools import combinations for s in S: try: hash(s) except TypeError: raise TypeError("The elements of S must be hashable, and this one is not: {}".format(s)) ground_set_to_sets = {} for s in S: for x in s: if x not in ground_set_to_sets: ground_set_to_sets[x] = [] ground_set_to_sets[x].append(s) g = Graph(name="Intersection Graph") g.add_vertices(S) for clique in ground_set_to_sets.itervalues(): g.add_edges((u,v) for u,v in combinations(clique,2)) return g
def is_regular(self, k = None, *largs, **kargs): store = lookup(kargs, "store", default = discretezoo.WRITE_TO_DB, destroy = True) cur = lookup(kargs, "cur", default = None, destroy = True) default = len(largs) + len(kargs) == 0 try: if not default: raise NotImplementedError r = lookup(self._graphprops, "is_regular") return r and (True if k is None else k == self.average_degree(store = store, cur = cur)) except (KeyError, NotImplementedError): r = Graph.is_regular(self, k, *largs, **kargs) if default: if store: row = {"is_regular": r} if r and k is not None: row["average_degree"] = k self._update_rows(ZooGraph, row, {self._spec["primary_key"]: self._zooid}, cur = cur) update(self._graphprops, "is_regular", r) if r and k is not None: update(self._graphprops, "average_degree", k) return r
def _spring_layout(self): r""" Return a spring layout for the vertices. The layout is computed by creating a graph `G` on the vertices *and* sets of the hypergraph. Each set is then made adjacent in `G` with all vertices it contains before a spring layout is computed for this graph. The position of the vertices in the hypergraph is the position of the same vertices in the graph's layout. .. NOTE:: This method also returns the position of the "fake" vertices, i.e. those representing the sets. EXAMPLES:: sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{4,5,6}]); H Hypergraph on 6 vertices containing 4 sets sage: L = H._spring_layout() sage: L # random {1: (0.238, -0.926), 2: (0.672, -0.518), 3: (0.449, -0.225), 4: (0.782, 0.225), 5: (0.558, 0.518), 6: (0.992, 0.926), {3, 4, 5}: (0.504, 0.173), {2, 3, 4}: (0.727, -0.173), {4, 5, 6}: (0.838, 0.617), {1, 2, 3}: (0.393, -0.617)} sage: all(v in L for v in H.domain()) True sage: all(v in L for v in H._sets) True """ from sage.graphs.graph import Graph g = Graph() for s in self._sets: for x in s: g.add_edge(s,x) _ = g.plot(iterations = 50000,save_pos=True) # The values are rounded as TikZ does not like accuracy. return {k:(round(x,3),round(y,3)) for k,(x,y) in g.get_pos().items()}
def LadderGraph(n): """ Returns a ladder graph with 2\*n nodes. A ladder graph is a basic structure that is typically displayed as a ladder, i.e.: two parallel path graphs connected at each corresponding node pair. This constructor depends on NetworkX numeric labels. PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, each ladder graph will be displayed horizontally, with the first n nodes displayed left to right on the top horizontal line. EXAMPLES: Construct and show a ladder graph with 14 nodes :: sage: g = graphs.LadderGraph(7) sage: g.show() # long time Create several ladder graphs in a Sage graphics array :: sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.LadderGraph(i+2) ....: g.append(k) sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = sage.plot.graphics.GraphicsArray(j) sage: G.show() # long time """ pos_dict = {} for i in range(n): pos_dict[i] = (i,1) for i in range(n,2*n): x = i - n pos_dict[i] = (x,0) G = Graph(pos=pos_dict, name="Ladder graph") G.add_vertices( range(2*n) ) G.add_path( range(n) ) G.add_path( range(n,2*n) ) G.add_edges( (i,i+n) for i in range(n) ) return G
def read_mtx(f): contents = f.readlines() edges = [] first = 0 for i in range(len(contents)): words = contents[i].split() if words[0][0] != '%': if first == 0: first = 1 else: if(len(words) == 3): edges.append((int(words[0]), int(words[1]), float(words[2]))) else: edges.append((int(words[0]), int(words[1]), None)) g = Graph() g.add_edges(edges) return g
def relabel(self, perm = None, inplace = True, return_map = False, check_input = True, complete_partial_function = True, immutable = True): r""" This method has been overridden by DiscreteZOO to ensure that a mutable copy will have type ``Graph``. """ if inplace: raise ValueError("To relabel an immutable graph use inplace=False") G = Graph(self, immutable = False) perm = G.relabel(perm, return_map = True, check_input = check_input, complete_partial_function = complete_partial_function) if immutable is not False: G = self.__class__(self, vertex_labels = perm) if return_map: return G, perm else: return G
def __init__(self, G): """ Initialize ``self``. INPUT: - ``G`` -- a graph TESTS:: sage: G = RightAngledArtinGroup(graphs.CycleGraph(5)) sage: TestSuite(G).run() """ self._graph = G F = FreeGroup(names=['v{}'.format(v) for v in self._graph.vertices()]) CG = Graph(G).complement() # Make sure it's mutable CG.relabel() # Standardize the labels rels = tuple(F([i+1, j+1, -i-1, -j-1]) for i,j in CG.edges(False)) #+/- 1 for indexing FinitelyPresentedGroup.__init__(self, F, rels)
def second_dist_to_set(G, v, W): """ For vertices adjacent to W, return the lenght of the second shortest path to W. Otherwise return G.order(). WARNING: Not very efficient. """ if v in W: return 0 # Neighbors in W nw = set(G.neighbors(v)).intersection(set(W)) if len(nw) == 0: return G.order() if len(nw) >= 2: return 1 G2 = Graph(G) # always undirected, copy G2.delete_edge(v, nw.pop()) ds2 = G2.distance_all_pairs() dist2 = min([ds2[v][u] for u in W]) assert dist2 >= 2 return dist2
def underlying_graph(G): r""" Given a graph `G` with multi-edges, returns a graph where all the multi-edges are replaced with a single edge. EXAMPLES:: sage: from sage.graphs.tutte_polynomial import underlying_graph sage: G = Graph(multiedges=True) sage: G.add_edges([(0,1,'a'),(0,1,'b')]) sage: G.edges() [(0, 1, 'a'), (0, 1, 'b')] sage: underlying_graph(G).edges() [(0, 1, None)] """ g = Graph() g.allow_loops(True) for edge in set(G.edges(labels=False)): g.add_edge(edge) return g
def _graphattr(store=False, *largs, **kargs): default = len(largs) + len(kargs) == 0 try: if not default: raise NotImplementedError return lookup(self._props, name) except (KeyError, NotImplementedError): a = Graph.__getattribute__(self, name)(*largs, **kargs) if default and store: update(self._props, attr, d) return a
def _spanning_tree(base, verts): graph = Graph([list(verts), lambda x, y: x is not y]) def length(edge): x, y, _ = edge return abs(CC(x.value) - CC(y.value)) tree = graph.min_spanning_tree(length) tree = Graph(tree) tree.add_vertex(base) return tree
def to_graph(self): r""" Returns the graph corresponding to the perfect matching. OUTPUT: The realization of ``self`` as a graph. EXAMPLES:: sage: PerfectMatching([[1,3], [4,2]]).to_graph().edges(labels=False) [(1, 3), (2, 4)] sage: PerfectMatching([[1,4], [3,2]]).to_graph().edges(labels=False) [(1, 4), (2, 3)] sage: PerfectMatching([]).to_graph().edges(labels=False) [] """ from sage.graphs.graph import Graph G = Graph() for a, b in self.value: G.add_edge((a, b)) return G
def is_connected(self, force_computation=False): if not force_computation and self._connected: return True from sage.graphs.graph import Graph G = Graph(loops=True, multiedges=True) for i in range(self._total_darts): if self._active_darts[i]: G.add_edge(i,self._vertices[i]) G.add_edge(i,self._edges[i]) G.add_edge(i,self._faces[i]) return G.is_connected()
def TetrahedralGraph(): """ Return a tetrahedral graph (with 4 nodes). A tetrahedron is a 4-sided triangular pyramid. The tetrahedral graph corresponds to the connectivity of the vertices of the tetrahedron. This graph is equivalent to a wheel graph with 4 nodes and also a complete graph on four nodes. (See examples below). PLOTTING: The Tetrahedral graph should be viewed in 3 dimensions. We choose to use a planar embedding of the graph. We hope to add rotatable, 3-dimensional viewing in the future. In such a case, a argument will be added to select the desired layout. EXAMPLES: Construct and show a Tetrahedral graph:: sage: g = graphs.TetrahedralGraph() sage: g.show() # long time The following example requires networkx:: sage: import networkx as NX Compare this Tetrahedral, Wheel(4), Complete(4), and the Tetrahedral plotted with the spring-layout algorithm below in a Sage graphics array:: sage: tetra_pos = graphs.TetrahedralGraph() sage: tetra_spring = Graph(NX.tetrahedral_graph()) sage: wheel = graphs.WheelGraph(4) sage: complete = graphs.CompleteGraph(4) sage: g = [tetra_pos, tetra_spring, wheel, complete] sage: j = [] sage: for i in range(2): ....: n = [] ....: for m in range(2): ....: n.append(g[i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) sage: G.show() # long time """ edges = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] pos = { 0: (0, 0), 1: (0, 1), 2: (cos(3.5 * pi / 3), sin(3.5 * pi / 3)), 3: (cos(5.5 * pi / 3), sin(5.5 * pi / 3)) } return Graph(edges, name="Tetrahedron", pos=pos)
def graph6_to_plot(graph6): """ Return a ``Graphics`` object from a ``graph6`` string. This method constructs a graph from a ``graph6`` string and returns a :class:`sage.plot.graphics.Graphics` object with arguments preset for the :meth:`sage.plot.graphics.Graphics.show` method. INPUT: - ``graph6`` -- a ``graph6`` string EXAMPLES:: sage: from sage.graphs.graph_database import graph6_to_plot sage: type(graph6_to_plot('D??')) <class 'sage.plot.graphics.Graphics'> """ g = Graph(str(graph6)) return g.plot(layout='circular', vertex_size=30, vertex_labels=False, graph_border=False)
def construct_spx(spx, max=Integer(1280)): for r in range(3, max / 4 + 1): spx[r] = {} s = Integer(1) m = Integer(4) * r while m <= max: c = sum([[(tuple(v), n) for n in Integers(r)] for v in Integers(2)**Integer(s)], []) c = [(v, n, Integer(1)) for v, n in c] + [(v, n, Integer(-1)) for v, n in c] spx[r][s] = Graph([c, spx_adj]) s += 1 m *= 2 print "Finished r = %d, constructed %d graphs" % (r, len(spx[r]))
def RandomRegular(d, n, seed=None): """ Returns a random d-regular graph on n vertices, or returns False on failure. Since every edge is incident to two vertices, n\*d must be even. INPUT: - ``n`` - number of vertices - ``d`` - degree - ``seed`` - for the random number generator EXAMPLE: We show the edge list of a random graph with 8 nodes each of degree 3. :: sage: graphs.RandomRegular(3, 8).edges(labels=False) [(0, 1), (0, 4), (0, 7), (1, 5), (1, 7), (2, 3), (2, 5), (2, 6), (3, 4), (3, 6), (4, 5), (6, 7)] :: sage: G = graphs.RandomRegular(3, 20) sage: if G: ....: G.show() # random output, long time REFERENCES: .. [KimVu2003] Kim, Jeong Han and Vu, Van H. Generating random regular graphs. Proc. 35th ACM Symp. on Thy. of Comp. 2003, pp 213-222. ACM Press, San Diego, CA, USA. http://doi.acm.org/10.1145/780542.780576 .. [StegerWormald1999] Steger, A. and Wormald, N. Generating random regular graphs quickly. Prob. and Comp. 8 (1999), pp 377-396. """ if seed is None: seed = current_randstate().long_seed() import networkx try: N = networkx.random_regular_graph(d, n, seed=seed) if N is False: return False return Graph(N, sparse=True) except Exception: return False
def relabel(self, perm=None, inplace=True, return_map=False, check_input=True, complete_partial_function=True, immutable=True): r""" This method has been overridden by DiscreteZOO to ensure that a mutable copy will have type ``Graph``. """ if inplace: raise ValueError("To relabel an immutable graph use inplace=False") G = Graph(self, immutable=False) perm = G.relabel(perm, return_map=True, check_input=check_input, complete_partial_function=complete_partial_function) if immutable is not False: G = self.__class__(self, vertex_labels=perm) if return_map: return G, perm else: return G
def DegreeSequenceConfigurationModel(deg_sequence, seed=None): """ Returns a random pseudograph with the given degree sequence. Raises a NetworkX error if the proposed degree sequence cannot be that of a graph with multiple edges and loops. One requirement is that the sum of the degrees must be even, since every edge must be incident with two vertices. INPUT: - ``deg_sequence`` - a list of integers with each entry corresponding to the expected degree of a different vertex. - ``seed`` - a ``random.Random`` seed or a Python ``int`` for the random number generator (default: ``None``). EXAMPLES:: sage: G = graphs.DegreeSequenceConfigurationModel([1,1]) sage: G.adjacency_matrix() [0 1] [1 0] Note: as of this writing, plotting of loops and multiple edges is not supported, and the output is allowed to contain both types of edges. :: sage: G = graphs.DegreeSequenceConfigurationModel([3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]) sage: len(G.edges()) 30 sage: G.show() # long time REFERENCE: [New2003]_ """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) import networkx return Graph(networkx.configuration_model([int(i) for i in deg_sequence], seed=seed), loops=True, multiedges=True, sparse=True)
def DegreeSequenceConfigurationModel(deg_sequence, seed=None): """ Returns a random pseudograph with the given degree sequence. Raises a NetworkX error if the proposed degree sequence cannot be that of a graph with multiple edges and loops. One requirement is that the sum of the degrees must be even, since every edge must be incident with two vertices. INPUT: - ``deg_sequence`` - a list of integers with each entry corresponding to the expected degree of a different vertex. - ``seed`` - for the random number generator. EXAMPLES:: sage: G = graphs.DegreeSequenceConfigurationModel([1,1]) sage: G.adjacency_matrix() [0 1] [1 0] Note: as of this writing, plotting of loops and multiple edges is not supported, and the output is allowed to contain both types of edges. :: sage: G = graphs.DegreeSequenceConfigurationModel([3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]) sage: G.edges(labels=False) [(0, 2), (0, 10), (0, 15), (1, 6), (1, 16), (1, 17), (2, 5), (2, 19), (3, 7), (3, 14), (3, 14), (4, 9), (4, 13), (4, 19), (5, 6), (5, 15), (6, 11), (7, 11), (7, 17), (8, 11), (8, 18), (8, 19), (9, 12), (9, 13), (10, 15), (10, 18), (12, 13), (12, 16), (14, 17), (16, 18)] sage: G.show() # long time REFERENCE: .. [Newman2003] Newman, M.E.J. The Structure and function of complex networks, SIAM Review vol. 45, no. 2 (2003), pp. 167-256. """ if seed is None: seed = current_randstate().long_seed() import networkx return Graph(networkx.configuration_model([int(i) for i in deg_sequence], seed=seed), loops=True, multiedges=True, sparse=True)
def LadderGraph(n): r""" Return a ladder graph with `2 * n` nodes. A ladder graph is a basic structure that is typically displayed as a ladder, i.e.: two parallel path graphs connected at each corresponding node pair. PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, each ladder graph will be displayed horizontally, with the first n nodes displayed left to right on the top horizontal line. EXAMPLES: Construct and show a ladder graph with 14 nodes:: sage: g = graphs.LadderGraph(7) sage: g.show() # long time Create several ladder graphs in a Sage graphics array:: sage: g = [] sage: j = [] sage: for i in range(9): ....: k = graphs.LadderGraph(i+2) ....: g.append(k) sage: for i in range(3): ....: n = [] ....: for m in range(3): ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False)) ....: j.append(n) sage: G = graphics_array(j) sage: G.show() # long time """ pos_dict = {} for i in range(n): pos_dict[i] = (i, 1) for i in range(n, 2 * n): x = i - n pos_dict[i] = (x, 0) G = Graph(2 * n, pos=pos_dict, name="Ladder graph") G.add_path(list(range(n))) G.add_path(list(range(n, 2 * n))) G.add_edges((i, i + n) for i in range(n)) return G
def automorphism_group(self): r""" The automorphism group of the graph. EXAMPLES: :: sage: from boolean_cayley_graphs.royle_x_graph import royle_x_graph sage: g = royle_x_graph() sage: from boolean_cayley_graphs.strongly_regular_graph import StronglyRegularGraph sage: srg = StronglyRegularGraph(g) sage: srg.automorphism_group Permutation Group with generators [(11,21)(12,22)(13,23)(14,24)(15,25)(16,26)(17,27)(18,28)(19,29)(20,30)(36,37)(44,49)(45,50)(46,51)(47,52)(48,53), (5,11)(6,12)(7,13)(8,14)(9,15)(10,16)(27,31)(28,32)(29,33)(30,34)(37,38)(43,44)(50,54)(51,55)(52,56)(53,57), (3,4)(6,7)(8,9)(12,13)(14,15)(17,18)(22,23)(24,25)(27,28)(31,32)(41,42)(47,48)(52,53)(56,57)(59,60)(61,62), (2,3)(5,6)(9,10)(11,12)(15,16)(18,19)(21,22)(25,26)(28,29)(32,33)(40,41)(46,47)(51,52)(55,56)(58,59)(62,63), (2,5)(3,6)(4,7)(14,17)(15,18)(16,19)(24,27)(25,28)(26,29)(34,35)(38,39)(44,45)(49,50)(55,58)(56,59)(57,60), (1,2)(6,8)(7,9)(12,14)(13,15)(19,20)(22,24)(23,25)(29,30)(33,34)(39,40)(45,46)(50,51)(54,55)(59,61)(60,62), (1,20)(2,19)(3,18)(4,17)(5,16)(6,15)(7,14)(8,13)(9,12)(10,11)(37,43)(38,44)(39,45)(40,46)(41,47)(42,48), (0,1)(2,38,4,36)(3,37)(5,57,23,46)(6,53,22,51)(7,48,21,55)(8,17,26,33)(9,27,25,29)(10,31,24,19)(11,56,13,47)(12,52)(14,18,16,32)(15,28)(20,58,34,60)(30,59)(35,39)(40,43,42,49)(41,44)(45,63,54,61)(50,62)] """ return Graph.automorphism_group(self)
def RandomNewmanWattsStrogatz(n, k, p, seed=None): """ Returns a Newman-Watts-Strogatz small world random graph on n vertices. From the NetworkX documentation: First create a ring over n nodes. Then each node in the ring is connected with its k nearest neighbors. Then shortcuts are created by adding new edges as follows: for each edge u-v in the underlying "n-ring with k nearest neighbors"; with probability p add a new edge u-w with randomly-chosen existing node w. In contrast with watts_strogatz_graph(), no edges are removed. INPUT: - ``n`` - number of vertices. - ``k`` - each vertex is connected to its k nearest neighbors - ``p`` - the probability of adding a new edge for each edge - ``seed`` - for the random number generator EXAMPLE: We show the edge list of a random graph on 7 nodes with 2 "nearest neighbors" and probability `p = 0.2`:: sage: graphs.RandomNewmanWattsStrogatz(7, 2, 0.2).edges(labels=False) [(0, 1), (0, 2), (0, 3), (0, 6), (1, 2), (2, 3), (2, 4), (3, 4), (3, 6), (4, 5), (5, 6)] :: sage: G = graphs.RandomNewmanWattsStrogatz(12, 2, .3) sage: G.show() # long time REFERENCE: .. [NWS99] Newman, M.E.J., Watts, D.J. and Strogatz, S.H. Random graph models of social networks. Proc. Nat. Acad. Sci. USA 99, 2566-2572. """ if seed is None: seed = current_randstate().long_seed() import networkx return Graph(networkx.newman_watts_strogatz_graph(n, k, p, seed=seed))
def ButterflyGraph(): r""" Return the butterfly graph. Let `C_3` be the cycle graph on 3 vertices. The butterfly or bowtie graph is obtained by joining two copies of `C_3` at a common vertex, resulting in a graph that is isomorphic to the friendship graph `F_2`. See the :wikipedia:`Butterfly_graph` for more information. .. SEEALSO:: - :meth:`GraphGenerators.FriendshipGraph` EXAMPLES: The butterfly graph is a planar graph on 5 vertices and having 6 edges:: sage: G = graphs.ButterflyGraph(); G Butterfly graph: Graph on 5 vertices sage: G.show() # long time sage: G.is_planar() True sage: G.order() 5 sage: G.size() 6 It has diameter 2, girth 3, and radius 1:: sage: G.diameter() 2 sage: G.girth() 3 sage: G.radius() 1 The butterfly graph is Eulerian, with chromatic number 3:: sage: G.is_eulerian() True sage: G.chromatic_number() 3 """ edge_dict = {0: [3, 4], 1: [2, 4], 2: [4], 3: [4]} pos_dict = {0: [-1, 1], 1: [1, 1], 2: [1, -1], 3: [-1, -1], 4: [0, 0]} return Graph(edge_dict, pos=pos_dict, name="Butterfly graph")
def DegreeSequence(deg_sequence): """ Returns a graph with the given degree sequence. Raises a NetworkX error if the proposed degree sequence cannot be that of a graph. Graph returned is the one returned by the Havel-Hakimi algorithm, which constructs a simple graph by connecting vertices of highest degree to other vertices of highest degree, resorting the remaining vertices by degree and repeating the process. See Theorem 1.4 in [CharLes1996]_. INPUT: - ``deg_sequence`` - a list of integers with each entry corresponding to the degree of a different vertex. EXAMPLES:: sage: G = graphs.DegreeSequence([3,3,3,3]) sage: G.edges(labels=False) [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] sage: G.show() # long time :: sage: G = graphs.DegreeSequence([3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]) sage: G.show() # long time :: sage: G = graphs.DegreeSequence([4,4,4,4,4,4,4,4]) sage: G.show() # long time :: sage: G = graphs.DegreeSequence([1,2,3,4,3,4,3,2,3,2,1]) sage: G.show() # long time REFERENCE: .. [CharLes1996] Chartrand, G. and Lesniak, L.: Graphs and Digraphs. Chapman and Hall/CRC, 1996. """ import networkx return Graph(networkx.havel_hakimi_graph([int(i) for i in deg_sequence]))
def coxeter_diagram(self): """ Returns the Coxeter matrix for this type. EXAMPLES:: sage: ct = CartanType(['I', 4]) sage: ct.coxeter_diagram() Graph on 2 vertices sage: ct.coxeter_diagram().edges() [(1, 2, 4)] sage: ct.coxeter_matrix() [1 4] [4 1] """ from sage.graphs.graph import Graph return Graph([[1, 2, self.n]], multiedges=False)
def create_graph_from_model(self, solver, model): ''' Given a model from the SAT solver, construct the graph. ''' g = Graph() on_vertices = solver.get_objects_in_model( model, self, self.internal_graph.vertices()) on_edges = solver.get_objects_in_model( model, self, self.internal_graph.edges(labels=False)) g.add_vertices(on_vertices) g.add_edges(on_edges) return g
def DegreeSequenceConfigurationModel(deg_sequence, seed=None): """ Return a random pseudograph with the given degree sequence. This method raises a NetworkX error if the proposed degree sequence cannot be that of a graph with multiple edges and loops. One requirement is that the sum of the degrees must be even, since every edge must be incident with two vertices. INPUT: - ``deg_sequence`` -- list of integers with each entry corresponding to the expected degree of a different vertex - ``seed`` -- (optional) a ``random.Random`` seed or a Python ``int`` for the random number generator EXAMPLES:: sage: G = graphs.DegreeSequenceConfigurationModel([1,1]) sage: G.adjacency_matrix() [0 1] [1 0] The output is allowed to contain both loops and multiple edges:: sage: deg_sequence = [3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3] sage: G = graphs.DegreeSequenceConfigurationModel(deg_sequence) sage: G.order(), G.size() (20, 30) sage: G.has_loops() or G.has_multiple_edges() # random True sage: G.show() # long time REFERENCE: [New2003]_ """ if seed is None: seed = int(current_randstate().long_seed() % sys.maxsize) import networkx deg_sequence = [int(i) for i in deg_sequence] return Graph(networkx.configuration_model(deg_sequence, seed=seed), loops=True, multiedges=True, sparse=True)
def _parse_db(self, directory): r""" Parses the ISGCI database and stores its content in ``self``. INPUT: - ``directory`` -- the name of the directory containing the latest version of the database. EXAMPLE:: sage: from sage.env import SAGE_SHARE sage: graph_classes._parse_db(os.path.join(SAGE_SHARE,'graphs')) """ import xml.etree.cElementTree as ET import os.path from sage.graphs.graph import Graph xml_file = os.path.join(SAGE_SHARE, 'graphs', _XML_FILE) tree = ET.ElementTree(file=xml_file) root = tree.getroot() DB = _XML_to_dict(root) giveme = lambda x, y: str(x.getAttribute(y)) classes = {c['id']: c for c in DB['GraphClasses']["GraphClass"]} for c in classes.itervalues(): c["problem"] = {pb.pop("name"): pb for pb in c["problem"]} inclusions = DB['Inclusions']['incl'] # Parses the list of ISGCI small graphs smallgraph_file = open( os.path.join(SAGE_SHARE, 'graphs', _SMALLGRAPHS_FILE), 'r') smallgraphs = {} for l in smallgraph_file.readlines(): key, string = l.split("\t") smallgraphs[key] = Graph(string) smallgraph_file.close() self.inclusions.set_cache(inclusions) self.classes.set_cache(classes) self.smallgraphs.set_cache(smallgraphs)
def get_graphs_list(self): """ Return a list of Sage Graph objects that satisfy the query. EXAMPLES:: sage: Q = GraphQuery(display_cols=['graph6', 'num_vertices', 'degree_sequence'], num_edges=['<=', 5], min_degree=1) sage: L = Q.get_graphs_list() sage: L[0] Graph on 2 vertices sage: len(L) 35 """ s = self.__query_string__ re.sub('SELECT.*FROM ', 'SELECT graph6 FROM ', s) q = GenericGraphQuery(s, self.__database__, self.__param_tuple__) graph6_list = q.query_results() return [Graph(str(g[0])) for g in graph6_list]
def IntersectionGraph(S): r""" Returns the intersection graph of the family `S` The intersection graph of a family `S` is a graph `G` with `V(G)=S` such that two elements `s_1,s_2\in S` are adjacent in `G` if and only if `s_1\cap s_2\neq \emptyset`. INPUT: - ``S`` -- a list of sets/tuples/iterables .. NOTE:: The elements of `S` must be finite, hashable, and the elements of any `s\in S` must be hashable too. EXAMPLES:: sage: graphs.IntersectionGraph([(1,2,3),(3,4,5),(5,6,7)]) Intersection Graph: Graph on 3 vertices TESTS:: sage: graphs.IntersectionGraph([(1,2,[1])]) Traceback (most recent call last): ... TypeError: The elements of S must be hashable, and this one is not: (1, 2, [1]) """ from itertools import combinations for s in S: try: hash(s) except TypeError: raise TypeError( "The elements of S must be hashable, and this one is not: {}". format(s)) ground_set_to_sets = {} for s in S: for x in s: if x not in ground_set_to_sets: ground_set_to_sets[x] = [] ground_set_to_sets[x].append(s) g = Graph(name="Intersection Graph") g.add_vertices(S) for clique in itervalues(ground_set_to_sets): g.add_clique(set(clique)) return g
def DartGraph(): """ Return a dart graph with 5 nodes. PLOTTING: Upon construction, the position dictionary is filled to override the spring-layout algorithm. By convention, the dart graph is drawn as a dart, with the sharp part on the bottom. EXAMPLES: Construct and show a dart graph:: sage: g = graphs.DartGraph() sage: g.show() # long time """ pos_dict = {0: (0, 1), 1: (-1, 0), 2: (1, 0), 3: (0, -1), 4: (0, 0)} edges = [(0, 1), (0, 2), (1, 4), (2, 4), (0, 4), (3, 4)] return Graph(edges, pos=pos_dict, name="Dart Graph")
def RandomTreePowerlaw(n, gamma=3, tries=100, seed=None): """ Returns a tree with a power law degree distribution. Returns False on failure. From the NetworkX documentation: A trial power law degree sequence is chosen and then elements are swapped with new elements from a power law distribution until the sequence makes a tree (size = order - 1). INPUT: - ``n`` - number of vertices - ``gamma`` - exponent of power law - ``tries`` - number of attempts to adjust sequence to make a tree - ``seed`` - for the random number generator EXAMPLE: We show the edge list of a random graph with 10 nodes and a power law exponent of 2. :: sage: graphs.RandomTreePowerlaw(10, 2).edges(labels=False) [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (6, 8), (6, 9)] :: sage: G = graphs.RandomTreePowerlaw(15, 2) sage: if G: ....: G.show() # random output, long time """ if seed is None: seed = current_randstate().long_seed() import networkx try: return Graph( networkx.random_powerlaw_tree(n, gamma, seed=seed, tries=tries)) except networkx.NetworkXError: return False
def _check_pbd(B, v, S): r""" Checks that ``B`` is a PBD on `v` points with given block sizes. INPUT: - ``bibd`` -- a list of blocks - ``v`` (integer) -- number of points - ``S`` -- list of integers EXAMPLE:: sage: designs.BalancedIncompleteBlockDesign(40,4).blocks() # indirect doctest [[0, 1, 2, 12], [0, 3, 6, 9], [0, 4, 8, 11], [0, 5, 7, 10], [0, 13, 26, 39], [0, 14, 28, 38], [0, 15, 25, 27], [0, 16, 32, 35], [0, 17, 34, 37], [0, 18, 33, 36], ... """ from itertools import combinations from sage.graphs.graph import Graph if not all(len(X) in S for X in B): raise RuntimeError( "This is not a nice honest PBD from the good old days !") g = Graph() m = 0 for X in B: g.add_edges(list(combinations(X, 2))) if g.size() != m + binomial(len(X), 2): raise RuntimeError( "This is not a nice honest PBD from the good old days !") m = g.size() if not (g.is_clique() and g.vertices() == range(v)): raise RuntimeError( "This is not a nice honest PBD from the good old days !") return B
def boolean_cayley_graph(dim, f): r""" Construct the Cayley graph of a Boolean function. Given the non-negative integer ``dim`` and the function ``f``, a Boolean function that takes a non-negative integer argument, the function ``Boolean_Cayley_graph`` constructs the Cayley graph of ``f`` as a Boolean function on :math:`\mathbb{F}_2^{dim}`, with the lexicographica ordering. The value ``f(0)`` is assumed to be ``0``, so the graph is always simple. INPUT: - ``dim`` -- integer. The Boolean dimension of the given function. - ``f`` -- function. A Boolean function expressed as a Python function taking non-negative integer arguments. OUTPUT: A ``Graph`` object representing the Cayley graph of ``f``. .. SEEALSO: :module:`sage.graphs.graph` EXAMPLES: The Cayley graph of the function ``f`` where :math:`f(n) = n \mod 2`. :: sage: from boolean_cayley_graphs.boolean_cayley_graph import boolean_cayley_graph sage: f = lambda n: n % 2 sage: g = boolean_cayley_graph(2, f) sage: g.adjacency_matrix() [0 1 0 1] [1 0 1 0] [0 1 0 1] [1 0 1 0] """ return Graph([srange(2 ** dim), lambda i, j: f(i ^ j)], format="rule", immutable=True)
def to_graph(self): r""" Return the graph corresponding to the perfect matching. OUTPUT: The realization of ``self`` as a graph. EXAMPLES:: sage: PerfectMatching([[1,3], [4,2]]).to_graph().edges(labels=False) [(1, 3), (2, 4)] sage: PerfectMatching([[1,4], [3,2]]).to_graph().edges(labels=False) [(1, 4), (2, 3)] sage: PerfectMatching([]).to_graph().edges(labels=False) [] """ from sage.graphs.graph import Graph return Graph([list(p) for p in self], format='list_of_edges')
def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, immutable=None, *largs, **kargs): r""" This method has been overridden by DiscreteZOO to ensure that the subgraph will have type ``Graph``. """ if immutable is None: immutable = True return Graph(self)._subgraph_by_adding(vertices=vertices, edges=edges, edge_property=edge_property, immutable=immutable, *largs, **kargs)
def independence_graph(self): r""" Return the digraph of independence relations. OUTPUT: Independence graph with generators as vertices. TESTS:: sage: from sage.monoids.trace_monoid import TraceMonoid sage: F.<a,b,c> = FreeMonoid() sage: M.<ai,bi,ci> = TraceMonoid(F, I=((a,c), (c,a))) sage: M.independence_graph() == Graph({a:[c], b:[], c:[]}) True """ verts = list(self._free_monoid.gens()) edges = list(map(list, self.independence())) return Graph([verts, edges], immutable=True)
def _spring_layout(self): r""" Return a spring layout for the vertices. The layout is computed by creating a graph `G` on the vertices *and* sets of the hypergraph. Each set is then made adjacent in `G` with all vertices it contains before a spring layout is computed for this graph. The position of the vertices in the hypergraph is the position of the same vertices in the graph's layout. .. NOTE:: This method also returns the position of the "fake" vertices, i.e. those representing the sets. EXAMPLES:: sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{4,5,6}]); H Hypergraph on 6 vertices containing 4 sets sage: L = H._spring_layout() sage: L # random {1: (0.238, -0.926), 2: (0.672, -0.518), 3: (0.449, -0.225), 4: (0.782, 0.225), 5: (0.558, 0.518), 6: (0.992, 0.926), {3, 4, 5}: (0.504, 0.173), {2, 3, 4}: (0.727, -0.173), {4, 5, 6}: (0.838, 0.617), {1, 2, 3}: (0.393, -0.617)} sage: all(v in L for v in H.domain()) True sage: all(v in L for v in H._sets) True """ from sage.graphs.graph import Graph g = Graph() for s in self._sets: for x in s: g.add_edge(s, x) _ = g.plot(iterations=50000, save_pos=True) # The values are rounded as TikZ does not like accuracy. return { k: (round(x, 3), round(y, 3)) for k, (x, y) in g.get_pos().items() }