Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/graphs/hypergraph.py
8815 views
1
r"""
2
Hypergraphs
3
4
This module consists in a very basic implementation of :class:`Hypergraph`,
5
whose only current purpose is to observe them: it can be used to compute
6
automorphism groups and to draw them. The latter is done at the moment through
7
`\LaTeX` and TikZ, and can be obtained from Sage through the ``view`` command::
8
9
sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{4,5,6}]); H
10
Hypergraph on 6 vertices containing 4 sets
11
sage: view(H) # not tested
12
13
Note that hypergraphs are very hard to visualize, and unless it is very small
14
(`\leq 10` sets) or has a very specific structure (like the following one),
15
Sage's drawing will only bring more confusion::
16
17
sage: g = graphs.Grid2dGraph(5,5)
18
sage: sets = Set(map(Set,list(g.subgraph_search_iterator(graphs.CycleGraph(4)))))
19
sage: H = Hypergraph(sets)
20
sage: view(H) # not tested
21
22
.. SEEALSO::
23
24
:class:`Hypergraph` for information on the `\LaTeX` output
25
26
Classes and methods
27
-------------------
28
"""
29
from sage.misc.latex import latex
30
from sage.sets.set import Set
31
32
class Hypergraph:
33
r"""
34
A hypergraph.
35
36
A *hypergraph* `H = (V, E)` is a set of vertices `V` and a collection `E` of
37
sets of vertices called *hyperedges* or edges. In particular `E \subseteq
38
\mathcal{P}(V)`. If all (hyper)edges contain exactly 2 vertices, then `H` is
39
a graph in the usual sense.
40
41
.. rubric:: Latex output
42
43
The `\LaTeX` for a hypergraph `H` is consists of the vertices set and a
44
set of closed curves. The set of vertices in each closed curve represents a
45
hyperedge of `H`. A vertex which is encircled by a curve but is not
46
located on its boundary is **NOT** included in the corresponding set.
47
48
The colors are picked for readability and have no other meaning.
49
50
INPUT:
51
52
- ``sets`` -- A list of hyperedges
53
54
EXAMPLES::
55
56
sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{6}]); H
57
Hypergraph on 6 vertices containing 4 sets
58
59
REFERENCES:
60
61
- :wikipedia:`Hypergraph`
62
"""
63
def __init__(self, sets):
64
r"""
65
Constructor
66
67
EXAMPLES::
68
69
sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{4,5,6}]); H
70
Hypergraph on 6 vertices containing 4 sets
71
"""
72
from sage.sets.set import Set
73
self._sets = map(Set, sets)
74
self._domain = set([])
75
for s in sets:
76
for i in s:
77
self._domain.add(i)
78
79
def __repr__(self):
80
r"""
81
Short description of ``self``.
82
83
EXAMPLES::
84
85
sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{4,5,6}]); H
86
Hypergraph on 6 vertices containing 4 sets
87
"""
88
return ("Hypergraph on "+str(len(self.domain()))+" "
89
"vertices containing "+str(len(self._sets))+" sets")
90
91
def edge_coloring(self):
92
r"""
93
Compute a proper edge-coloring.
94
95
A proper edge-coloring is an assignment of colors to the sets of the
96
hypergraph such that two sets with non-empty intersection receive
97
different colors. The coloring returned minimizes the number of colors.
98
99
OUTPUT:
100
101
A partition of the sets into color classes.
102
103
EXAMPLES::
104
105
sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{4,5,6}]); H
106
Hypergraph on 6 vertices containing 4 sets
107
sage: C = H.edge_coloring()
108
sage: C # random
109
[[{3, 4, 5}], [{4, 5, 6}, {1, 2, 3}], [{2, 3, 4}]]
110
sage: Set(sum(C,[])) == Set(H._sets)
111
True
112
"""
113
from sage.graphs.graph import Graph
114
g = Graph([self._sets,lambda x,y : len(x&y)],loops = False)
115
return g.coloring(algorithm="MILP")
116
117
def _spring_layout(self):
118
r"""
119
Return a spring layout for the vertices.
120
121
The layout is computed by creating a graph `G` on the vertices *and*
122
sets of the hypergraph. Each set is then made adjacent in `G` with all
123
vertices it contains before a spring layout is computed for this
124
graph. The position of the vertices in the hypergraph is the position of
125
the same vertices in the graph's layout.
126
127
.. NOTE::
128
129
This method also returns the position of the "fake" vertices,
130
i.e. those representing the sets.
131
132
EXAMPLES::
133
134
sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{4,5,6}]); H
135
Hypergraph on 6 vertices containing 4 sets
136
sage: L = H._spring_layout()
137
sage: L # random
138
{1: (0.238, -0.926),
139
2: (0.672, -0.518),
140
3: (0.449, -0.225),
141
4: (0.782, 0.225),
142
5: (0.558, 0.518),
143
6: (0.992, 0.926),
144
{3, 4, 5}: (0.504, 0.173),
145
{2, 3, 4}: (0.727, -0.173),
146
{4, 5, 6}: (0.838, 0.617),
147
{1, 2, 3}: (0.393, -0.617)}
148
sage: all(v in L for v in H.domain())
149
True
150
sage: all(v in L for v in H._sets)
151
True
152
"""
153
from sage.graphs.graph import Graph
154
155
g = Graph()
156
for s in self._sets:
157
for x in s:
158
g.add_edge(s,x)
159
160
_ = g.plot(iterations = 50000,save_pos=True)
161
162
# The values are rounded as TikZ does not like accuracy.
163
return {k:(round(x,3),round(y,3)) for k,(x,y) in g.get_pos().items()}
164
165
def domain(self):
166
r"""
167
Return the set of vertices.
168
169
EXAMPLES::
170
171
sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{4,5,6}]); H
172
Hypergraph on 6 vertices containing 4 sets
173
sage: H.domain()
174
set([1, 2, 3, 4, 5, 6])
175
"""
176
return self._domain.copy()
177
178
def _latex_(self):
179
r"""
180
Return a TikZ representation of the hypergraph.
181
182
EXAMPLES::
183
184
sage: H = Hypergraph([{1,2,3},{2,3,4},{3,4,5},{4,5,6}]); H
185
Hypergraph on 6 vertices containing 4 sets
186
sage: view(H) # not tested
187
188
With sets of size 4::
189
190
sage: g = graphs.Grid2dGraph(5,5)
191
sage: C4 = graphs.CycleGraph(4)
192
sage: sets = Set(map(Set,list(g.subgraph_search_iterator(C4))))
193
sage: H = Hypergraph(sets)
194
sage: view(H) # not tested
195
"""
196
from sage.rings.integer import Integer
197
from sage.functions.trig import arctan2
198
199
from sage.misc.misc import warn
200
warn("\nThe hypergraph is drawn as a set of closed curves. The curve "
201
"representing a set S go **THROUGH** the vertices contained "
202
"in S.\n A vertex which is encircled by a curve but is not located "
203
"on its boundary is **NOT** included in the corresponding set.\n"
204
"\n"
205
"The colors are picked for readability and have no other meaning.")
206
207
latex.add_package_to_preamble_if_available("tikz")
208
209
if not latex.has_file("tikz.sty"):
210
raise RuntimeError("You must have TikZ installed in order "
211
"to draw a hypergraph.")
212
213
domain = self.domain()
214
pos = self._spring_layout()
215
tex = "\\begin{tikzpicture}[scale=3]\n"
216
217
colors = ["black", "red", "green", "blue", "cyan", "magenta", "yellow","pink","brown"]
218
colored_sets = [(s,i) for i,S in enumerate(self.edge_coloring()) for s in S]
219
220
# Prints each set with its color
221
for s,i in colored_sets:
222
current_color = colors[i%len(colors)]
223
224
if len(s) == 2:
225
s = list(s)
226
tex += ("\\draw[color="+str(current_color)+","+
227
"line width=.1cm,opacity = .6] "+
228
str(pos[s[0]])+" -- "+str(pos[s[1]])+";\n")
229
continue
230
231
tex += ("\\draw[color="+str(current_color)+","
232
"line width=.1cm,opacity = .6,"
233
"line cap=round,"
234
"line join=round]"
235
"plot [smooth cycle,tension=1] coordinates {")
236
237
# Reorders the vertices of s according to their angle with the
238
# "center", i.e. the vertex representing the set s
239
cx,cy = pos[s]
240
s = map(lambda x:pos[x],s)
241
s = sorted(s, key = lambda (x,y) : arctan2(x-cx,y-cy))
242
243
for x in s:
244
tex += str(x)+" "
245
tex += "};\n"
246
247
# Prints each vertex
248
for v in domain:
249
tex += "\\draw node[fill,circle,scale=.5,label={90:$"+latex(v)+"$}] at "+str(pos[v])+" {};\n"
250
251
tex += "\\end{tikzpicture}"
252
return tex
253
254
def to_bipartite_graph(self, with_partition=False):
255
r"""
256
Returns the associated bipartite graph
257
258
INPUT:
259
260
- with_partition -- boolean (default: False)
261
262
OUTPUT:
263
264
- a graph or a pair (graph, partition)
265
266
EXAMPLES::
267
268
sage: H = designs.steiner_triple_system(7).blocks()
269
sage: H = Hypergraph(H)
270
sage: g = H.to_bipartite_graph(); g
271
Graph on 14 vertices
272
sage: g.is_regular()
273
True
274
"""
275
from sage.graphs.graph import Graph
276
277
G = Graph()
278
domain = list(self.domain())
279
G.add_vertices(domain)
280
for s in self._sets:
281
for i in s:
282
G.add_edge(s, i)
283
if with_partition:
284
return (G, [domain, list(self._sets)])
285
else:
286
return G
287
288
def automorphism_group(self):
289
r"""
290
Returns the automorphism group.
291
292
For more information on the automorphism group of a hypergraph, see the
293
:wikipedia:`Hypergraph`.
294
295
EXAMPLE::
296
297
sage: H = designs.steiner_triple_system(7).blocks()
298
sage: H = Hypergraph(H)
299
sage: g = H.automorphism_group(); g
300
Permutation Group with generators [(2,4)(5,6), (2,5)(4,6), (1,2)(3,4), (1,3)(5,6), (0,1)(2,5)]
301
sage: g.is_isomorphic(groups.permutation.PGL(3,2))
302
True
303
"""
304
from sage.groups.perm_gps.permgroup import PermutationGroup
305
306
G, part = self.to_bipartite_graph(with_partition=True)
307
308
domain = part[0]
309
310
ag = G.automorphism_group(partition=part)
311
312
gens = [[tuple(c) for c in g.cycle_tuples() if c[0] in domain]
313
for g in ag.gens()]
314
315
return PermutationGroup(gens = gens, domain = domain)
316
317