passagemath-graphs 10.5.43__cp312-cp312-macosx_14_0_arm64.whl → 10.6.1rc2__cp312-cp312-macosx_14_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {passagemath_graphs-10.5.43.dist-info → passagemath_graphs-10.6.1rc2.dist-info}/METADATA +5 -6
- {passagemath_graphs-10.5.43.dist-info → passagemath_graphs-10.6.1rc2.dist-info}/RECORD +132 -130
- sage/combinat/abstract_tree.py +188 -17
- sage/combinat/cluster_algebra_quiver/interact.py +1 -2
- sage/combinat/cluster_algebra_quiver/mutation_type.py +518 -519
- sage/combinat/cluster_algebra_quiver/quiver.py +233 -205
- sage/combinat/designs/covering_design.py +2 -6
- sage/combinat/designs/database.py +11 -10
- sage/combinat/designs/designs_pyx.cpython-312-darwin.so +0 -0
- sage/combinat/designs/designs_pyx.pyx +2 -2
- sage/combinat/designs/evenly_distributed_sets.cpython-312-darwin.so +0 -0
- sage/combinat/designs/evenly_distributed_sets.pyx +4 -4
- sage/combinat/designs/gen_quadrangles_with_spread.cpython-312-darwin.so +0 -0
- sage/combinat/designs/latin_squares.py +53 -20
- sage/combinat/designs/orthogonal_arrays.py +2 -1
- sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-312-darwin.so +0 -0
- sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +22 -21
- sage/combinat/designs/resolvable_bibd.py +191 -157
- sage/combinat/designs/subhypergraph_search.cpython-312-darwin.so +0 -0
- sage/combinat/designs/subhypergraph_search.pyx +4 -4
- sage/combinat/designs/twographs.py +2 -2
- sage/combinat/finite_state_machine.py +6 -6
- sage/combinat/posets/bubble_shuffle.py +247 -0
- sage/combinat/posets/d_complete.py +3 -3
- sage/combinat/posets/elements.py +3 -3
- sage/combinat/posets/hasse_cython.cpython-312-darwin.so +0 -0
- sage/combinat/posets/hasse_cython.pyx +1 -1
- sage/combinat/posets/hasse_diagram.py +16 -22
- sage/combinat/posets/hochschild_lattice.py +158 -0
- sage/combinat/posets/incidence_algebras.py +14 -16
- sage/combinat/posets/lattices.py +51 -53
- sage/combinat/posets/linear_extension_iterator.cpython-312-darwin.so +0 -0
- sage/combinat/posets/linear_extensions.py +10 -12
- sage/combinat/posets/moebius_algebra.py +4 -4
- sage/combinat/posets/poset_examples.py +70 -23
- sage/combinat/posets/posets.py +294 -103
- sage/databases/knotinfo_db.py +2 -1
- sage/graphs/asteroidal_triples.cpython-312-darwin.so +0 -0
- sage/graphs/asteroidal_triples.pyx +24 -3
- sage/graphs/base/boost_graph.cpython-312-darwin.so +0 -0
- sage/graphs/base/boost_graph.pxd +3 -3
- sage/graphs/base/c_graph.cpython-312-darwin.so +0 -0
- sage/graphs/base/c_graph.pyx +1 -1
- sage/graphs/base/dense_graph.cpython-312-darwin.so +0 -0
- sage/graphs/base/dense_graph.pxd +5 -3
- sage/graphs/base/dense_graph.pyx +44 -0
- sage/graphs/base/graph_backends.cpython-312-darwin.so +0 -0
- sage/graphs/base/sparse_graph.cpython-312-darwin.so +0 -0
- sage/graphs/base/static_dense_graph.cpython-312-darwin.so +0 -0
- sage/graphs/base/static_sparse_backend.cpython-312-darwin.so +0 -0
- sage/graphs/base/static_sparse_backend.pyx +8 -5
- sage/graphs/base/static_sparse_graph.cpython-312-darwin.so +0 -0
- sage/graphs/base/static_sparse_graph.pyx +86 -15
- sage/graphs/bipartite_graph.py +59 -36
- sage/graphs/centrality.cpython-312-darwin.so +0 -0
- sage/graphs/centrality.pyx +82 -9
- sage/graphs/cographs.py +1 -1
- sage/graphs/comparability.cpython-312-darwin.so +0 -0
- sage/graphs/comparability.pyx +64 -26
- sage/graphs/connectivity.cpython-312-darwin.so +0 -0
- sage/graphs/convexity_properties.cpython-312-darwin.so +0 -0
- sage/graphs/convexity_properties.pyx +52 -9
- sage/graphs/digraph.py +439 -95
- sage/graphs/digraph_generators.py +174 -102
- sage/graphs/distances_all_pairs.cpython-312-darwin.so +0 -0
- sage/graphs/dot2tex_utils.py +1 -1
- sage/graphs/edge_connectivity.cpython-312-darwin.so +0 -0
- sage/graphs/generators/basic.py +1 -1
- sage/graphs/generators/distance_regular.cpython-312-darwin.so +0 -0
- sage/graphs/generators/distance_regular.pyx +1 -1
- sage/graphs/generators/families.py +37 -27
- sage/graphs/generators/random.py +2 -2
- sage/graphs/generators/smallgraphs.py +3 -3
- sage/graphs/generic_graph.py +558 -86
- sage/graphs/generic_graph_pyx.cpython-312-darwin.so +0 -0
- sage/graphs/generic_graph_pyx.pyx +58 -11
- sage/graphs/genus.cpython-312-darwin.so +0 -0
- sage/graphs/genus.pyx +3 -4
- sage/graphs/graph.py +291 -8
- sage/graphs/graph_coloring.cpython-312-darwin.so +0 -0
- sage/graphs/graph_database.py +67 -12
- sage/graphs/graph_decompositions/bandwidth.cpython-312-darwin.so +0 -0
- sage/graphs/graph_decompositions/clique_separators.cpython-312-darwin.so +0 -0
- sage/graphs/graph_decompositions/clique_separators.pyx +24 -3
- sage/graphs/graph_decompositions/cutwidth.cpython-312-darwin.so +0 -0
- sage/graphs/graph_decompositions/fast_digraph.cpython-312-darwin.so +0 -0
- sage/graphs/graph_decompositions/fast_digraph.pyx +1 -1
- sage/graphs/graph_decompositions/graph_products.cpython-312-darwin.so +0 -0
- sage/graphs/graph_decompositions/graph_products.pyx +67 -21
- sage/graphs/graph_decompositions/modular_decomposition.cpython-312-darwin.so +0 -0
- sage/graphs/graph_decompositions/slice_decomposition.cpython-312-darwin.so +0 -0
- sage/graphs/graph_decompositions/slice_decomposition.pyx +34 -8
- sage/graphs/graph_decompositions/tree_decomposition.cpython-312-darwin.so +0 -0
- sage/graphs/graph_decompositions/vertex_separation.cpython-312-darwin.so +0 -0
- sage/graphs/graph_generators.py +45 -32
- sage/graphs/graph_generators_pyx.cpython-312-darwin.so +0 -0
- sage/graphs/graph_generators_pyx.pyx +15 -15
- sage/graphs/graph_latex.py +1 -1
- sage/graphs/graph_list.py +52 -9
- sage/graphs/graph_plot.py +7 -0
- sage/graphs/hyperbolicity.cpython-312-darwin.so +0 -0
- sage/graphs/hyperbolicity.pyx +2 -0
- sage/graphs/independent_sets.cpython-312-darwin.so +0 -0
- sage/graphs/isoperimetric_inequalities.cpython-312-darwin.so +0 -0
- sage/graphs/isoperimetric_inequalities.pyx +42 -6
- sage/graphs/line_graph.cpython-312-darwin.so +0 -0
- sage/graphs/line_graph.pyx +153 -37
- sage/graphs/matching_covered_graph.py +84 -60
- sage/graphs/orientations.py +3 -18
- sage/graphs/path_enumeration.cpython-312-darwin.so +0 -0
- sage/graphs/path_enumeration.pyx +2 -2
- sage/graphs/spanning_tree.cpython-312-darwin.so +0 -0
- sage/graphs/strongly_regular_db.cpython-312-darwin.so +0 -0
- sage/graphs/strongly_regular_db.pyx +15 -15
- sage/graphs/traversals.cpython-312-darwin.so +0 -0
- sage/graphs/traversals.pyx +13 -12
- sage/graphs/trees.cpython-312-darwin.so +0 -0
- sage/graphs/tutte_polynomial.py +1 -1
- sage/graphs/views.cpython-312-darwin.so +0 -0
- sage/graphs/weakly_chordal.cpython-312-darwin.so +0 -0
- sage/graphs/weakly_chordal.pyx +50 -8
- sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-312-darwin.so +0 -0
- sage/knots/free_knotinfo_monoid.py +3 -3
- sage/knots/knotinfo.py +102 -82
- sage/knots/link.py +72 -39
- sage/topology/cubical_complex.py +4 -5
- sage/topology/delta_complex.py +4 -4
- sage/topology/simplicial_complex.py +0 -1
- sage/topology/simplicial_complex_catalog.py +6 -0
- sage/topology/simplicial_complex_examples.py +4 -16
- {passagemath_graphs-10.5.43.dist-info → passagemath_graphs-10.6.1rc2.dist-info}/WHEEL +0 -0
- {passagemath_graphs-10.5.43.dist-info → passagemath_graphs-10.6.1rc2.dist-info}/top_level.txt +0 -0
sage/graphs/graph_list.py
CHANGED
@@ -19,7 +19,7 @@ AUTHORS:
|
|
19
19
|
# ****************************************************************************
|
20
20
|
|
21
21
|
|
22
|
-
def from_whatever(data):
|
22
|
+
def from_whatever(data, immutable=False):
|
23
23
|
r"""
|
24
24
|
Return a list of Sage Graphs, given a list of whatever kind of data.
|
25
25
|
|
@@ -28,6 +28,9 @@ def from_whatever(data):
|
|
28
28
|
- ``data`` -- can be a string, a list/iterable of strings, or a readable
|
29
29
|
file-like object
|
30
30
|
|
31
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return immutable
|
32
|
+
or mutable graphs
|
33
|
+
|
31
34
|
EXAMPLES::
|
32
35
|
|
33
36
|
sage: l = ['N@@?N@UGAGG?gGlKCMO', ':P_`cBaC_ACd`C_@BC`ABDHaEH_@BF_@CHIK_@BCEHKL_BIKM_BFGHI']
|
@@ -46,11 +49,20 @@ def from_whatever(data):
|
|
46
49
|
sage: with open(filename) as fobj:
|
47
50
|
....: graphs_list.from_whatever(fobj)
|
48
51
|
[Graph on 15 vertices, Looped multi-graph on 17 vertices]
|
52
|
+
|
53
|
+
Check the behaviour of parameter ``immutable``::
|
54
|
+
|
55
|
+
sage: with open(filename) as fobj:
|
56
|
+
....: any(g.is_immutable() for g in graphs_list.from_whatever(fobj))
|
57
|
+
False
|
58
|
+
sage: with open(filename) as fobj:
|
59
|
+
....: all(g.is_immutable() for g in graphs_list.from_whatever(fobj, immutable=True))
|
60
|
+
True
|
49
61
|
"""
|
50
|
-
return _from_whatever(data)
|
62
|
+
return _from_whatever(data, immutable=immutable)
|
51
63
|
|
52
64
|
|
53
|
-
def _from_whatever(data, fmt=None):
|
65
|
+
def _from_whatever(data, fmt=None, immutable=False):
|
54
66
|
"""
|
55
67
|
Implementation details of :func:`from_whatever`.
|
56
68
|
|
@@ -64,11 +76,21 @@ def _from_whatever(data, fmt=None):
|
|
64
76
|
indicating that the ``Graph`` constructor should determine this for
|
65
77
|
itself
|
66
78
|
|
79
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return immutable
|
80
|
+
or mutable graphs
|
81
|
+
|
67
82
|
EXAMPLES::
|
68
83
|
|
69
84
|
sage: l = ['N@@?N@UGAGG?gGlKCMO', ':P_`cBaC_ACd`C_@BC`ABDHaEH_@BF_@CHIK_@BCEHKL_BIKM_BFGHI']
|
70
85
|
sage: graphs_list.from_whatever(l)
|
71
86
|
[Graph on 15 vertices, Looped multi-graph on 17 vertices]
|
87
|
+
|
88
|
+
Check the behaviour of parameter ``immutable``::
|
89
|
+
|
90
|
+
sage: any(g.is_immutable() for g in graphs_list.from_whatever(l))
|
91
|
+
False
|
92
|
+
sage: all(g.is_immutable() for g in graphs_list.from_whatever(l, immutable=True))
|
93
|
+
True
|
72
94
|
"""
|
73
95
|
from sage.graphs.graph import Graph
|
74
96
|
|
@@ -110,14 +132,15 @@ def _from_whatever(data, fmt=None):
|
|
110
132
|
continue
|
111
133
|
|
112
134
|
if '\n' in line:
|
113
|
-
out.append(_from_whatever(line.splitlines(), fmt=fmt
|
135
|
+
out.append(_from_whatever(line.splitlines(), fmt=fmt,
|
136
|
+
immutable=immutable))
|
114
137
|
else:
|
115
|
-
out.append(Graph(line, **kwargs))
|
138
|
+
out.append(Graph(line, immutable=immutable, **kwargs))
|
116
139
|
|
117
140
|
return out
|
118
141
|
|
119
142
|
|
120
|
-
def from_graph6(data):
|
143
|
+
def from_graph6(data, immutable=False):
|
121
144
|
"""
|
122
145
|
Return a list of Sage Graphs, given a list of graph6 data.
|
123
146
|
|
@@ -125,16 +148,26 @@ def from_graph6(data):
|
|
125
148
|
|
126
149
|
- ``data`` -- can be a string, a list of strings, or a file stream
|
127
150
|
|
151
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return immutable
|
152
|
+
or mutable graphs
|
153
|
+
|
128
154
|
EXAMPLES::
|
129
155
|
|
130
156
|
sage: l = ['N@@?N@UGAGG?gGlKCMO', 'XsGGWOW?CC?C@HQKHqOjYKC_uHWGX?P?~TqIKA`OA@SAOEcEA??']
|
131
157
|
sage: graphs_list.from_graph6(l)
|
132
158
|
[Graph on 15 vertices, Graph on 25 vertices]
|
159
|
+
|
160
|
+
Check the behaviour of parameter ``immutable``::
|
161
|
+
|
162
|
+
sage: any(g.is_immutable() for g in graphs_list.from_graph6(l))
|
163
|
+
False
|
164
|
+
sage: all(g.is_immutable() for g in graphs_list.from_graph6(l, immutable=True))
|
165
|
+
True
|
133
166
|
"""
|
134
|
-
return _from_whatever(data, fmt='graph6')
|
167
|
+
return _from_whatever(data, fmt='graph6', immutable=immutable)
|
135
168
|
|
136
169
|
|
137
|
-
def from_sparse6(data):
|
170
|
+
def from_sparse6(data, immutable=False):
|
138
171
|
"""
|
139
172
|
Return a list of Sage Graphs, given a list of sparse6 data.
|
140
173
|
|
@@ -142,6 +175,9 @@ def from_sparse6(data):
|
|
142
175
|
|
143
176
|
- ``data`` -- can be a string, a list of strings, or a file stream
|
144
177
|
|
178
|
+
- ``immutable`` -- boolean (default: ``False``); whether to return immutable
|
179
|
+
or mutable graphs
|
180
|
+
|
145
181
|
EXAMPLES::
|
146
182
|
|
147
183
|
sage: g1 = ':P_`cBaC_ACd`C_@BC`ABDHaEH_@BF_@CHIK_@BCEHKL_BIKM_BFGHI'
|
@@ -152,8 +188,15 @@ def from_sparse6(data):
|
|
152
188
|
sage: g2 += 'BA@XCs\\NggWSOJIDbHh@?A@aF'
|
153
189
|
sage: graphs_list.from_sparse6([g1, g2])
|
154
190
|
[Looped multi-graph on 17 vertices, Looped multi-graph on 39 vertices]
|
191
|
+
|
192
|
+
Check the behaviour of parameter ``immutable``::
|
193
|
+
|
194
|
+
sage: any(g.is_immutable() for g in graphs_list.from_sparse6([g1, g2]))
|
195
|
+
False
|
196
|
+
sage: all(g.is_immutable() for g in graphs_list.from_sparse6([g1, g2], immutable=True))
|
197
|
+
True
|
155
198
|
"""
|
156
|
-
return _from_whatever(data, fmt='sparse6')
|
199
|
+
return _from_whatever(data, fmt='sparse6', immutable=immutable)
|
157
200
|
|
158
201
|
|
159
202
|
def to_graph6(graphs, file=None, output_list=False):
|
sage/graphs/graph_plot.py
CHANGED
@@ -161,6 +161,13 @@ layout_options = {
|
|
161
161
|
'tree_orientation':
|
162
162
|
'The direction of tree branches -- \'up\', \'down\', '
|
163
163
|
'\'left\' or \'right\'.',
|
164
|
+
'external_face':
|
165
|
+
'A list of the vertices of the external face of the graph, '
|
166
|
+
'used for Tutte embedding layout.',
|
167
|
+
'external_face_pos':
|
168
|
+
'A dictionary specifying the positions of the external face of the '
|
169
|
+
'graph, used for Tutte embedding layout. If none specified, the'
|
170
|
+
'external face is a regular polygon.',
|
164
171
|
'save_pos':
|
165
172
|
'Whether or not to save the computed position for the graph.',
|
166
173
|
'dim':
|
Binary file
|
sage/graphs/hyperbolicity.pyx
CHANGED
@@ -1160,6 +1160,7 @@ def hyperbolicity(G,
|
|
1160
1160
|
|
1161
1161
|
Asking for an approximation in a grid graph::
|
1162
1162
|
|
1163
|
+
sage: # needs sage.rings.real_mpfr
|
1163
1164
|
sage: from sage.graphs.hyperbolicity import hyperbolicity
|
1164
1165
|
sage: G = graphs.Grid2dGraph(2, 10)
|
1165
1166
|
sage: L,C,U = hyperbolicity(G, algorithm='CCL', approximation_factor=1.5); L,U
|
@@ -1175,6 +1176,7 @@ def hyperbolicity(G,
|
|
1175
1176
|
|
1176
1177
|
Asking for an approximation in a cycle graph::
|
1177
1178
|
|
1179
|
+
sage: # needs sage.rings.real_mpfr
|
1178
1180
|
sage: from sage.graphs.hyperbolicity import hyperbolicity
|
1179
1181
|
sage: G = graphs.CycleGraph(10)
|
1180
1182
|
sage: L,C,U = hyperbolicity(G, algorithm='CCL', approximation_factor=1.5); L,U
|
Binary file
|
Binary file
|
@@ -24,9 +24,11 @@ Authors:
|
|
24
24
|
from cysignals.signals cimport sig_on, sig_off
|
25
25
|
from cysignals.memory cimport check_malloc, sig_free
|
26
26
|
|
27
|
-
from sage.graphs.base.static_sparse_graph cimport short_digraph, init_short_digraph, free_short_digraph
|
28
27
|
from sage.data_structures.binary_matrix cimport *
|
29
28
|
from sage.graphs.base.static_dense_graph cimport dense_graph_init
|
29
|
+
from sage.graphs.base.static_sparse_backend cimport StaticSparseCGraph
|
30
|
+
from sage.graphs.base.static_sparse_backend cimport StaticSparseBackend
|
31
|
+
from sage.graphs.base.static_sparse_graph cimport short_digraph, init_short_digraph, free_short_digraph
|
30
32
|
|
31
33
|
from sage.rings.infinity import Infinity
|
32
34
|
from sage.rings.rational_field import QQ
|
@@ -89,6 +91,17 @@ def cheeger_constant(g):
|
|
89
91
|
Traceback (most recent call last):
|
90
92
|
...
|
91
93
|
ValueError: Cheeger constant is not defined for the empty graph
|
94
|
+
|
95
|
+
Immutable graph::
|
96
|
+
|
97
|
+
sage: G = graphs.RandomGNP(10, .7)
|
98
|
+
sage: G._backend
|
99
|
+
<sage.graphs.base.sparse_graph.SparseGraphBackend ...>
|
100
|
+
sage: H = Graph(G, immutable=True)
|
101
|
+
sage: H._backend
|
102
|
+
<sage.graphs.base.static_sparse_backend.StaticSparseBackend ...>
|
103
|
+
sage: G.cheeger_constant() == H.cheeger_constant()
|
104
|
+
True
|
92
105
|
"""
|
93
106
|
if g.is_directed():
|
94
107
|
raise ValueError("Cheeger constant is only defined on non-oriented graph")
|
@@ -98,8 +111,9 @@ def cheeger_constant(g):
|
|
98
111
|
elif g.num_verts() == 1:
|
99
112
|
return Infinity
|
100
113
|
elif not g.is_connected():
|
101
|
-
return QQ(
|
114
|
+
return QQ.zero()
|
102
115
|
|
116
|
+
cdef StaticSparseCGraph cg
|
103
117
|
cdef short_digraph sd # a copy of the graph g
|
104
118
|
cdef int * subgraph # vertices of the subgraph (stack)
|
105
119
|
cdef int * bitsubgraph # vertices of the subgraph (bit array of +1 (in) or -1 (not in))
|
@@ -111,7 +125,11 @@ def cheeger_constant(g):
|
|
111
125
|
cdef unsigned long vmin = 1 # value of the volume for the min
|
112
126
|
cdef int i
|
113
127
|
|
114
|
-
|
128
|
+
if isinstance(g, StaticSparseBackend):
|
129
|
+
cg = <StaticSparseCGraph> g._cg
|
130
|
+
sd = <short_digraph> cg.g
|
131
|
+
else:
|
132
|
+
init_short_digraph(sd, g, edge_labelled=False, vertex_list=list(g))
|
115
133
|
|
116
134
|
subgraph = <int *> check_malloc(sd.n * sizeof(int))
|
117
135
|
bitsubgraph = <int *> check_malloc(sd.n * sizeof(int))
|
@@ -171,7 +189,8 @@ def cheeger_constant(g):
|
|
171
189
|
return QQ((bmin, vmin))
|
172
190
|
|
173
191
|
finally:
|
174
|
-
|
192
|
+
if not isinstance(g, StaticSparseBackend):
|
193
|
+
free_short_digraph(sd)
|
175
194
|
sig_free(subgraph)
|
176
195
|
sig_free(bitsubgraph)
|
177
196
|
sig_off()
|
@@ -225,6 +244,17 @@ def edge_isoperimetric_number(g):
|
|
225
244
|
Traceback (most recent call last):
|
226
245
|
...
|
227
246
|
ValueError: edge-isoperimetric number not defined for the empty graph
|
247
|
+
|
248
|
+
Immutable graph::
|
249
|
+
|
250
|
+
sage: G = graphs.RandomGNP(10, .7)
|
251
|
+
sage: G._backend
|
252
|
+
<sage.graphs.base.sparse_graph.SparseGraphBackend ...>
|
253
|
+
sage: H = Graph(G, immutable=True)
|
254
|
+
sage: H._backend
|
255
|
+
<sage.graphs.base.static_sparse_backend.StaticSparseBackend ...>
|
256
|
+
sage: G.edge_isoperimetric_number() == H.edge_isoperimetric_number()
|
257
|
+
True
|
228
258
|
"""
|
229
259
|
if g.is_directed():
|
230
260
|
raise ValueError("edge isoperimetric number is only defined on non-oriented graph")
|
@@ -236,6 +266,7 @@ def edge_isoperimetric_number(g):
|
|
236
266
|
elif not g.is_connected():
|
237
267
|
return QQ((0, 1))
|
238
268
|
|
269
|
+
cdef StaticSparseCGraph cg
|
239
270
|
cdef short_digraph sd # a copy of the graph g
|
240
271
|
cdef int * subgraph # vertices of the subgraph (stack)
|
241
272
|
cdef int * bitsubgraph # vertices of the subgraph (bit array of +1 (in) or -1 (not in))
|
@@ -245,7 +276,11 @@ def edge_isoperimetric_number(g):
|
|
245
276
|
cdef int u = 0 # current vertex
|
246
277
|
cdef int i
|
247
278
|
|
248
|
-
|
279
|
+
if isinstance(g, StaticSparseBackend):
|
280
|
+
cg = <StaticSparseCGraph> g._cg
|
281
|
+
sd = <short_digraph> cg.g
|
282
|
+
else:
|
283
|
+
init_short_digraph(sd, g, edge_labelled=False, vertex_list=list(g))
|
249
284
|
|
250
285
|
cdef unsigned long bmin = sd.neighbors[1] - sd.neighbors[0] # value of boundary for the min
|
251
286
|
cdef unsigned long vmin = 1 # value of the volume for the min
|
@@ -311,7 +346,8 @@ def edge_isoperimetric_number(g):
|
|
311
346
|
|
312
347
|
finally:
|
313
348
|
sig_off()
|
314
|
-
|
349
|
+
if not isinstance(g, StaticSparseBackend):
|
350
|
+
free_short_digraph(sd)
|
315
351
|
sig_free(subgraph)
|
316
352
|
sig_free(bitsubgraph)
|
317
353
|
|
Binary file
|
sage/graphs/line_graph.pyx
CHANGED
@@ -128,6 +128,8 @@ Functions
|
|
128
128
|
---------
|
129
129
|
"""
|
130
130
|
|
131
|
+
from sage.structure.element cimport parent
|
132
|
+
|
131
133
|
|
132
134
|
def is_line_graph(g, certificate=False):
|
133
135
|
r"""
|
@@ -264,21 +266,36 @@ def is_line_graph(g, certificate=False):
|
|
264
266
|
return True
|
265
267
|
|
266
268
|
|
267
|
-
def line_graph(g, labels=True):
|
269
|
+
def line_graph(g, labels=True, return_labels=False, immutable=None):
|
268
270
|
"""
|
269
|
-
Return the line graph of the (di)graph ``g
|
271
|
+
Return the line graph of the (di)graph ``g`` (multiedges and loops allowed).
|
270
272
|
|
271
273
|
INPUT:
|
272
274
|
|
273
275
|
- ``labels`` -- boolean (default: ``True``); whether edge labels should be
|
274
276
|
taken in consideration. If ``labels=True``, the vertices of the line graph
|
275
|
-
will be triples ``(u,v,label)``, and pairs of vertices otherwise.
|
276
|
-
|
277
|
-
|
278
|
-
|
277
|
+
will be triples ``(u,v,label)``, and pairs of vertices otherwise. In case
|
278
|
+
of multiple edges, the vertices of the line graph will be triples
|
279
|
+
``(u,v,an integer)``.
|
280
|
+
|
281
|
+
- ``return_labels`` -- boolean (default: ``False``); whether edge labels should
|
282
|
+
be stored or not. If g has multiple edges and if ``return_labels=True``, the
|
283
|
+
method returns a list the first element of which is the line-graph of g
|
284
|
+
and the second element is a dictionary {vertex of the line-graph: former
|
285
|
+
corresponding edge with its original label}. If ``return_labels=False``,
|
286
|
+
the method returns only the line-graph.
|
287
|
+
|
288
|
+
- ``immutable`` -- boolean (default: ``None``); whether to create a
|
289
|
+
mutable/immutable (di)graph. ``immutable=None`` (default) means that the
|
290
|
+
(di)graph and its line (di)graph will behave the same way.
|
291
|
+
|
292
|
+
The line graph of an undirected graph G is an undirected simple graph H such
|
293
|
+
that the vertices of H are the edges of G and two vertices e and f of H are
|
279
294
|
adjacent if e and f share a common vertex in G. In other words, an edge in H
|
280
295
|
represents a path of length 2 in G.
|
281
296
|
|
297
|
+
Loops are not adjacent to themselves.
|
298
|
+
|
282
299
|
The line graph of a directed graph G is a directed graph H such that the
|
283
300
|
vertices of H are the edges of G and two vertices e and f of H are adjacent
|
284
301
|
if e and f share a common vertex in G and the terminal vertex of e is the
|
@@ -312,7 +329,7 @@ def line_graph(g, labels=True):
|
|
312
329
|
(1, 2, None),
|
313
330
|
(1, 3, None),
|
314
331
|
(2, 3, None)]
|
315
|
-
sage: h.am()
|
332
|
+
sage: h.am() # needs sage.modules
|
316
333
|
[0 1 1 1 1 0]
|
317
334
|
[1 0 1 1 0 1]
|
318
335
|
[1 1 0 0 1 1]
|
@@ -322,7 +339,7 @@ def line_graph(g, labels=True):
|
|
322
339
|
sage: h2 = g.line_graph(labels=False)
|
323
340
|
sage: h2.vertices(sort=True)
|
324
341
|
[(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
|
325
|
-
sage: h2.am() == h.am()
|
342
|
+
sage: h2.am() == h.am() # needs sage.modules
|
326
343
|
True
|
327
344
|
sage: g = DiGraph([[1..4], lambda i,j: i < j])
|
328
345
|
sage: h = g.line_graph()
|
@@ -339,6 +356,40 @@ def line_graph(g, labels=True):
|
|
339
356
|
((1, 3, None), (3, 4, None), None),
|
340
357
|
((2, 3, None), (3, 4, None), None)]
|
341
358
|
|
359
|
+
Examples with multiple edges::
|
360
|
+
|
361
|
+
sage: L = Graph([(0,1),(0,1),(1,2)],multiedges=True).line_graph()
|
362
|
+
sage: L.edges()
|
363
|
+
[((0, 1, 0), (0, 1, 1), None), ((0, 1, 1), (1, 2, 2), None),
|
364
|
+
((0, 1, 0), (1, 2, 2), None)]
|
365
|
+
sage: G = Graph([(0,1),(0,1,'a'),(0,1,'b'),(0,2),(1,2,'c')],
|
366
|
+
....: multiedges=True)
|
367
|
+
sage: L = G.line_graph(False,True)
|
368
|
+
sage: L[0].edges()
|
369
|
+
[((0, 1, 1), (0, 1, 2), None), ((0, 1, 0), (0, 1, 2), None),
|
370
|
+
((0, 1, 2), (0, 2, 3), None), ((0, 1, 2), (1, 2, 4), None), ((0, 1, 0),
|
371
|
+
(0, 1, 1), None), ((0, 1, 1), (0, 2, 3), None), ((0, 1, 1),
|
372
|
+
(1, 2, 4), None), ((0, 1, 0), (0, 2, 3), None), ((0, 1, 0),
|
373
|
+
(1, 2, 4), None), ((0, 2, 3), (1, 2, 4), None)]
|
374
|
+
sage: L[1]
|
375
|
+
{(0, 1, 0): (0, 1, None),
|
376
|
+
(0, 1, 1): (0, 1, 'b'),
|
377
|
+
(0, 1, 2): (0, 1, 'a'),
|
378
|
+
(0, 2, 3): (0, 2, None),
|
379
|
+
(1, 2, 4): (1, 2, 'c')}
|
380
|
+
sage: g = DiGraph([(0,1),(0,1),(1,2)],multiedges=True)
|
381
|
+
sage: g.line_graph().edges()
|
382
|
+
[((0, 1, 1), (1, 2, 2), None), ((0, 1, 0), (1, 2, 2), None)]
|
383
|
+
|
384
|
+
An example with a loop::
|
385
|
+
|
386
|
+
sage: g = Graph([(0,0),(0,1),(0,2),(1,2)],multiedges=True,loops=True)
|
387
|
+
sage: L = g.line_graph()
|
388
|
+
sage: L.edges()
|
389
|
+
[((0, 0, None), (0, 1, None), None), ((0, 0, None), (0, 2, None), None),
|
390
|
+
((0, 1, None), (0, 2, None), None), ((0, 1, None), (1, 2, None), None),
|
391
|
+
((0, 2, None), (1, 2, None), None)]
|
392
|
+
|
342
393
|
TESTS:
|
343
394
|
|
344
395
|
:issue:`13787`::
|
@@ -349,24 +400,64 @@ def line_graph(g, labels=True):
|
|
349
400
|
True
|
350
401
|
sage: C.line_graph().is_isomorphic(g.line_graph())
|
351
402
|
True
|
403
|
+
|
404
|
+
Check the behavior of parameter ``immutable``::
|
405
|
+
|
406
|
+
sage: G = Graph([(0, 1), (1, 2)])
|
407
|
+
sage: G.line_graph().is_immutable()
|
408
|
+
False
|
409
|
+
sage: G.line_graph(immutable=True).is_immutable()
|
410
|
+
True
|
411
|
+
sage: G = Graph([(0, 1), (1, 2)], immutable=True)
|
412
|
+
sage: G.line_graph().is_immutable()
|
413
|
+
True
|
414
|
+
sage: G.line_graph(immutable=False).is_immutable()
|
415
|
+
False
|
416
|
+
sage: G = Graph([(0, 1), (0, 1), (1, 2)], multiedges=True)
|
417
|
+
sage: G.line_graph().is_immutable()
|
418
|
+
False
|
419
|
+
sage: G.line_graph(immutable=True).is_immutable()
|
420
|
+
True
|
421
|
+
sage: G = Graph([(0, 1), (0, 1), (1, 2)], multiedges=True, immutable=True)
|
422
|
+
sage: G.line_graph().is_immutable()
|
423
|
+
True
|
424
|
+
sage: G.line_graph(immutable=False).is_immutable()
|
425
|
+
False
|
426
|
+
sage: G = DiGraph([(0, 1), (1, 2)])
|
427
|
+
sage: G.line_graph().is_immutable()
|
428
|
+
False
|
429
|
+
sage: G.line_graph(immutable=True).is_immutable()
|
430
|
+
True
|
352
431
|
"""
|
353
432
|
cdef dict conflicts = {}
|
354
|
-
cdef
|
433
|
+
cdef dict origlabels_dic = {} # stores original labels of edges in case of multiple edges
|
434
|
+
|
435
|
+
multiple = g.has_multiple_edges()
|
436
|
+
|
437
|
+
if immutable is None:
|
438
|
+
immutable = g.is_immutable()
|
439
|
+
|
440
|
+
if multiple:
|
441
|
+
# As the edges of g are the vertices of its line graph, we need to distinguish between the multiple edges of g.
|
442
|
+
# To this aim, we assign to each edge of g an integer label (between 0 and g.size() - 1) and set labels to True
|
443
|
+
# in order to keep these labels during the construction of the line graph.
|
444
|
+
labels = True
|
445
|
+
origlabels_dic = {(u, v, id): (u, v, label)
|
446
|
+
for id, (u, v, label) in enumerate(g.edge_iterator())}
|
447
|
+
g = parent(g)([g, origlabels_dic.keys()], format='vertices_and_edges', multiedges=True)
|
355
448
|
|
356
|
-
g._scream_if_not_simple()
|
357
449
|
if g._directed:
|
358
450
|
from sage.graphs.digraph import DiGraph
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
451
|
+
# Connect appropriate incident edges of each vertex v
|
452
|
+
arcs = ((e, f) for v in g
|
453
|
+
for e in g.incoming_edge_iterator(v, labels=labels)
|
454
|
+
for f in g.outgoing_edge_iterator(v, labels=labels))
|
455
|
+
G = DiGraph([g.edge_iterator(labels=labels), arcs],
|
456
|
+
format='vertices_and_edges', immutable=immutable)
|
457
|
+
if return_labels and multiple:
|
458
|
+
return [G, origlabels_dic]
|
365
459
|
return G
|
366
460
|
|
367
|
-
from sage.graphs.graph import Graph
|
368
|
-
G = Graph()
|
369
|
-
|
370
461
|
# We must sort the edges' endpoints so that (1,2,None) is seen as the
|
371
462
|
# same edge as (2,1,None).
|
372
463
|
#
|
@@ -376,25 +467,27 @@ def line_graph(g, labels=True):
|
|
376
467
|
# pair in the dictionary of conflicts
|
377
468
|
|
378
469
|
# 1) List of vertices in the line graph
|
470
|
+
cdef list vertices = []
|
379
471
|
for e in g.edge_iterator(labels=labels):
|
380
472
|
if hash(e[0]) < hash(e[1]):
|
381
|
-
|
473
|
+
vertices.append(e)
|
382
474
|
elif hash(e[0]) > hash(e[1]):
|
383
|
-
|
475
|
+
vertices.append((e[1], e[0]) + e[2:])
|
384
476
|
else:
|
385
477
|
# Settle the conflict arbitrarily
|
386
478
|
conflicts[e] = e
|
387
479
|
conflicts[(e[1], e[0]) + e[2:]] = e
|
388
|
-
|
389
|
-
|
390
|
-
G.add_vertices(elist)
|
480
|
+
vertices.append(e)
|
391
481
|
|
392
482
|
# 2) adjacencies in the line graph
|
483
|
+
cdef list edges = []
|
484
|
+
cdef list elist
|
485
|
+
from itertools import combinations
|
393
486
|
for v in g:
|
394
487
|
elist = []
|
395
488
|
|
396
489
|
# Add the edge to the list, according to hashes, as previously
|
397
|
-
for e in g.edge_iterator(v, labels=labels):
|
490
|
+
for e in g.edge_iterator(v, labels=labels): # iterates over the edges incident to v
|
398
491
|
if hash(e[0]) < hash(e[1]):
|
399
492
|
elist.append(e)
|
400
493
|
elif hash(e[0]) > hash(e[1]):
|
@@ -403,15 +496,19 @@ def line_graph(g, labels=True):
|
|
403
496
|
elist.append(conflicts[e])
|
404
497
|
|
405
498
|
# All pairs of elements in elist are edges of the line graph
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
G.add_edge(x, y)
|
499
|
+
# if g has multiple edges, some pairs appear more than once but as G is defined as simple,
|
500
|
+
# the corresponding edges are not added as multiedges (as it should be).
|
501
|
+
edges.extend(combinations(elist, 2))
|
410
502
|
|
503
|
+
from sage.graphs.graph import Graph
|
504
|
+
G = Graph([vertices, edges], format='vertices_and_edges',
|
505
|
+
immutable=immutable)
|
506
|
+
if return_labels and multiple:
|
507
|
+
return [G, origlabels_dic]
|
411
508
|
return G
|
412
509
|
|
413
510
|
|
414
|
-
def root_graph(g, verbose=False):
|
511
|
+
def root_graph(g, verbose=False, immutable=None):
|
415
512
|
r"""
|
416
513
|
Return the root graph corresponding to the given graph ``g``.
|
417
514
|
|
@@ -424,6 +521,10 @@ def root_graph(g, verbose=False):
|
|
424
521
|
- ``verbose`` -- boolean (default: ``False``); display some information
|
425
522
|
about what is happening inside of the algorithm
|
426
523
|
|
524
|
+
- ``immutable`` -- boolean (default: ``None``); whether to create a
|
525
|
+
mutable/immutable (di)graph. ``immutable=None`` (default) means that the
|
526
|
+
(di)graph and its root (di)graph will behave the same way.
|
527
|
+
|
427
528
|
.. WARNING::
|
428
529
|
|
429
530
|
This code assumes that `g` is a line graph, and is a connected,
|
@@ -466,6 +567,19 @@ def root_graph(g, verbose=False):
|
|
466
567
|
Graph on 4 vertices
|
467
568
|
sage: G, D = root_graph(graphs.WheelGraph(5)); G
|
468
569
|
Diamond Graph: Graph on 4 vertices
|
570
|
+
|
571
|
+
Check the behavior of parameter ``immutable``::
|
572
|
+
|
573
|
+
sage: G = graphs.CycleGraph(4)
|
574
|
+
sage: root_graph(G)[0].is_immutable()
|
575
|
+
False
|
576
|
+
sage: root_graph(G, immutable=True)[0].is_immutable()
|
577
|
+
True
|
578
|
+
sage: G = graphs.CycleGraph(4, immutable=True)
|
579
|
+
sage: root_graph(G)[0].is_immutable()
|
580
|
+
True
|
581
|
+
sage: root_graph(G, immutable=True)[0].is_immutable()
|
582
|
+
True
|
469
583
|
"""
|
470
584
|
from sage.graphs.digraph import DiGraph
|
471
585
|
|
@@ -478,23 +592,26 @@ def root_graph(g, verbose=False):
|
|
478
592
|
# is_line_graph expects a particular error message when g is not a line graph
|
479
593
|
not_line_graph = "this graph is not a line graph !"
|
480
594
|
|
595
|
+
if immutable is None:
|
596
|
+
immutable = g.is_immutable()
|
597
|
+
|
481
598
|
# Complete Graph ?
|
482
599
|
if g.is_clique():
|
483
600
|
from sage.graphs.generators.basic import CompleteBipartiteGraph
|
484
|
-
return (CompleteBipartiteGraph(1, g.order()),
|
601
|
+
return (CompleteBipartiteGraph(1, g.order(), immutable=immutable),
|
485
602
|
{v: (0, 1 + i) for i, v in enumerate(g)})
|
486
603
|
|
487
604
|
# Diamond Graph ?
|
488
605
|
elif g.order() == 4 and g.size() == 5:
|
489
606
|
from sage.graphs.graph import Graph
|
490
|
-
root = Graph([(0, 1), (1, 2), (2, 0), (0, 3)])
|
607
|
+
root = Graph([(0, 1), (1, 2), (2, 0), (0, 3)], immutable=immutable)
|
491
608
|
return (root,
|
492
609
|
g.is_isomorphic(root.line_graph(labels=False), certificate=True)[1])
|
493
610
|
|
494
611
|
# Wheel on 5 vertices ?
|
495
612
|
elif g.order() == 5 and g.size() == 8 and min(g.degree()) == 3:
|
496
613
|
from sage.graphs.generators.basic import DiamondGraph
|
497
|
-
root = DiamondGraph()
|
614
|
+
root = DiamondGraph(immutable=immutable)
|
498
615
|
return (root,
|
499
616
|
g.is_isomorphic(root.line_graph(labels=False), certificate=True)[1])
|
500
617
|
|
@@ -503,7 +620,7 @@ def root_graph(g, verbose=False):
|
|
503
620
|
from sage.graphs.generators.platonic_solids import OctahedralGraph
|
504
621
|
if g.is_isomorphic(OctahedralGraph()):
|
505
622
|
from sage.graphs.generators.basic import CompleteGraph
|
506
|
-
root = CompleteGraph(4)
|
623
|
+
root = CompleteGraph(4, immutable=immutable)
|
507
624
|
return (root,
|
508
625
|
g.is_isomorphic(root.line_graph(labels=False), certificate=True)[1])
|
509
626
|
|
@@ -592,8 +709,6 @@ def root_graph(g, verbose=False):
|
|
592
709
|
|
593
710
|
# We now have all our cliques. Let's build the root graph to check that it
|
594
711
|
# all fits !
|
595
|
-
from sage.graphs.graph import Graph
|
596
|
-
R = Graph()
|
597
712
|
|
598
713
|
# Associates an integer to each clique
|
599
714
|
cdef dict relabel = {}
|
@@ -617,7 +732,8 @@ def root_graph(g, verbose=False):
|
|
617
732
|
print(v, L)
|
618
733
|
|
619
734
|
# We now build R
|
620
|
-
|
735
|
+
from sage.graphs.graph import Graph
|
736
|
+
R = Graph(vertex_to_map.values(), format='list_of_edges', immutable=immutable)
|
621
737
|
|
622
738
|
# If g is a line graph, then it is isomorphic to the line graph of the graph
|
623
739
|
# R that we have constructed, so we return R (and the isomorphism).
|