# Ticket #14712: trac_14712.patch

File trac_14712.patch, 13.8 KB (added by ncohen, 8 years ago)
• ## doc/en/reference/graphs/index.rst

# HG changeset patch
# User Nathann Cohen <nathann.cohen@gmail.com>
# Date 1370860578 -7200
# Node ID d0b9d29d21159047139b49edc8beaf6641361e3d
A Hypergraph class for visualisation
* * *
#14712: review patch
* * *
An Hypergraph class for visualization -- Warning

diff --git a/doc/en/reference/graphs/index.rst b/doc/en/reference/graphs/index.rst
 a Graph Theory ============ sage/graphs/graph_generators sage/graphs/digraph_generators sage/graphs/graph_generators_pyx sage/graphs/hypergraph_generators sage/graphs/graph_database sage/graphs/isgci sage/graphs/base/dense_graph sage/graphs/base/static_sparse_graph Hypergraphs ----------- .. toctree:: :maxdepth: 1 sage/graphs/hypergraph_generators sage/graphs/hypergraph Libraries of algorithms -----------------------
• ## sage/graphs/all.py

diff --git a/sage/graphs/all.py b/sage/graphs/all.py
 a from graph_database import GraphDatabase, GenericGraphQuery, GraphQuery from graph import Graph from digraph import DiGraph from hypergraph import Hypergraph from bipartite_graph import BipartiteGraph from graph_bundle import GraphBundle import weakly_chordal
• ## sage/graphs/generic_graph.py

diff --git a/sage/graphs/generic_graph.py b/sage/graphs/generic_graph.py
 a Graph on 0 vertices """ self._latex_opts = None # FIXME: this has nothing to do here. Ideally, we would want # this to be run just once, just before the creation of a full # latex file including a graph. # There should be a Sage-wide strategy for handling this. from sage.graphs.graph_latex import setup_latex_preamble setup_latex_preamble() def __add__(self, other_graph): """ object that may be used to also customize the output produced here.  Possible options are documented at :meth:sage.graphs.graph_latex.GraphLatex.set_option. EXAMPLES:: EXAMPLES:: sage: from sage.graphs.graph_latex import check_tkz_graph sage: check_tkz_graph()  # random - depends on TeX installation sage: g = graphs.CompleteGraph(2) % \end{tikzpicture} """ from sage.graphs.graph_latex import setup_latex_preamble setup_latex_preamble() return self.latex_options().latex() def _matrix_(self, R=None): """ Returns the adjacency matrix of the graph over the specified ring. EXAMPLES:: EXAMPLES:: sage: G = graphs.CompleteBipartiteGraph(2,3) sage: m = matrix(G); m.parent() Full MatrixSpace of 5 by 5 dense matrices over Integer Ring
• ## sage/graphs/graph_coloring.py

diff --git a/sage/graphs/graph_coloring.py b/sage/graphs/graph_coloring.py
 a elif hex_colors: return {rainbow(1)[0]: g.vertices()} else: return g.vertices() return [g.vertices()] # - Bipartite set if g.is_bipartite(): if value_only:
• ## new file sage/graphs/hypergraph.py

