Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/matroids/utilities.py
8817 views
1
r"""
2
Some useful functions for the matroid class.
3
4
For direct access to the methods :meth:`newlabel`, :meth:`setprint` and
5
:meth:`get_nonisomorphic_matroids`, type::
6
7
sage: from sage.matroids.advanced import *
8
9
See also :mod:`sage.matroids.advanced`.
10
11
AUTHORS:
12
13
- Stefan van Zwam (2011-06-24): initial version
14
15
"""
16
#*****************************************************************************
17
# Copyright (C) 2013 Rudi Pendavingh <[email protected]>
18
# Copyright (C) 2013 Stefan van Zwam <[email protected]>
19
#
20
#
21
# Distributed under the terms of the GNU General Public License (GPL)
22
# as published by the Free Software Foundation; either version 2 of
23
# the License, or (at your option) any later version.
24
# http://www.gnu.org/licenses/
25
#*****************************************************************************
26
27
from sage.matrix.constructor import Matrix
28
from sage.rings.all import ZZ, QQ, FiniteField, GF
29
from sage.graphs.all import BipartiteGraph
30
from pprint import pformat
31
from sage.structure.all import SageObject
32
33
34
def setprint(X):
35
"""
36
Print nested data structures nicely.
37
38
Python's data structures ``set`` and ``frozenset`` do not print nicely.
39
This function can be used as replacement for ``print`` to overcome this.
40
For direct access to ``setprint``, run::
41
42
sage: from sage.matroids.advanced import *
43
44
.. NOTE::
45
46
This function will be redundant when Sage moves to Python 3, since the
47
default ``print`` will suffice then.
48
49
INPUT:
50
51
- ``X`` -- Any Python object
52
53
OUTPUT:
54
55
``None``. However, the function prints a nice representation of ``X``.
56
57
EXAMPLES:
58
59
Output looks much better::
60
61
sage: from sage.matroids.advanced import setprint
62
sage: L = [{1, 2, 3}, {1, 2, 4}, {2, 3, 4}, {4, 1, 3}]
63
sage: print(L)
64
[set([1, 2, 3]), set([1, 2, 4]), set([2, 3, 4]), set([1, 3, 4])]
65
sage: setprint(L)
66
[{1, 2, 3}, {1, 2, 4}, {2, 3, 4}, {1, 3, 4}]
67
68
Note that for iterables, the effect can be undesirable::
69
70
sage: from sage.matroids.advanced import setprint
71
sage: M = matroids.named_matroids.Fano().delete('efg')
72
sage: M.bases()
73
Iterator over a system of subsets
74
sage: setprint(M.bases())
75
[{'a', 'b', 'c'}, {'a', 'c', 'd'}, {'a', 'b', 'd'}]
76
77
An exception was made for subclasses of SageObject::
78
79
sage: from sage.matroids.advanced import setprint
80
sage: G = graphs.PetersenGraph()
81
sage: list(G)
82
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
83
sage: setprint(G)
84
Petersen graph: Graph on 10 vertices
85
"""
86
print setprint_s(X, toplevel=True)
87
88
89
def setprint_s(X, toplevel=False):
90
"""
91
Create the string for use by ``setprint()``.
92
93
INPUT:
94
95
- ``X`` -- any Python object
96
- ``toplevel`` -- (default: ``False``) indicates whether this is a
97
recursion or not.
98
99
OUTPUT:
100
101
A string representation of the object, with nice notation for sets and
102
frozensets.
103
104
EXAMPLES::
105
106
sage: from sage.matroids.utilities import setprint_s
107
sage: L = [{1, 2, 3}, {1, 2, 4}, {2, 3, 4}, {4, 1, 3}]
108
sage: setprint_s(L)
109
'[{1, 2, 3}, {1, 2, 4}, {2, 3, 4}, {1, 3, 4}]'
110
111
The ``toplevel`` argument only affects strings, to mimic ``print``'s
112
behavior::
113
114
sage: X = 'abcd'
115
sage: setprint_s(X)
116
"'abcd'"
117
sage: setprint_s(X, toplevel=True)
118
'abcd'
119
"""
120
if isinstance(X, frozenset) or isinstance(X, set):
121
return '{' + ', '.join([setprint_s(x) for x in sorted(X)]) + '}'
122
elif isinstance(X, dict):
123
return '{' + ', '.join([setprint_s(key) + ': ' + setprint_s(val) for key, val in sorted(X.iteritems())]) + '}'
124
elif isinstance(X, str):
125
if toplevel:
126
return X
127
else:
128
return "'" + X + "'"
129
elif hasattr(X, '__iter__') and not isinstance(X, SageObject):
130
return '[' + ', '.join([setprint_s(x) for x in sorted(X)]) + ']'
131
else:
132
return repr(X)
133
134
135
def newlabel(groundset):
136
r"""
137
Create a new element label different from the labels in ``groundset``.
138
139
INPUT:
140
141
- ``groundset`` -- A set of objects.
142
143
OUTPUT:
144
145
A string not in the set ``groundset``.
146
147
For direct access to ``newlabel``, run::
148
149
sage: from sage.matroids.advanced import *
150
151
ALGORITHM:
152
153
#. Create a set of all one-character alphanumeric strings.
154
#. Remove the string representation of each existing element from this
155
list.
156
#. If the list is nonempty, return any element.
157
#. Otherwise, return the concatenation of the strings of each existing
158
element, preceded by 'e'.
159
160
EXAMPLES::
161
162
sage: from sage.matroids.advanced import newlabel
163
sage: S = set(['a', 42, 'b'])
164
sage: newlabel(S) in S
165
False
166
167
sage: S = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')
168
sage: t = newlabel(S)
169
sage: len(t)
170
63
171
sage: t[0]
172
'e'
173
174
"""
175
char_list = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')
176
char_list.difference_update([str(e) for e in groundset])
177
try:
178
s = char_list.pop()
179
except KeyError:
180
s = 'e' + ''.join([str(e) for e in groundset])
181
return s
182
183
184
def sanitize_contractions_deletions(matroid, contractions, deletions):
185
r"""
186
Return a fixed version of sets ``contractions`` and ``deletions``.
187
188
INPUT:
189
190
- ``matroid`` -- a :class:`Matroid <sage.matroids.matroid.Matroid>`
191
instance.
192
- ``contractions`` -- a subset of the groundset.
193
- ``deletions`` -- a subset of the groundset.
194
195
OUTPUT:
196
197
An independent set ``C`` and a coindependent set ``D`` such that
198
199
``matroid / contractions \ deletions == matroid / C \ D``
200
201
Raise an error if either is not a subset of the groundset of ``matroid``
202
or if they are not disjoint.
203
204
This function is used by the
205
:meth:`Matroid.minor() <sage.matroids.matroid.Matroid.minor>` method.
206
207
EXAMPLES::
208
209
sage: from sage.matroids.utilities import setprint
210
sage: from sage.matroids.utilities import sanitize_contractions_deletions
211
sage: M = matroids.named_matroids.Fano()
212
sage: setprint(sanitize_contractions_deletions(M, 'abc', 'defg'))
213
[{'a', 'b', 'c'}, {'d', 'e', 'f', 'g'}]
214
sage: setprint(sanitize_contractions_deletions(M, 'defg', 'abc'))
215
[{'d', 'e', 'g'}, {'a', 'b', 'c', 'f'}]
216
sage: setprint(sanitize_contractions_deletions(M, [1, 2, 3], 'efg'))
217
Traceback (most recent call last):
218
...
219
ValueError: input contractions is not a subset of the groundset.
220
sage: setprint(sanitize_contractions_deletions(M, 'efg', [1, 2, 3]))
221
Traceback (most recent call last):
222
...
223
ValueError: input deletions is not a subset of the groundset.
224
sage: setprint(sanitize_contractions_deletions(M, 'ade', 'efg'))
225
Traceback (most recent call last):
226
...
227
ValueError: contraction and deletion sets are not disjoint.
228
229
"""
230
if contractions is None:
231
contractions = frozenset([])
232
contractions = frozenset(contractions)
233
if not matroid.groundset().issuperset(contractions):
234
raise ValueError("input contractions is not a subset of the groundset.")
235
236
if deletions is None:
237
deletions = frozenset([])
238
deletions = frozenset(deletions)
239
if not matroid.groundset().issuperset(deletions):
240
raise ValueError("input deletions is not a subset of the groundset.")
241
242
if not contractions.isdisjoint(deletions):
243
raise ValueError("contraction and deletion sets are not disjoint.")
244
245
conset = matroid._max_independent(contractions)
246
delset = matroid._max_coindependent(deletions)
247
248
return conset.union(deletions.difference(delset)), delset.union(contractions.difference(conset))
249
250
251
def make_regular_matroid_from_matroid(matroid):
252
r"""
253
Attempt to construct a regular representation of a matroid.
254
255
INPUT:
256
257
- ``matroid`` -- a matroid.
258
259
OUTPUT:
260
261
Return a `(0, 1, -1)`-matrix over the integers such that, if the input is
262
a regular matroid, then the output is a totally unimodular matrix
263
representing that matroid.
264
265
EXAMPLES::
266
267
sage: from sage.matroids.utilities import make_regular_matroid_from_matroid
268
sage: make_regular_matroid_from_matroid(
269
....: matroids.CompleteGraphic(6)).is_isomorphic(
270
....: matroids.CompleteGraphic(6))
271
True
272
"""
273
import sage.matroids.linear_matroid
274
M = matroid
275
if isinstance(M, sage.matroids.linear_matroid.RegularMatroid):
276
return M
277
rk = M.full_rank()
278
# First create a reduced 0-1 matrix
279
B = list(M.basis())
280
NB = list(M.groundset().difference(B))
281
dB = {}
282
i = 0
283
for e in B:
284
dB[e] = i
285
i += 1
286
dNB = {}
287
i = 0
288
for e in NB:
289
dNB[e] = i
290
i += 1
291
A = Matrix(ZZ, len(B), len(NB), 0)
292
G = BipartiteGraph(A.transpose()) # Sage's BipartiteGraph uses the column set as first color class. This is an edgeless graph.
293
for e in NB:
294
C = M.circuit(B + [e])
295
for f in C.difference([e]):
296
A[dB[f], dNB[e]] = 1
297
# Change some entries from -1 to 1
298
entries = BipartiteGraph(A.transpose()).edges(labels=False)
299
while len(entries) > 0:
300
L = [G.shortest_path(u, v) for u, v in entries]
301
mindex, minval = min(enumerate(L), key=lambda x: len(x[1]))
302
303
# if minval = 0, there is an edge not spanned by the current subgraph. Its entry is free to be scaled any way.
304
if len(minval) > 0:
305
# Check the subdeterminant
306
S = frozenset(L[mindex])
307
rows = []
308
cols = []
309
for i in S:
310
if i < rk:
311
rows.append(i)
312
else:
313
cols.append(i - rk)
314
if A[rows, cols].det() != 0:
315
A[entries[mindex][0], entries[mindex][1] - rk] = -1
316
G.add_edge(entries[mindex][0], entries[mindex][1])
317
entries.pop(mindex)
318
return sage.matroids.linear_matroid.RegularMatroid(groundset=B + NB, reduced_matrix=A)
319
320
321
def get_nonisomorphic_matroids(MSet):
322
"""
323
Return non-isomorphic members of the matroids in set ``MSet``.
324
325
For direct access to ``get_nonisomorphic_matroids``, run::
326
327
sage: from sage.matroids.advanced import *
328
329
INPUT:
330
331
- ``MSet`` -- an iterable whose members are matroids.
332
333
OUTPUT:
334
335
A list containing one representative of each isomorphism class of
336
members of ``MSet``.
337
338
EXAMPLES::
339
340
sage: from sage.matroids.advanced import *
341
sage: L = matroids.Uniform(3, 5).extensions()
342
sage: len(list(L))
343
32
344
sage: len(get_nonisomorphic_matroids(L))
345
5
346
"""
347
OutSet = []
348
for M in MSet:
349
seen = False
350
for N in OutSet:
351
if N.is_isomorphic(M):
352
seen = True
353
break
354
if not seen:
355
OutSet.append(M)
356
return OutSet
357
358