Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/matroids/extension.pyx
8817 views
1
"""
2
Iterators for linear subclasses
3
4
The classes below are iterators returned by the functions
5
:func:`M.linear_subclasses() <sage.matroids.matroid.Matroid.linear_subclasses>`
6
and :func:`M.extensions() <sage.matroids.matroid.Matroid.extensions>`.
7
See the documentation of these methods for more detail.
8
For direct access to these classes, run::
9
10
sage: from sage.matroids.advanced import *
11
12
See also :mod:`sage.matroids.advanced`.
13
14
AUTHORS:
15
16
- Rudi Pendavingh, Stefan van Zwam (2013-04-01): initial version
17
18
Methods
19
=======
20
"""
21
#*****************************************************************************
22
# Copyright (C) 2013 Rudi Pendavingh <[email protected]>
23
# Copyright (C) 2013 Stefan van Zwam <[email protected]>
24
#
25
#
26
# Distributed under the terms of the GNU General Public License (GPL)
27
# as published by the Free Software Foundation; either version 2 of
28
# the License, or (at your option) any later version.
29
# http://www.gnu.org/licenses/
30
#*****************************************************************************
31
include 'sage/ext/stdsage.pxi'
32
include 'sage/misc/bitset.pxi'
33
from basis_matroid cimport BasisMatroid
34
from sage.rings.arith import binomial
35
36
cdef class CutNode:
37
"""
38
An internal class used for creating linear subclasses of a matroids in a
39
depth-first manner.
40
41
A linear subclass is a set of hyperplanes `mc` with the property that
42
certain sets of hyperplanes must either be fully contained in `mc` or
43
intersect `mc` in at most 1 element. The way we generate them is by a
44
depth-first seach. This class represents a node in the search tree.
45
46
It contains the set of hyperplanes selected so far, as well as a
47
collection of hyperplanes whose insertion has been explored elsewhere in
48
the seach tree.
49
50
The class has methods for selecting a hyperplane to insert, for inserting
51
hyperplanes and closing the set to become a linear subclass again, and for
52
adding a hyperplane to the set of *forbidden* hyperplanes, and similarly
53
closing that set.
54
55
"""
56
def __cinit__(self, MC, N=None):
57
"""
58
Internal data structure init
59
60
EXAMPLES::
61
62
sage: len(list(matroids.named_matroids.Fano().linear_subclasses())) # indirect doctest
63
16
64
"""
65
cdef CutNode node
66
self._MC = MC
67
bitset_init(self._p_free, self._MC._hyperplanes_count + 1)
68
bitset_init(self._p_in, self._MC._hyperplanes_count + 1)
69
bitset_init(self._l0, self._MC._hyperlines_count + 1)
70
bitset_init(self._l1, self._MC._hyperlines_count + 1)
71
if N is None:
72
bitset_set_first_n(self._p_free, self._MC._hyperplanes_count)
73
bitset_clear(self._p_in)
74
bitset_set_first_n(self._l0, self._MC._hyperlines_count)
75
bitset_clear(self._l1)
76
else:
77
node = N
78
bitset_copy(self._p_free, node._p_free)
79
bitset_copy(self._p_in, node._p_in)
80
bitset_copy(self._l0, node._l0)
81
bitset_copy(self._l1, node._l1)
82
self._ml = node._ml
83
84
def __dealloc__(self):
85
bitset_free(self._p_free)
86
bitset_free(self._p_in)
87
bitset_free(self._l0)
88
bitset_free(self._l1)
89
90
cdef CutNode copy(self):
91
return CutNode(self._MC, self)
92
93
cdef bint insert_plane(self, long p0):
94
"""
95
Add a hyperplane to the linear subclass.
96
"""
97
cdef long l, p
98
cdef list p_stack, l_stack
99
if bitset_in(self._p_in, p0):
100
return True
101
if not bitset_in(self._p_free, p0):
102
return False
103
bitset_discard(self._p_free, p0)
104
bitset_add(self._p_in, p0)
105
p_stack = [p0]
106
l_stack = []
107
while len(p_stack) > 0:
108
while len(p_stack) > 0:
109
p = p_stack.pop()
110
for l in self._MC._lines_on_plane[p]:
111
if bitset_in(self._l0, l):
112
bitset_discard(self._l0, l)
113
bitset_add(self._l1, l)
114
else:
115
if bitset_in(self._l1, l):
116
bitset_discard(self._l1, l)
117
l_stack.append(l)
118
while len(l_stack) > 0:
119
l = l_stack.pop()
120
for p in self._MC._planes_on_line[l]:
121
if bitset_in(self._p_in, p):
122
continue
123
if bitset_in(self._p_free, p):
124
bitset_discard(self._p_free, p)
125
bitset_add(self._p_in, p)
126
p_stack.append(p)
127
else:
128
return False
129
return True
130
131
cdef bint remove_plane(self, long p0):
132
"""
133
Remove a hyperplane from the linear subclass.
134
"""
135
cdef long p, l
136
cdef list p_stack, l_stack
137
bitset_discard(self._p_free, p0)
138
p_stack = [p0]
139
l_stack = []
140
while len(p_stack) > 0:
141
while len(p_stack) > 0:
142
p = p_stack.pop()
143
for l in self._MC._lines_on_plane[p]:
144
if bitset_in(self._l1, l):
145
l_stack.append(l)
146
while len(l_stack) > 0:
147
l = l_stack.pop()
148
for p in self._MC._planes_on_line[l]:
149
if bitset_in(self._p_free, p):
150
bitset_discard(self._p_free, p)
151
p_stack.append(p)
152
else:
153
return False
154
return True
155
156
cdef select_plane(self):
157
"""
158
Choose a hyperplane from the linear subclass.
159
"""
160
cdef long l, p
161
while self._ml >= 0:
162
l = self._MC._mandatory_lines[self._ml]
163
if bitset_in(self._l0, l):
164
for p in self._MC._planes_on_line[l]:
165
if bitset_in(self._p_free, p):
166
return p
167
return None
168
self._ml -= 1
169
170
return bitset_first(self._p_free)
171
172
cdef list planes(self):
173
"""
174
Return all hyperplanes from the linear subclass.
175
"""
176
return bitset_list(self._p_in)
177
178
cdef class LinearSubclassesIter:
179
"""
180
An iterator for a set of linear subclass.
181
"""
182
def __init__(self, MC):
183
"""
184
Create a linear subclass iterator.
185
186
Auxiliary to class LinearSubclasses.
187
188
INPUT:
189
190
- ``MC`` -- a member of class LinearSubclasses.
191
192
EXAMPLES::
193
194
sage: from sage.matroids.extension import LinearSubclasses
195
sage: M = matroids.Uniform(3, 6)
196
sage: type(LinearSubclasses(M).__iter__())
197
<type 'sage.matroids.extension.LinearSubclassesIter'>
198
"""
199
cdef CutNode first_cut = CutNode(MC)
200
self._MC = MC
201
self._nodes = []
202
203
for i in self._MC._forbidden_planes:
204
if not first_cut.remove_plane(i):
205
return
206
207
for i in self._MC._mandatory_planes:
208
if not first_cut.insert_plane(i):
209
return
210
211
first_cut._ml = len(self._MC._mandatory_lines) - 1
212
213
self._nodes = [first_cut]
214
215
def __next__(self):
216
"""
217
Return the next linear subclass.
218
219
EXAMPLES::
220
221
sage: from sage.matroids.advanced import *
222
sage: from sage.matroids.extension import LinearSubclasses
223
sage: M = BasisMatroid(matroids.Uniform(3, 6))
224
sage: I = LinearSubclasses(M).__iter__()
225
sage: M.extension('x', I.__next__())
226
Matroid of rank 3 on 7 elements with 35 bases
227
sage: M.extension('x', I.__next__())
228
Matroid of rank 3 on 7 elements with 34 bases
229
"""
230
cdef CutNode node, node2
231
while True:
232
if len(self._nodes) == 0:
233
raise StopIteration
234
node = self._nodes.pop()
235
p0 = node.select_plane()
236
while p0 is not None and p0 >= 0:
237
node2 = node.copy()
238
if node2.insert_plane(p0):
239
self._nodes.append(node2)
240
node.remove_plane(p0)
241
p0 = node.select_plane()
242
243
if p0 is not None:
244
res = self._MC[node]
245
if res is not None:
246
return res
247
248
249
cdef class LinearSubclasses:
250
"""
251
An iterable set of linear subclasses of a matroid.
252
253
Enumerate linear subclasses of a given matroid. A *linear subclass* is a
254
collection of hyperplanes (flats of rank `r - 1` where `r` is the rank of
255
the matroid) with the property that no modular triple of hyperplanes has
256
exactly two members in the linear subclass. A triple of hyperplanes in a
257
matroid of rank `r` is *modular* if its intersection has rank `r - 2`.
258
259
INPUT:
260
261
- ``M`` -- a matroid.
262
- ``line_length`` -- (default: ``None``) an integer.
263
- ``subsets`` -- (default: ``None``) a set of subsets of the groundset of
264
``M``.
265
- ``splice`` -- (default: ``None``) a matroid `N` such that for some
266
`e \in E(N)` and some `f \in E(M)`, we have
267
`N\setminus e= M\setminus f`.
268
269
OUTPUT:
270
271
An enumerator for the linear subclasses of M.
272
273
If ``line_length`` is not ``None``, the enumeration is restricted to
274
linear subclasses ``mc`` so containing at least one of each set of
275
``line_length`` hyperplanes which have a common intersection of
276
rank `r - 2`.
277
278
If ``subsets`` is not ``None``, the enumeration is restricted to linear
279
subclasses ``mc`` containing all hyperplanes which fully contain some set
280
from ``subsets``.
281
282
If ``splice`` is not ``None``, then the enumeration is restricted to
283
linear subclasses `mc` such that if `M'` is the extension of `M` by `e`
284
that arises from `mc`, then `M'\setminus f = N`.
285
286
EXAMPLES::
287
288
sage: from sage.matroids.extension import LinearSubclasses
289
sage: M = matroids.Uniform(3, 6)
290
sage: len([mc for mc in LinearSubclasses(M)])
291
83
292
sage: len([mc for mc in LinearSubclasses(M, line_length=5)])
293
22
294
sage: for mc in LinearSubclasses(M, subsets=[[0, 1], [2, 3], [4, 5]]):
295
....: print len(mc)
296
....:
297
3
298
15
299
300
Note that this class is intended for runtime, internal use, so no
301
loads/dumps mechanism was implemented.
302
"""
303
def __init__(self, M, line_length=None, subsets=None, splice=None):
304
"""
305
See class docstring for full documentation.
306
307
EXAMPLES::
308
309
sage: from sage.matroids.advanced import * # LinearSubclasses, BasisMatroid
310
sage: M = matroids.Uniform(3, 6)
311
sage: len([mc for mc in LinearSubclasses(M)])
312
83
313
sage: len([mc for mc in LinearSubclasses(M, line_length=5)])
314
22
315
sage: for mc in LinearSubclasses(M,
316
....: subsets=[[0, 1], [2, 3], [4, 5]]):
317
....: print len(mc)
318
....:
319
3
320
15
321
sage: M = BasisMatroid(matroids.named_matroids.BetsyRoss()); M
322
Matroid of rank 3 on 11 elements with 140 bases
323
sage: e = 'k'; f = 'h'; Me = M.delete(e); Mf=M.delete(f)
324
sage: for mc in LinearSubclasses(Mf, splice=Me):
325
....: print Mf.extension(f, mc)
326
....:
327
Matroid of rank 3 on 11 elements with 141 bases
328
Matroid of rank 3 on 11 elements with 140 bases
329
sage: for mc in LinearSubclasses(Me, splice=Mf):
330
....: print Me.extension(e, mc)
331
....:
332
Matroid of rank 3 on 11 elements with 141 bases
333
Matroid of rank 3 on 11 elements with 140 bases
334
"""
335
# set up hyperplanes/ hyperlines
336
E = M.groundset()
337
R = M.full_rank()
338
339
self._hyperlines = M.flats(R - 2)
340
self._hyperlines_count = len(self._hyperlines)
341
342
self._hyperplanes = M.flats(R - 1)
343
self._hyperplanes_count = len(self._hyperplanes)
344
345
self._planes_on_line = [[] for l in range(self._hyperlines_count)]
346
self._lines_on_plane = [[] for l in range(self._hyperplanes_count)]
347
for l in xrange(self._hyperlines_count):
348
for h in xrange(self._hyperplanes_count):
349
if self._hyperplanes[h] >= self._hyperlines[l]:
350
self._lines_on_plane[h].append(l)
351
self._planes_on_line[l].append(h)
352
353
self._mandatory_planes = []
354
self._forbidden_planes = []
355
self._mandatory_lines = []
356
self._line_length = -1
357
358
if line_length is not None:
359
self._line_length = line_length
360
self._mandatory_lines = [l for l in xrange(self._hyperlines_count) if len(self._planes_on_line[l]) >= line_length]
361
362
if subsets is not None:
363
for p in xrange(self._hyperplanes_count):
364
H = self._hyperplanes[p]
365
for S in subsets:
366
if frozenset(S).issubset(H):
367
self._mandatory_planes.append(p)
368
break
369
370
if splice is not None:
371
E2 = splice.groundset()
372
F = frozenset(E - E2)
373
F2 = frozenset(E2 - E)
374
if len(E) != len(E2) or len(F) != 1:
375
raise ValueError("LinearSubclasses: the ground set of the splice matroid is not of the form E + e-f")
376
377
for p in xrange(self._hyperplanes_count):
378
X = self._hyperplanes[p] - F
379
if splice._rank(X) == splice.full_rank() - 1:
380
if splice._rank(X | F2) == splice.full_rank() - 1:
381
self._mandatory_planes.append(p)
382
else:
383
self._forbidden_planes.append(p)
384
385
def __iter__(self):
386
"""
387
Return an iterator for the linear subclasses.
388
389
EXAMPLES::
390
391
sage: from sage.matroids.extension import LinearSubclasses
392
sage: M = matroids.Uniform(3, 6)
393
sage: for mc in LinearSubclasses(M, subsets=[[0, 1], [2, 3], [4, 5]]):
394
....: print len(mc)
395
3
396
15
397
"""
398
return LinearSubclassesIter(self)
399
400
def __getitem__(self, CutNode node):
401
"""
402
Return a linear subclass stored in a given CutNode.
403
404
Internal function.
405
406
EXAMPLES::
407
408
sage: from sage.matroids.extension import LinearSubclasses
409
sage: M = matroids.Uniform(3, 6)
410
sage: len([mc for mc in LinearSubclasses(M)])
411
83
412
"""
413
cdef long p
414
return [self._hyperplanes[p] for p in node.planes()]
415
416
417
cdef class MatroidExtensions(LinearSubclasses):
418
"""
419
An iterable set of single-element extensions of a given matroid.
420
421
INPUT:
422
423
- ``M`` -- a matroid
424
- ``e`` -- an element
425
- ``line_length`` (default: ``None``) -- an integer
426
- ``subsets`` (default: ``None``) -- a set of subsets of the groundset of
427
``M``
428
- ``splice`` -- a matroid `N` such that for some `f \in E(M)`, we have
429
`N\setminus e= M\setminus f`.
430
431
OUTPUT:
432
433
An enumerator for the extensions of ``M`` to a matroid ``N`` so that
434
`N\setminus e = M`. If ``line_length`` is not ``None``, the enumeration
435
is restricted to extensions `N` without `U(2, k)`-minors, where
436
``k > line_length``.
437
438
If ``subsets`` is not ``None``, the enumeration is restricted to
439
extensions `N` of `M` by element `e` so that all hyperplanes of `M`
440
which fully contain some set from ``subsets``, will also span `e`.
441
442
If ``splice`` is not ``None``, then the enumeration is restricted to
443
extensions `M'` such that `M'\setminus f = N`, where
444
`E(M)\setminus E(N)=\{f\}`.
445
446
EXAMPLES::
447
448
sage: from sage.matroids.advanced import *
449
sage: M = matroids.Uniform(3, 6)
450
sage: len([N for N in MatroidExtensions(M, 'x')])
451
83
452
sage: len([N for N in MatroidExtensions(M, 'x', line_length=5)])
453
22
454
sage: for N in MatroidExtensions(M, 'x', subsets=[[0, 1], [2, 3],
455
....: [4, 5]]): print N
456
Matroid of rank 3 on 7 elements with 32 bases
457
Matroid of rank 3 on 7 elements with 20 bases
458
sage: M = BasisMatroid(matroids.named_matroids.BetsyRoss()); M
459
Matroid of rank 3 on 11 elements with 140 bases
460
sage: e = 'k'; f = 'h'; Me = M.delete(e); Mf=M.delete(f)
461
sage: for N in MatroidExtensions(Mf, f, splice=Me): print N
462
Matroid of rank 3 on 11 elements with 141 bases
463
Matroid of rank 3 on 11 elements with 140 bases
464
sage: for N in MatroidExtensions(Me, e, splice=Mf): print N
465
Matroid of rank 3 on 11 elements with 141 bases
466
Matroid of rank 3 on 11 elements with 140 bases
467
468
Note that this class is intended for runtime, internal use, so no
469
loads/dumps mechanism was implemented.
470
"""
471
def __init__(self, M, e, line_length=None, subsets=None, splice=None, orderly=False):
472
"""
473
See class docstring for full documentation.
474
475
EXAMPLES::
476
477
sage: from sage.matroids.advanced import *
478
sage: M = matroids.Uniform(3, 6)
479
sage: len([N for N in MatroidExtensions(M, 'x')])
480
83
481
sage: len([N for N in MatroidExtensions(M, 'x', line_length=5)])
482
22
483
sage: for N in MatroidExtensions(M, 'x', subsets=[[0, 1], [2, 3],
484
....: [4, 5]]): print N
485
Matroid of rank 3 on 7 elements with 32 bases
486
Matroid of rank 3 on 7 elements with 20 bases
487
488
"""
489
if M.full_rank() == 0:
490
pass
491
if type(M) == BasisMatroid:
492
BM = M
493
else:
494
BM = BasisMatroid(M)
495
LinearSubclasses.__init__(self, BM, line_length=line_length, subsets=subsets, splice=splice)
496
self._BX = BM._extension(e, [])
497
self._BH = [BM._extension(e, [self._hyperplanes[i]]) for i in xrange(len(self._hyperplanes))]
498
if orderly:
499
self._orderly = True
500
501
def __getitem__(self, CutNode node):
502
"""
503
Return a single-element extension determined by a given CutNode.
504
505
Internal function.
506
507
EXAMPLES::
508
509
sage: from sage.matroids.advanced import *
510
sage: M = matroids.Uniform(3, 6)
511
sage: len([N for N in MatroidExtensions(M, 'x')])
512
83
513
"""
514
cdef long i
515
X = BasisMatroid(self._BX)
516
for i in node.planes():
517
bitset_intersection(X._bb, X._bb, (<BasisMatroid>self._BH[i])._bb)
518
X._reset_invariants()
519
if self._orderly and not X.is_distinguished(len(X) - 1):
520
return None
521
if self._line_length > 0 and X.has_line_minor(self._line_length + 1):
522
return None
523
return X
524
525