diff --git a/sage/graphs/hypergraph.py b/sage/graphs/hypergraph.py
new file mode 100644
 - r""" Hypergraphs This module consists in a very basic implementation of :class:Hypergraph, whose only current purpose is to provide method to visualize them. This is done at the moment through \LaTeX and TikZ, and can be obtained from Sage through the view command:: sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{4,5,6}]); H Hypergraph on 6 vertices containing 4 sets sage: view(H) # not tested Note that hypergraphs are very hard to visualize, and unless it is very small (\leq 10 sets) or has a very specific structure (like the following one), Sage's drawing will only bring more confusion:: sage: g = graphs.Grid2dGraph(5,5) sage: sets = Set(map(Set,list(g.subgraph_search_iterator(graphs.CycleGraph(4))))) sage: H = Hypergraph(sets) sage: view(H) # not tested .. SEEALSO:: :class:Hypergraph for information on the \LaTeX output Classes and methods ------------------- """ from sage.misc.latex import latex from sage.sets.set import Set class Hypergraph: r""" A hypergraph. A *hypergraph* H = (V, E) is a set of vertices V and a collection E of sets of vertices called *hyperedges* or edges. In particular E \subseteq \mathcal{P}(V). If all (hyper)edges contain exactly 2 vertices, then H is a graph in the usual sense. .. rubric:: Latex output The \LaTeX for a hypergraph H is consists of the vertices set and a set of closed curves. The set of vertices in each closed curve represents a hyperedge of H. A vertex which is encircled by a curve but is not located on its boundary is **NOT** included in the corresponding set. The colors are picked for readability and have no other meaning. INPUT: - sets -- A list of hyperedges EXAMPLES:: sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{6}]); H Hypergraph on 6 vertices containing 4 sets REFERENCES: - :wikipedia:Hypergraph """ def __init__(self, sets): r""" Constructor EXAMPLES:: sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{4,5,6}]); H Hypergraph on 6 vertices containing 4 sets """ from sage.sets.set import Set self._sets = map(Set, sets) self._domain = set([]) for s in sets: for i in s: self._domain.add(i) def __repr__(self): r""" Short description of self. EXAMPLES:: sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{4,5,6}]); H Hypergraph on 6 vertices containing 4 sets """ return ("Hypergraph on "+str(len(self.domain()))+" " "vertices containing "+str(len(self._sets))+" sets") 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 _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 domain(self): r""" Return the set of vertices. 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: H.domain() set([1, 2, 3, 4, 5, 6]) """ return self._domain.copy() def _latex_(self): r""" Return a TikZ representation of the hypergraph. 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: view(H) # not tested With sets of size 4:: sage: g = graphs.Grid2dGraph(5,5) sage: C4 = graphs.CycleGraph(4) sage: sets = Set(map(Set,list(g.subgraph_search_iterator(C4)))) sage: H = Hypergraph(sets) sage: view(H) # not tested """ from sage.rings.integer import Integer from sage.functions.trig import arctan2 from sage.misc.misc import warn warn("\nThe hypergraph is drawn as a set of closed curves. The curve " "representing a set S go **THROUGH** the vertices contained " "in S.\n A vertex which is encircled by a curve but is not located " "on its boundary is **NOT** included in the corresponding set.\n" "\n" "The colors are picked for readability and have no other meaning.") latex.add_package_to_preamble_if_available("tikz") if not latex.has_file("tikz.sty"): raise RuntimeError("You must have TikZ installed in order " "to draw a hypergraph.") domain = self.domain() pos = self._spring_layout() tex = "\\begin{tikzpicture}[scale=3]\n" colors = ["black", "red", "green", "blue", "cyan", "magenta", "yellow","pink","brown"] colored_sets = [(s,i) for i,S in enumerate(self.edge_coloring()) for s in S] # Prints each set with its color for s,i in colored_sets: current_color = colors[i%len(colors)] if len(s) == 2: s = list(s) tex += ("\\draw[color="+str(current_color)+","+ "line width=.1cm,opacity = .6] "+ str(pos[s[0]])+" -- "+str(pos[s[1]])+";\n") continue tex += ("\\draw[color="+str(current_color)+"," "line width=.1cm,opacity = .6," "line cap=round," "line join=round]" "plot [smooth cycle,tension=1] coordinates {") # Reorders the vertices of s according to their angle with the # "center", i.e. the vertex representing the set s cx,cy = pos[s] s = map(lambda x:pos[x],s) s = sorted(s, key = lambda (x,y) : arctan2(x-cx,y-cy)) for x in s: tex += str(x)+" " tex += "};\n" # Prints each vertex for v in domain: tex += "\\draw node[fill,circle,scale=.5,label={90:$"+latex(v)+"$}] at "+str(pos[v])+" {};\n" tex += "\\end{tikzpicture}" return tex
• ## sage/graphs/hypergraph_generators.py

diff --git a/sage/graphs/hypergraph_generators.py b/sage/graphs/hypergraph_generators.py
 a r""" Hypergraph generators. Hypergraph generators At the moment this module only implement one method, which calls Brendan McKay's Nauty (_) to enumerate hypergraphs up to
• ## sage/misc/latex.py

diff --git a/sage/misc/latex.py b/sage/misc/latex.py
 a sage: s = sage.misc.latex._latex_file_(blah()) coucou """ MACROS = latex_extra_preamble() process = True if has_latex_attr(objects): objects = [objects] else: size='' s = LATEX_HEADER + '\n' + MACROS s += '%s\n\\begin{document}\n\\begin{center}{\\Large\\bf %s}\\end{center}\n%s'%( s = '%s\n\\begin{document}\n\\begin{center}{\\Large\\bf %s}\\end{center}\n%s'%( extra_preamble, title, size) #s += "(If something is missing it may be on the next page or there may be errors in the latex.  Use view with {\\tt debug=True}.)\\vfill" else: s += "\n\n".join([str(x) for x in objects]) s += '\n\\end{document}' # latex_extra_preamble() is called here and not before because some objects # may require additional packages to be displayed in LaTeX. Hence, the call # to latex(x) in the previous loop may change the result of # latex_extra_preamble() MACROS = latex_extra_preamble() s = LATEX_HEADER + '\n' + MACROS + s + '\n\\end{document}' if debug: print s