diff --git a/src/sage/algebras/orlik_solomon.py b/src/sage/algebras/orlik_solomon.py index caea1a60d37..d70df4c5c5e 100644 --- a/src/sage/algebras/orlik_solomon.py +++ b/src/sage/algebras/orlik_solomon.py @@ -132,7 +132,7 @@ def __init__(self, R, M, ordering=None): self._broken_circuits[frozenset(L[1:])] = L[0] cat = Algebras(R).FiniteDimensional().WithBasis().Graded() - CombinatorialFreeModule.__init__(self, R, M.no_broken_circuits_sets(ordering), + CombinatorialFreeModule.__init__(self, R, list(M.no_broken_circuits_sets(ordering)), prefix='OS', bracket='{', sorting_key=self._sort_key, category=cat) diff --git a/src/sage/algebras/orlik_terao.py b/src/sage/algebras/orlik_terao.py index d1f3fb38af7..222e2152739 100644 --- a/src/sage/algebras/orlik_terao.py +++ b/src/sage/algebras/orlik_terao.py @@ -25,7 +25,7 @@ class OrlikTeraoAlgebra(CombinatorialFreeModule): r""" An Orlik-Terao algebra. - Let `R` be a commutative ring. Let `M` be a matroid with ground set + Let `R` be a commutative ring. Let `M` be a matroid with groundset `X` with some fixed ordering and representation `A = (a_x)_{x \in X}` (so `a_x` is a (column) vector). Let `C(M)` denote the set of circuits of `M`. Let `P` denote the quotient algebra `R[e_x \mid x \in X] / @@ -65,7 +65,7 @@ class OrlikTeraoAlgebra(CombinatorialFreeModule): - ``R`` -- the base ring - ``M`` -- the defining matroid - - ``ordering`` -- (optional) an ordering of the ground set + - ``ordering`` -- (optional) an ordering of the groundset EXAMPLES: @@ -164,7 +164,7 @@ def __init__(self, R, M, ordering=None): self._broken_circuits[frozenset(L[1:])] = L[0] cat = Algebras(R).FiniteDimensional().Commutative().WithBasis().Graded() - CombinatorialFreeModule.__init__(self, R, M.no_broken_circuits_sets(ordering), + CombinatorialFreeModule.__init__(self, R, list(M.no_broken_circuits_sets(ordering)), prefix='OT', bracket='{', sorting_key=self._sort_key, category=cat) @@ -252,7 +252,7 @@ def algebra_generators(self): r""" Return the algebra generators of ``self``. - These form a family indexed by the ground set `X` of `M`. For + These form a family indexed by the groundset `X` of `M`. For each `x \in X`, the `x`-th element is `e_x`. EXAMPLES:: @@ -323,7 +323,7 @@ def product_on_basis(self, a, b): TESTS: Let us check that `e_{s_1} e_{s_2} \cdots e_{s_k} = e_S` for any - subset `S = \{ s_1 < s_2 < \cdots < s_k \}` of the ground set:: + subset `S = \{ s_1 < s_2 < \cdots < s_k \}` of the groundset:: sage: # needs sage.graphs sage: G = Graph([[1,2],[1,2],[2,3],[3,4],[4,2]], multiedges=True) @@ -355,11 +355,11 @@ def product_on_basis(self, a, b): def subset_image(self, S): r""" Return the element `e_S` of ``self`` corresponding to a - subset ``S`` of the ground set of the defining matroid. + subset ``S`` of the groundset of the defining matroid. INPUT: - - ``S`` -- a frozenset which is a subset of the ground set of `M` + - ``S`` -- a frozenset which is a subset of the groundset of `M` EXAMPLES:: diff --git a/src/sage/matroids/circuits_matroid.pxd b/src/sage/matroids/circuits_matroid.pxd index f495a1eff81..2c876fa3a48 100644 --- a/src/sage/matroids/circuits_matroid.pxd +++ b/src/sage/matroids/circuits_matroid.pxd @@ -2,23 +2,30 @@ from sage.matroids.matroid cimport Matroid from sage.matroids.set_system cimport SetSystem cdef class CircuitsMatroid(Matroid): - cdef frozenset _groundset # _E - cdef int _matroid_rank # _R - cdef SetSystem _C # circuits + cdef frozenset _groundset + cdef int _matroid_rank + cdef set _C # circuits cdef dict _k_C # k-circuits (k=len) + cdef list _sorted_C_lens cdef bint _nsc_defined cpdef groundset(self) cpdef _rank(self, X) cpdef full_rank(self) - cpdef _is_independent(self, F) - cpdef _max_independent(self, F) - cpdef _circuit(self, F) + cpdef _is_independent(self, X) + cpdef _max_independent(self, X) + cpdef _circuit(self, X) + cpdef _closure(self, X) # enumeration cpdef bases(self) + cpdef nonbases(self) + cpdef independent_r_sets(self, long r) + cpdef dependent_r_sets(self, long r) cpdef circuits(self, k=*) cpdef nonspanning_circuits(self) - cpdef no_broken_circuits_sets(self, ordering=*) + cpdef no_broken_circuits_facets(self, ordering=*, reduced=*) + cpdef no_broken_circuits_sets(self, ordering=*, reduced=*) + cpdef broken_circuit_complex(self, ordering=*, reduced=*) # properties cpdef girth(self) diff --git a/src/sage/matroids/circuits_matroid.pyx b/src/sage/matroids/circuits_matroid.pyx index aec280a35f7..6152dae2842 100644 --- a/src/sage/matroids/circuits_matroid.pyx +++ b/src/sage/matroids/circuits_matroid.pyx @@ -30,11 +30,10 @@ AUTHORS: # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.structure.richcmp cimport rich_to_bool, richcmp -from sage.matroids.matroid cimport Matroid -from sage.matroids.set_system cimport SetSystem from cpython.object cimport Py_EQ, Py_NE - +from sage.structure.richcmp cimport rich_to_bool, richcmp +from .matroid cimport Matroid +from .set_system cimport SetSystem cdef class CircuitsMatroid(Matroid): r""" @@ -42,9 +41,9 @@ cdef class CircuitsMatroid(Matroid): INPUT: - - ``M`` -- a matroid (default: ``None``) - - ``groundset`` -- a list (default: ``None``); the groundset of the matroid - - ``circuits`` -- a list (default: ``None``); the collection of circuits of + - ``M`` -- matroid (default: ``None``) + - ``groundset`` -- list (default: ``None``); the groundset of the matroid + - ``circuits`` -- list (default: ``None``); the collection of circuits of the matroid - ``nsc_defined`` -- boolean (default: ``False``); whether the matroid was defined by its nonspanning circuits @@ -69,18 +68,19 @@ cdef class CircuitsMatroid(Matroid): """ if M is not None: self._groundset = frozenset(M.groundset()) - self._C = SetSystem(list(M.groundset()), frozenset([frozenset(C) for C in M.circuits()])) + self._C = set([C for C in M.circuits()]) else: self._groundset = frozenset(groundset) - self._C = SetSystem(list(groundset), frozenset([frozenset(C) for C in circuits])) + self._C = set([frozenset(C) for C in circuits]) # k-circuits self._k_C = {} for C in self._C: try: - self._k_C[len(C)] += [C] + self._k_C[len(C)].add(C) except KeyError: - self._k_C[len(C)] = [] - self._k_C[len(C)] += [C] + self._k_C[len(C)] = set() + self._k_C[len(C)].add(C) + self._sorted_C_lens = sorted(self._k_C) self._matroid_rank = self.rank(self._groundset) self._nsc_defined = nsc_defined @@ -90,7 +90,7 @@ cdef class CircuitsMatroid(Matroid): The groundset is the set of elements that comprise the matroid. - OUTPUT: a set + OUTPUT: set EXAMPLES:: @@ -111,7 +111,7 @@ cdef class CircuitsMatroid(Matroid): - ``X`` -- an object with Python's ``frozenset`` interface - OUTPUT: an integer; the rank of ``X`` in the matroid + OUTPUT: integer EXAMPLES:: @@ -130,7 +130,7 @@ cdef class CircuitsMatroid(Matroid): The *rank* of the matroid is the size of the largest independent subset of the groundset. - OUTPUT: an integer; the rank of the matroid + OUTPUT: integer EXAMPLES:: @@ -140,13 +140,13 @@ cdef class CircuitsMatroid(Matroid): """ return self._matroid_rank - cpdef _is_independent(self, F): + cpdef _is_independent(self, X): """ Test if input is independent. INPUT: - - ``X`` -- An object with Python's ``frozenset`` interface containing + - ``X`` -- an object with Python's ``frozenset`` interface containing a subset of ``self.groundset()`` OUTPUT: boolean @@ -159,25 +159,26 @@ cdef class CircuitsMatroid(Matroid): sage: M._is_independent(['y0', 'y2', 'y3', 'x2']) True """ - cdef set I = set(F) - cdef int s = len(F) - for i in self._k_C: - if i <= s: - for C in self._k_C[i]: - if C <= I: - return False + cdef set XX = set(X) + cdef int i, l = len(XX) + for i in self._sorted_C_lens: + if i > l: + break + for C in self._k_C[i]: + if C <= XX: + return False return True - cpdef _max_independent(self, F): + cpdef _max_independent(self, X): """ Compute a maximal independent subset. INPUT: - - ``X`` -- An object with Python's ``frozenset`` interface containing + - ``X`` -- an object with Python's ``frozenset`` interface containing a subset of ``self.groundset()`` - OUTPUT: a frozenset; a maximal independent subset of ``X`` + OUTPUT: frozenset; a maximal independent subset of ``X`` EXAMPLES:: @@ -185,26 +186,27 @@ cdef class CircuitsMatroid(Matroid): sage: len(M._max_independent(M.groundset())) 6 """ - cdef set I = set(F) - for i in self._k_C: - for C in self._k_C[i]: - if i <= len(I) and i > 0: - if C <= I: - e = next(iter(C)) - I.remove(e) - - return frozenset(I) + cdef set XX = set(X) + cdef int i + cdef frozenset C + while True: + try: + C = self._circuit(XX) + e = next(iter(C)) + XX.remove(e) + except (ValueError, StopIteration): + return frozenset(XX) - cpdef _circuit(self, F): + cpdef _circuit(self, X): """ Return a minimal dependent subset. INPUT: - - ``X`` -- An object with Python's ``frozenset`` interface containing - a subset of ``self.groundset()``. + - ``X`` -- an object with Python's ``frozenset`` interface containing + a subset of ``self.groundset()`` - OUTPUT: a frozenset; a circuit contained in ``X``, if it exists. + OUTPUT: frozenset; a circuit contained in ``X``, if it exists. Otherwise an error is raised. EXAMPLES:: @@ -217,19 +219,53 @@ cdef class CircuitsMatroid(Matroid): ... ValueError: no circuit in independent set """ - cdef set I = set(F) - for C in self._C: - if C <= I: - return C + cdef set XX = set(X) + cdef int i, l = len(XX) + for i in self._sorted_C_lens: + if i > l: + break + for C in self._k_C[i]: + if C <= XX: + return C raise ValueError("no circuit in independent set") + cpdef _closure(self, X): + """ + Return the closure of a set. + + INPUT: + + - ``X`` -- an object with Python's ``frozenset`` interface containing + a subset of ``self.groundset()`` + + OUTPUT: :class:`frozenset` + + EXAMPLES:: + + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + sage: M = CircuitsMatroid(matroids.catalog.Vamos()) + sage: sorted(M._closure(set(['a', 'b', 'c']))) + ['a', 'b', 'c', 'd'] + """ + cdef set XX = set(X) + cdef frozenset S + cdef int i + for i in self._sorted_C_lens: + if i > len(XX) + 1: + break + for C in self._k_C[i]: + S = C - XX + if len(S) == 1: + XX.add(next(iter(S))) + return frozenset(XX) + cpdef _is_isomorphic(self, other, certificate=False): """ Test if ``self`` is isomorphic to ``other``. INPUT: - - ``other`` -- a matroid + - ``other`` -- matroid - ``certificate`` -- boolean (default: ``False``) OUTPUT: boolean, and, if ``certificate=True``, a dictionary giving the @@ -253,7 +289,9 @@ cdef class CircuitsMatroid(Matroid): if certificate: return self._is_isomorphic(other), self._isomorphism(other) N = CircuitsMatroid(other) - return self._C._isomorphism(N._C) is not None + S = SetSystem(list(self._groundset), self._C) + O = SetSystem(list(N._groundset), N._C) + return S._isomorphism(O) is not None # representation @@ -300,7 +338,7 @@ cdef class CircuitsMatroid(Matroid): sage: hash(M) == hash(O) False """ - return hash(tuple([self.groundset(), frozenset(self._C)])) + return hash(tuple([self._groundset, frozenset(self._C)])) def __richcmp__(left, right, int op): r""" @@ -377,7 +415,7 @@ cdef class CircuitsMatroid(Matroid): - ``mapping`` -- a python object such that ``mapping[e]`` is the new label of ``e`` - OUTPUT: a matroid + OUTPUT: matroid EXAMPLES:: @@ -415,30 +453,24 @@ cdef class CircuitsMatroid(Matroid): r""" Return the bases of the matroid. - OUTPUT: a :class:`SetSystem` + OUTPUT: :class:`SetSystem` EXAMPLES:: sage: from sage.matroids.circuits_matroid import CircuitsMatroid - sage: M = CircuitsMatroid(matroids.Uniform(2, 4)) + sage: M = CircuitsMatroid(matroids.CompleteGraphic(4)) sage: len(M.bases()) - 6 + 16 """ - cdef SetSystem B, NSC - cdef bint flag - B = SetSystem(list(self.groundset())) - NSC = self.nonspanning_circuits() from itertools import combinations + cdef set B = set() + cdef set NB = set(self.nonbases()) + cdef frozenset SS for S in combinations(self._groundset, self._matroid_rank): - flag = True - S = frozenset(S) - for C in NSC: - if C <= S: - flag = False - break - if flag: - B.append(S) - return B + SS = frozenset(S) + if SS not in NB: + B.add(SS) + return SetSystem(list(self._groundset), B) def bases_iterator(self): r""" @@ -460,11 +492,101 @@ cdef class CircuitsMatroid(Matroid): frozenset({2, 3})] """ from itertools import combinations - cdef SetSystem NSC = self.nonspanning_circuits() - for B in combinations(self._groundset, self._matroid_rank): - B = frozenset(B) - if not any(C <= B for C in NSC): - yield B + cdef set B = set() + cdef set NB = set(self.nonbases()) + cdef frozenset S + for SS in combinations(self._groundset, self._matroid_rank): + S = frozenset(SS) + if S not in NB: + yield S + + cpdef nonbases(self): + r""" + Return the nonbases of the matroid. + + OUTPUT: :class:`SetSystem` + + EXAMPLES:: + + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + sage: M = CircuitsMatroid(matroids.Uniform(2, 4)) + sage: len(M.nonbases()) + 0 + sage: M = CircuitsMatroid(matroids.CompleteGraphic(6)) + sage: len(M.nonbases()) + 1707 + """ + return self.dependent_r_sets(self._matroid_rank) + + cpdef independent_r_sets(self, long r): + r""" + Return the size-``r`` independent subsets of the matroid. + + INPUT: + + - ``r`` -- nonnegative integer + + OUTPUT: :class:`SetSystem` + + EXAMPLES:: + + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + sage: M = CircuitsMatroid(matroids.catalog.Pappus()) + sage: M.independent_r_sets(4) + SetSystem of 0 sets over 9 elements + sage: M.independent_r_sets(3) + SetSystem of 75 sets over 9 elements + sage: frozenset({'a', 'c', 'e'}) in _ + True + + .. SEEALSO:: + + :meth:`M.bases() ` + """ + from itertools import combinations + cdef set I_r = set() + cdef set D_r = set(self.dependent_r_sets(r)) + cdef frozenset SS + for S in combinations(self._groundset, r): + SS = frozenset(S) + if SS not in D_r: + I_r.add(SS) + return SetSystem(list(self._groundset), I_r) + + cpdef dependent_r_sets(self, long r): + r""" + Return the dependent subsets of fixed size. + + INPUT: + + - ``r`` -- nonnegative integer + + OUTPUT: :class:`SetSystem` + + EXAMPLES:: + + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + sage: M = CircuitsMatroid(matroids.catalog.Vamos()) + sage: M.dependent_r_sets(3) + SetSystem of 0 sets over 8 elements + sage: sorted([sorted(X) for X in M.dependent_r_sets(4)]) + [['a', 'b', 'c', 'd'], ['a', 'b', 'e', 'f'], ['a', 'b', 'g', 'h'], + ['c', 'd', 'e', 'f'], ['e', 'f', 'g', 'h']] + """ + cdef int i + cdef set NB = set() + cdef frozenset S + for i in range(min(self._k_C), r + 1): + if i in self._k_C: + for S in self._k_C[i]: + NB.add(S) + if i == r: + break + for S in NB.copy(): + NB.remove(S) + for e in S ^ self._groundset: + NB.add(S | set([e])) + return SetSystem(list(self._groundset), NB) cpdef circuits(self, k=None): """ @@ -472,9 +594,9 @@ cdef class CircuitsMatroid(Matroid): INPUT: - - ``k`` -- an integer (optional); the length of the circuits + - ``k`` -- integer (optional); the length of the circuits - OUTPUT: a :class:`SetSystem` + OUTPUT: :class:`SetSystem` EXAMPLES:: @@ -490,17 +612,16 @@ cdef class CircuitsMatroid(Matroid): frozenset({0, 2, 3}), frozenset({1, 2, 3})] """ - cdef SetSystem C - C = SetSystem(list(self.groundset())) + cdef set C = set() if k is not None: if k in self._k_C: for c in self._k_C[k]: - C.append(c) + C.add(c) else: for i in self._k_C: for c in self._k_C[i]: - C.append(c) - return C + C.add(c) + return SetSystem(list(self._groundset), C) def circuits_iterator(self, k=None): """ @@ -508,7 +629,7 @@ cdef class CircuitsMatroid(Matroid): INPUT: - - ``k`` -- an integer (optional); the length of the circuits + - ``k`` -- integer (optional); the length of the circuits EXAMPLES:: @@ -537,7 +658,7 @@ cdef class CircuitsMatroid(Matroid): """ Return the nonspanning circuits of the matroid. - OUTPUT: a :class:`SetSystem` + OUTPUT: :class:`SetSystem` EXAMPLES:: @@ -545,12 +666,16 @@ cdef class CircuitsMatroid(Matroid): sage: M = CircuitsMatroid(matroids.Uniform(2, 4)) sage: M.nonspanning_circuits() SetSystem of 0 sets over 4 elements + sage: M = matroids.Theta(5) + sage: M.nonspanning_circuits() + SetSystem of 15 sets over 10 elements """ - cdef list NSC = [] + cdef set NSC = set() + cdef int i for i in self._k_C: - if i <= self.rank(): - NSC.extend(self._k_C[i]) - return SetSystem(list(self.groundset()), NSC) + if i <= self._matroid_rank: + NSC.update(self._k_C[i]) + return SetSystem(list(self._groundset), NSC) def nonspanning_circuits_iterator(self): """ @@ -563,78 +688,165 @@ cdef class CircuitsMatroid(Matroid): sage: list(M.nonspanning_circuits_iterator()) [] """ + cdef int i for i in self._k_C: - if i <= self.rank(): + if i <= self._matroid_rank: for C in self._k_C[i]: yield C - cpdef no_broken_circuits_sets(self, ordering=None): + cpdef no_broken_circuits_facets(self, ordering=None, reduced=False): + r""" + Return the no broken circuits (NBC) facets of ``self``. + + INPUT: + + - ``ordering`` -- list (optional); a total ordering of the groundset + - ``reduced`` -- boolean (default: ``False``) + + OUTPUT: :class:`SetSystem` + + EXAMPLES:: + + sage: M = Matroid(circuits=[[0, 1, 2]]) + sage: M.no_broken_circuits_facets(ordering=[1, 0, 2]) + SetSystem of 2 sets over 3 elements + sage: sorted([sorted(X) for X in _]) + [[0, 1], [1, 2]] + sage: M.no_broken_circuits_facets(ordering=[1, 0, 2], reduced=True) + SetSystem of 2 sets over 3 elements + sage: sorted([sorted(X) for X in _]) + [[0], [2]] + """ + from itertools import combinations + from sage.matroids.utilities import cmp_elements_key + if ordering is None: + ordering = sorted(self._groundset, key=cmp_elements_key) + else: + if frozenset(ordering) != self._groundset: + raise ValueError("not an ordering of the groundset") + + cdef int i, r = self._matroid_rank + cdef frozenset min_e = frozenset([ordering[0]]) + cdef frozenset S + # compute broken circuits (with minimal element added) + cdef dict BC = {} + for i in range(r + 1): + BC[i] = set() + for C in self._C: + for e in ordering: + if e in C: + S = C - frozenset([e]) | min_e + if len(S) <= r: + BC[len(S)].add(S) + break + + for i in range(r): + for S in BC[i].copy(): + BC[i].remove(S) + for e in self._groundset ^ S: + BC[i+1].add(S | set([e])) + + cdef set B = set() + for SS in combinations(ordering[1:], self._matroid_rank - 1): + S = frozenset(SS) + if S | min_e not in BC[r]: + if not reduced: + B.add(S | min_e) + else: + B.add(S) + + return SetSystem(list(self.groundset()), B) + + cpdef no_broken_circuits_sets(self, ordering=None, reduced=False): r""" Return the no broken circuits (NBC) sets of ``self``. - An NBC set is a subset `A` of the ground set under some total + An NBC set is a subset `A` of the groundset under some total ordering `<` such that `A` contains no broken circuit. INPUT: - - ``ordering`` -- a total ordering of the groundset given as a list + - ``ordering`` -- list (optional); a total ordering of the groundset + - ``reduced`` -- boolean (default: ``False``) - OUTPUT: a list of frozensets + OUTPUT: :class:`SetSystem` EXAMPLES:: - sage: M = Matroid(circuits=[[1,2,3], [3,4,5], [1,2,4,5]]) + sage: M = Matroid(circuits=[[1, 2, 3], [3, 4, 5], [1, 2, 4, 5]]) sage: SimplicialComplex(M.no_broken_circuits_sets()) Simplicial complex with vertex set (1, 2, 3, 4, 5) and facets {(1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5)} - sage: SimplicialComplex(M.no_broken_circuits_sets([5,4,3,2,1])) + sage: SimplicialComplex(M.no_broken_circuits_sets([5, 4, 3, 2, 1])) Simplicial complex with vertex set (1, 2, 3, 4, 5) and facets {(1, 3, 5), (1, 4, 5), (2, 3, 5), (2, 4, 5)} :: - sage: M = Matroid(circuits=[[1,2,3], [1,4,5], [2,3,4,5]]) - sage: SimplicialComplex(M.no_broken_circuits_sets([5,4,3,2,1])) + sage: M = Matroid(circuits=[[1, 2, 3], [1, 4, 5], [2, 3, 4, 5]]) + sage: SimplicialComplex(M.no_broken_circuits_sets([5, 4, 3, 2, 1])) Simplicial complex with vertex set (1, 2, 3, 4, 5) and facets {(1, 3, 5), (2, 3, 5), (2, 4, 5), (3, 4, 5)} TESTS:: - sage: M = Matroid(circuits=[[1,2,3], [3,4,5], [1,2,4,5]]) + sage: M = Matroid(circuits=[[1, 2, 3], [3, 4, 5], [1, 2, 4, 5]]) sage: C1 = SimplicialComplex(M.no_broken_circuits_sets()) sage: from sage.matroids.basis_matroid import BasisMatroid - sage: M = BasisMatroid(Matroid(circuits=[[1,2,3], [3,4,5], [1,2,4,5]])) + sage: M = BasisMatroid(Matroid(circuits=[[1, 2, 3], [3, 4, 5], [1, 2, 4, 5]])) sage: C2 = SimplicialComplex(M.no_broken_circuits_sets()) sage: C1 == C2 True """ - from sage.matroids.utilities import cmp_elements_key - if ordering is None: - ordering = sorted(self.groundset(), key=cmp_elements_key) - else: - if frozenset(ordering) != self.groundset(): - raise ValueError("not an ordering of the groundset") + from sage.topology.simplicial_complex import SimplicialComplex + cdef set NBC = set() + for f in SimplicialComplex(self.no_broken_circuits_facets(ordering, reduced), + maximality_check=False).face_iterator(): + NBC.add(frozenset(f)) + return SetSystem(list(self.groundset()), NBC) - # compute broken circuits - cdef list BC = [] - for C in self._C: - for e in ordering: - if e in C: - BC.append(C - set([e])) - break + cpdef broken_circuit_complex(self, ordering=None, reduced=False): + r""" + Return the broken circuit complex of ``self``. - cdef list F = [] # broken circuit complex facets - for B in self.bases(): - flag = True - for bc in BC: - if bc <= B: - flag = False - break - if flag: - F.append(B) + The broken circuit complex of a matroid with a total ordering `<` + on the groundset is obtained from the + :meth:`NBC sets ` under subset inclusion. + INPUT: + + - ``ordering`` -- list (optional); a total ordering of the groundset + - ``reduced`` -- boolean (default: ``False``); whether to return the + reduced broken circuit complex (the link at the smallest element) + + OUTPUT: a simplicial complex of the NBC sets under inclusion + + EXAMPLES:: + + sage: M = Matroid(circuits=[[1, 2, 3], [3, 4, 5], [1, 2, 4, 5]]) + sage: M.broken_circuit_complex() + Simplicial complex with vertex set (1, 2, 3, 4, 5) + and facets {(1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5)} + sage: M.broken_circuit_complex([5, 4, 3, 2, 1]) + Simplicial complex with vertex set (1, 2, 3, 4, 5) + and facets {(1, 3, 5), (1, 4, 5), (2, 3, 5), (2, 4, 5)} + sage: M.broken_circuit_complex([5, 4, 3, 2, 1], reduced=True) + Simplicial complex with vertex set (1, 2, 3, 4) + and facets {(1, 3), (1, 4), (2, 3), (2, 4)} + + For a matroid with loops, the broken circuit complex is not defined, + and the method yields an error:: + + sage: M = Matroid(groundset=[0, 1, 2], circuits=[[0]]) + sage: M.broken_circuit_complex() + Traceback (most recent call last): + ... + ValueError: broken circuit complex of matroid with loops is not defined + """ from sage.topology.simplicial_complex import SimplicialComplex - return [frozenset(f) for f in SimplicialComplex(F).face_iterator()] + if self.loops(): + raise ValueError("broken circuit complex of matroid with loops is not defined") + return SimplicialComplex(self.no_broken_circuits_facets(ordering, reduced), maximality_check=False) # properties @@ -654,7 +866,8 @@ cdef class CircuitsMatroid(Matroid): [Oxl2011]_, p. 327. """ - return min(self._k_C, default=float('inf')) + from sage.rings.infinity import infinity + return min(self._k_C, default=infinity) cpdef is_paving(self): """ @@ -689,15 +902,15 @@ cdef class CircuitsMatroid(Matroid): sage: M = Matroid(circuits=C) sage: M.is_valid() True - sage: C = [[1,2], [1, 2, 3], [3, 4, 5], [1, 2, 4, 5]] + sage: C = [[1, 2], [1, 2, 3], [3, 4, 5], [1, 2, 4, 5]] sage: M = Matroid(circuits=C) sage: M.is_valid() False - sage: C = [[3,6], [1, 2, 3], [3, 4, 5], [1, 2, 4, 5]] + sage: C = [[3, 6], [1, 2, 3], [3, 4, 5], [1, 2, 4, 5]] sage: M = Matroid(circuits=C) sage: M.is_valid() False - sage: C = [[3,6], [1, 2, 3], [3, 4, 5], [1, 2, 6], [6, 4, 5], [1, 2, 4, 5]] + sage: C = [[3, 6], [1, 2, 3], [3, 4, 5], [1, 2, 6], [6, 4, 5], [1, 2, 4, 5]] sage: M = Matroid(circuits=C) sage: M.is_valid() True @@ -711,10 +924,9 @@ cdef class CircuitsMatroid(Matroid): False """ from itertools import combinations_with_replacement - cdef int i, j, k, S_len - cdef frozenset C1, C2, C3, I12, U12 - cdef bint flag - for (i, j) in combinations_with_replacement(sorted(self._k_C), 2): + cdef int i, j + cdef frozenset C1, C2, I12, U12 + for (i, j) in combinations_with_replacement(self._sorted_C_lens, 2): # loop through all circuit length pairs (i, j) with i <= j for C1 in self._k_C[i]: if not C1: # the empty set can't be a circuit @@ -730,18 +942,8 @@ cdef class CircuitsMatroid(Matroid): return False # check circuit elimination axiom U12 = C1 | C2 - S_len = len(U12) - 1 # the size of S below for e in I12: - flag = False S = U12 - {e} - for k in self._k_C: - if k <= S_len: - for C3 in self._k_C[k]: - if C3 <= S: - flag = True - break - if flag: - break - if not flag: + if self._is_independent(S): return False return True diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index 331470622de..a274df52180 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -2663,7 +2663,7 @@ cdef class Matroid(SageObject): sage: M = matroids.catalog.Vamos() sage: M.dependent_r_sets(3) - [] + SetSystem of 0 sets over 8 elements sage: sorted([sorted(X) for X in ....: matroids.catalog.Vamos().dependent_r_sets(4)]) [['a', 'b', 'c', 'd'], ['a', 'b', 'e', 'f'], ['a', 'b', 'g', 'h'], @@ -2673,12 +2673,13 @@ cdef class Matroid(SageObject): Test all subsets of the groundset of cardinality ``r`` """ - res = [] - for X in combinations(self.groundset(), r): - X = frozenset(X) - if self._rank(X) < len(X): - res.append(X) - return res + cdef set D = set() + cdef frozenset X + for XX in combinations(self.groundset(), r): + X = frozenset(XX) + if not self._is_independent(X): + D.add(X) + return SetSystem(list(self.groundset()), D) def dependent_r_sets_iterator(self, long r): r""" @@ -2853,10 +2854,9 @@ cdef class Matroid(SageObject): sage: M = matroids.catalog.Pappus() sage: M.independent_r_sets(4) - [] - sage: S = M.independent_r_sets(3) - sage: len(S) - 75 + SetSystem of 0 sets over 9 elements + sage: S = M.independent_r_sets(3); S + SetSystem of 75 sets over 9 elements sage: frozenset({'a', 'c', 'e'}) in S True @@ -2865,12 +2865,13 @@ cdef class Matroid(SageObject): :meth:`M.independent_sets() ` :meth:`M.bases() ` """ - cdef list res = [] - for X in combinations(self.groundset(), r): - X = frozenset(X) - if self._rank(X) == len(X): - res.append(X) - return res + cdef set I = set() + cdef frozenset X + for XX in combinations(self.groundset(), r): + X = frozenset(XX) + if self._is_independent(X): + I.add(X) + return SetSystem(list(self.groundset()), I) def independent_r_sets_iterator(self, r): r""" @@ -3269,7 +3270,7 @@ cdef class Matroid(SageObject): if is_indep: B.append(frozenset(H)) next_level.extend(Ht) - return B + return SetSystem(list(self.groundset()), B) def no_broken_circuits_sets_iterator(self, ordering=None): r""" @@ -8292,6 +8293,15 @@ cdef class Matroid(SageObject): Simplicial complex with vertex set (1, 2, 3, 4, 5) and facets {(1, 3, 5), (1, 4, 5), (2, 3, 5), (2, 4, 5)} + For a matroid with loops, the broken circuit complex is not defined, + and the method yields an error:: + + sage: M = Matroid(flats={0: ['a'], 1: ['ab', 'ac'], 2: ['abc']}) + sage: M.broken_circuit_complex() + Traceback (most recent call last): + ... + ValueError: broken circuit complex of matroid with loops is not defined + TESTS:: sage: for M in matroids.AllMatroids(5): # optional - matroid_database @@ -8305,6 +8315,10 @@ cdef class Matroid(SageObject): from sage.topology.simplicial_complex import SimplicialComplex cdef int r = self.rank() cdef list facets = [] + if self.loops(): + raise ValueError("broken circuit complex of matroid with loops is not defined") + if ordering is None: + ordering = sorted(self.groundset(), key=cmp_elements_key) for S in self.no_broken_circuits_sets_iterator(ordering): if len(S) == r: facets.append(S)