From b17a2e331d3e4562e26b8096740cb81891b855fa Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Wed, 24 Jan 2024 14:21:18 +0200 Subject: [PATCH 01/10] Add CircuitsMatroid class --- src/doc/en/reference/matroids/index.rst | 1 + src/sage/matroids/circuits_matroid.pxd | 30 ++ src/sage/matroids/circuits_matroid.pyx | 645 ++++++++++++++++++++++++ src/sage/matroids/constructor.py | 42 +- src/sage/matroids/database_matroids.py | 7 +- src/sage/matroids/unpickling.pyx | 53 +- 6 files changed, 747 insertions(+), 31 deletions(-) create mode 100644 src/sage/matroids/circuits_matroid.pxd create mode 100644 src/sage/matroids/circuits_matroid.pyx diff --git a/src/doc/en/reference/matroids/index.rst b/src/doc/en/reference/matroids/index.rst index 4b854c47573..692d798d222 100644 --- a/src/doc/en/reference/matroids/index.rst +++ b/src/doc/en/reference/matroids/index.rst @@ -27,6 +27,7 @@ Concrete implementations :maxdepth: 1 sage/matroids/basis_matroid + sage/matroids/circuits_matroid sage/matroids/circuit_closures_matroid sage/matroids/linear_matroid sage/matroids/rank_matroid diff --git a/src/sage/matroids/circuits_matroid.pxd b/src/sage/matroids/circuits_matroid.pxd new file mode 100644 index 00000000000..2452e639726 --- /dev/null +++ b/src/sage/matroids/circuits_matroid.pxd @@ -0,0 +1,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 dict _k_C # k-circuits (k=len) + cdef bint _nsc_defined + cpdef groundset(self) noexcept + cpdef _rank(self, X) noexcept + cpdef full_rank(self) noexcept + cpdef _is_independent(self, F) noexcept + cpdef _max_independent(self, F) noexcept + cpdef _circuit(self, F) noexcept + + # enumeration + cpdef bases(self) noexcept + cpdef circuits(self, k=*) noexcept + cpdef nonspanning_circuits(self) noexcept + + # properties + cpdef girth(self) noexcept + cpdef is_paving(self) noexcept + + # isomorphism + cpdef _is_isomorphic(self, other, certificate=*) noexcept + + # verification + cpdef is_valid(self) noexcept diff --git a/src/sage/matroids/circuits_matroid.pyx b/src/sage/matroids/circuits_matroid.pyx new file mode 100644 index 00000000000..3c211cc74d3 --- /dev/null +++ b/src/sage/matroids/circuits_matroid.pyx @@ -0,0 +1,645 @@ +r""" +Circuits matroids + +Matroids are characterized by a list of circuits, which are minimal dependent +sets. The CircuitsMatroid class implements matroids using this information as +data. + +A ``CircuitsMatroid`` can be created from another matroid or from a list of +circuits. For a full description of allowed inputs, see +:class:`below `. It is +recommended to use the :func:`Matroid() ` +function for a more flexible construction of a ``CircuitsMatroid``. For direct +access to the ``CircuitsMatroid`` constructor, run:: + + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + +AUTHORS: + +- Giorgos Mousa (2023-12-23): initial version + +TESTS:: + + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + sage: M = CircuitsMatroid(matroids.catalog.Fano()) + sage: TestSuite(M).run() +""" + +# **************************************************************************** +# Copyright (C) 2023 Giorgos Mousa +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# 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 + + +cdef class CircuitsMatroid(Matroid): + r""" + 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 + the matroid + + OUTPUT: + + - If the input is a matroid ``M``, return a ``CircuitsMatroid`` instance + representing ``M``. + - Otherwise, return a ``CircuitsMatroid`` instance based on the + ``groundset`` and ``circuits``. + + .. NOTE:: + + For a more flexible means of input, use the ``Matroid()`` function. + """ + + # necessary (__init__, groundset, _rank) + + def __init__(self, M=None, groundset=None, circuits=None, nsc_defined=False): + """ + Initialization of the matroid. See class docstring for full + documentation. + """ + if M is not None: + self._groundset = frozenset(M.groundset()) + self._C = SetSystem(list(M.groundset()), frozenset([frozenset(C) for C in M.circuits()])) + else: + self._groundset = frozenset(groundset) + self._C = SetSystem(list(groundset), frozenset([frozenset(C) for C in circuits])) + # k-circuits + self._k_C = {} + for C in self._C: + try: + self._k_C[len(C)] += [C] + except KeyError: + self._k_C[len(C)] = [] + self._k_C[len(C)] += [C] + self._matroid_rank = self.rank(self._groundset) + self._nsc_defined = nsc_defined + + cpdef groundset(self) noexcept: + """ + Return the groundset of the matroid. + + The groundset is the set of elements that comprise the matroid. + + OUTPUT: + + a set + + EXAMPLES:: + + sage: M = matroids.Theta(2) + sage: sorted(M.groundset()) + ['x0', 'x1', 'y0', 'y1'] + """ + return self._groundset + + cpdef _rank(self, X) noexcept: + """ + Return the rank of a set ``X``. + + This method does no checking on ``X``, and ``X`` may be assumed to have + the same interface as ``frozenset``. + + INPUT: + + - ``X`` -- an object with Python's ``frozenset`` interface + + OUTPUT: + + an integer; the rank of ``X`` in the matroid + + EXAMPLES:: + + sage: M = matroids.Theta(3) + sage: M._rank(['x1', 'y0', 'y2']) + 2 + """ + return len(self._max_independent(X)) + + # optional + + cpdef full_rank(self) noexcept: + r""" + Return the rank of the 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 + + EXAMPLES:: + + sage: M = matroids.Theta(20) + sage: M.full_rank() + 20 + """ + return self._matroid_rank + + cpdef _is_independent(self, F) noexcept: + """ + Test if input is independent. + + INPUT: + + - ``X`` -- An object with Python's ``frozenset`` interface containing + a subset of ``self.groundset()`` + + OUTPUT: + + boolean + """ + I = set(F) + s = len(F) + for i in self._k_C: + if i <= s: + for C in self._k_C[i]: + if C <= I: + return False + return True + + cpdef _max_independent(self, F) noexcept: + """ + Compute a maximal independent subset. + + INPUT: + + - ``X`` -- An object with Python's ``frozenset`` interface containing + a subset of ``self.groundset()`` + + OUTPUT: + + a frozenset; a maximal independent subset of ``X`` + """ + 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: + for e in C: + break + I.remove(e) + + return frozenset(I) + + cpdef _circuit(self, F) noexcept: + """ + Return a minimal dependent subset. + + INPUT: + + - ``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. Otherwise an + error is raised. + """ + I = set(F) + for C in self.circuits(): + if C <= I: + return C + raise ValueError("no circuit in independent set") + + cpdef _is_isomorphic(self, other, certificate=False) noexcept: + """ + Test if ``self`` is isomorphic to ``other``. + + INPUT: + + - ``other`` -- a matroid + - ``certificate`` -- boolean (optional) + + OUTPUT: + + boolean, and, if certificate = True, a dictionary giving the + isomorphism or None + + .. NOTE:: + + Internal version that does no input checking. + """ + if certificate: + return self._is_isomorphic(other), self._isomorphism(other) + N = CircuitsMatroid(other) + return self._C._isomorphism(N._C) is not None + + # representation + + def _repr_(self): + """ + Return a string representation of the matroid. + """ + if self._nsc_defined: + return Matroid._repr_(self) + " with " + str(len(self.nonspanning_circuits())) + " non-spanning circuits" + else: + return Matroid._repr_(self) + " with " + str(len(self._C)) + " circuits" + + # comparison + + def __hash__(self): + r""" + Return an invariant of the matroid. + + This function is called when matroids are added to a set. It is very + desirable to override it so it can distinguish matroids on the same + groundset, which is a very typical use case! + + .. WARNING:: + + This method is linked to __richcmp__ (in Cython) and __cmp__ or + __eq__/__ne__ (in Python). If you override one, you should + (and in Cython: MUST) override the other! + + EXAMPLES:: + + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + sage: M = CircuitsMatroid(matroids.catalog.Vamos()) + sage: N = CircuitsMatroid(matroids.catalog.Vamos()) + sage: hash(M) == hash(N) + True + sage: O = CircuitsMatroid(matroids.catalog.NonVamos()) + sage: hash(M) == hash(O) + False + """ + return hash(tuple([self.groundset(), frozenset(self._C)])) + + def __richcmp__(left, right, int op): + r""" + Compare two matroids. + + We take a very restricted view on equality: the objects need to be of + the exact same type (so no subclassing) and the internal data need to + be the same. For CircuitsMatroids, this means that the groundsets and + the sets of circuits of the two matroids are equal. + + EXAMPLES:: + + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + sage: M = CircuitsMatroid(matroids.catalog.Pappus()) + sage: N = CircuitsMatroid(matroids.catalog.NonPappus()) + sage: M == N + False + sage: N = Matroid(circuits=M.circuits()) + sage: M == N + True + """ + cdef CircuitsMatroid lt, rt + if op not in [Py_EQ, Py_NE]: + return NotImplemented + if type(left) is not type(right): + return NotImplemented + lt = left + rt = right + if lt.groundset() != rt.groundset(): + return rich_to_bool(op, 1) + if lt.full_rank() != rt.full_rank(): + return rich_to_bool(op, 1) + return richcmp(frozenset(lt._C), frozenset(rt._C), op) + + # copying, loading, saving + + def __copy__(self): + """ + Create a shallow copy. + + EXAMPLES:: + + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + sage: M = CircuitsMatroid(matroids.catalog.Vamos()) + sage: N = copy(M) # indirect doctest + sage: M == N + True + sage: M.groundset() is N.groundset() + True + """ + N = CircuitsMatroid(groundset=[], circuits=[]) + N._groundset = self._groundset + N._C = self._C + N._k_C = self._k_C + N._nsc_defined = self._nsc_defined + N._matroid_rank = self._matroid_rank + N.rename(self.get_custom_name()) + return N + + def __deepcopy__(self, memo=None): + """ + Create a deep copy. + + .. NOTE:: + + Since matroids are immutable, a shallow copy normally suffices. + + EXAMPLES:: + + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + sage: M = CircuitsMatroid(matroids.catalog.Vamos()) + sage: N = deepcopy(M) # indirect doctest + sage: M == N + True + sage: M.groundset() is N.groundset() + False + """ + if memo is None: + memo = {} + from copy import deepcopy + # Since matroids are immutable, N cannot reference itself in correct code, so no need to worry about the recursion. + N = CircuitsMatroid(groundset=deepcopy(self._groundset, memo), circuits=deepcopy(frozenset(self._C), memo)) + N.rename(deepcopy(self.get_custom_name(), memo)) + return N + + def __reduce__(self): + """ + Save the matroid for later reloading. + + OUTPUT: + + A tuple ``(unpickle, (version, data))``, where ``unpickle`` is the + name of a function that, when called with ``(version, data)``, + produces a matroid isomorphic to ``self``. ``version`` is an integer + (currently 0) and ``data`` is a tuple ``(E, C, name)`` where ``E`` is + the groundset, ``C`` is the list of circuits, and ``name`` is a custom + name. + + EXAMPLES:: + + sage: M = matroids.Theta(5) + sage: M == loads(dumps(M)) # indirect doctest + True + sage: M.reset_name() + sage: loads(dumps(M)) + Matroid of rank 5 on 10 elements with 45 circuits + """ + import sage.matroids.unpickling + data = (self._groundset, frozenset(self._C), self.get_custom_name()) + version = 0 + return sage.matroids.unpickling.unpickle_circuits_matroid, (version, data) + + # enumeration + + cpdef bases(self) noexcept: + r""" + Return the bases of the matroid. + + OUTPUT: + + an iterable + + EXAMPLES:: + + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + sage: M = CircuitsMatroid(matroids.Uniform(2, 4)) + """ + cdef SetSystem B + B = SetSystem(list(self.groundset())) + from itertools import combinations + for S in combinations(self._groundset, self._matroid_rank): + flag = True + for C in self.nonspanning_circuits(): + if C <= set(S): + flag = False + break + if flag: + B.append(S) + return B + + def bases_iterator(self): + r""" + Return the bases of the matroid. + + OUTPUT: + + an iterable + + EXAMPLES:: + + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + sage: M = CircuitsMatroid(matroids.Uniform(2, 4)) + """ + from itertools import combinations + for B in combinations(self._groundset, self._matroid_rank): + flag = True + for C in self.nonspanning_circuits(): + if C <= set(B): + flag = False + break + if flag: + yield frozenset(B) + + cpdef circuits(self, k=None) noexcept: + """ + Return the list of circuits of the matroid. + + OUTPUT: + + a SetSystem + """ + cdef SetSystem C + C = SetSystem(list(self.groundset())) + if k: + for c in self._k_C[k]: + C.append(c) + else: + for i in self._k_C: + for c in self._k_C[i]: + C.append(c) + return C + + def circuits_iterator(self, k=None): + """ + Return an iterator over the circuits of the matroid. + + OUTPUT: + + an iterator + """ + if k: + for C in self._k_C[k]: + yield C + else: + for i in self._k_C: + for C in self._k_C[i]: + yield C + + cpdef nonspanning_circuits(self) noexcept: + """ + Return the list of nonspanning circuits of the matroid. + + OUTPUT: + + a SetSystem + """ + cdef SetSystem NSC + NSC = SetSystem(list(self.groundset())) + for i in self._k_C: + if i <= self.rank(): + for C in self._k_C[i]: + NSC.append(C) + return NSC + + def no_broken_circuits_sets(self, order=None): + r""" + Return the no broken circuits (NBC) sets of ``self``. + + An NBC set is a subset `A` of the ground set under some total + ordering `<` such that `A` contains no broken circuit. + + INPUT: + + - ``order`` -- a total ordering of the groundset given as a list + + EXAMPLES:: + + 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])) + 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])) + Simplicial complex with vertex set (1, 2, 3, 4, 5) + and facets {(1, 3, 5), (2, 3, 5), (2, 4, 5), (3, 4, 5)} + """ + if order is None: + order = sorted(self.groundset(), key=str) + else: + if frozenset(order) != self.groundset(): + raise ValueError("not an ordering of the groundset") + + # compute broken circuits + BC = [] + for C in self.circuits(): + for e in order: + if e in C: + BC.append(C - set([e])) + break + + # the facets suffice + for B in self.bases(): + flag = True + for bc in BC: + if bc <= B: + flag = False + break + if flag: + yield B + + # properties + + cpdef girth(self) noexcept: + r""" + Return the girth of the matroid. + + The girth is the size of the smallest circuit. In case the matroid has + no circuits the girth is `\infty`. + + EXAMPLES:: + + sage: matroids.Theta(10).girth() + 3 + + REFERENCES: + + [Oxl2011]_, p. 327. + """ + return min([i for i in self._k_C], default=float('inf')) + + cpdef is_paving(self) noexcept: + """ + Return if ``self`` is paving. + + A matroid is paving if each of its circuits has size `r` or `r+1`. + + OUTPUT: + + boolean + + EXAMPLES:: + + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + sage: M = CircuitsMatroid(matroids.catalog.Vamos()) + sage: M.is_paving() + True + """ + return self.girth() >= self.rank() + + # verification + + cpdef is_valid(self) noexcept: + r""" + Test if self obeys the matroid axioms. + + For a matroid defined by its circuits, we check the circuit axioms. + + OUTPUT: + + boolean + + EXAMPLES:: + + sage: C = [[1, 2, 3], [3, 4, 5], [1, 2, 4, 5]] + 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: M = Matroid(circuits=C) + sage: M.is_valid() + False + 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: M = Matroid(circuits=C) + sage: M.is_valid() + True + sage: C = [[], [1, 2, 3], [3, 4, 5], [1, 2, 4, 5]] + sage: M = Matroid(circuits=C) + sage: M.is_valid() + False + sage: C = [[1, 2, 3], [3, 4, 5]] + sage: M = Matroid(circuits=C) + sage: M.is_valid() + False + """ + for i in self._k_C: + for j in self._k_C: + if i <= j: + for C1 in self._k_C[i]: + if len(C1) == 0: + return False + for C2 in self._k_C[j]: + if C1 < C2: + return False + if C1 == C2: + break + for e in C1 & C2: + flag = False + S = (set(C1) | set(C2)) - {e} + for k in self._k_C: + if k <= len(S) and not flag: + for C3 in self._k_C[k]: + if C3 <= S: + flag = True + break + if not flag: + return False + return True diff --git a/src/sage/matroids/constructor.py b/src/sage/matroids/constructor.py index 34368c34f91..7d25f96e9aa 100644 --- a/src/sage/matroids/constructor.py +++ b/src/sage/matroids/constructor.py @@ -112,6 +112,7 @@ import sage.matroids.matroid import sage.matroids.basis_exchange_matroid from .rank_matroid import RankMatroid +from .circuits_matroid import CircuitsMatroid from .circuit_closures_matroid import CircuitClosuresMatroid from .basis_matroid import BasisMatroid from .linear_matroid import LinearMatroid, RegularMatroid, BinaryMatroid, TernaryMatroid, QuaternaryMatroid @@ -302,21 +303,25 @@ def Matroid(groundset=None, data=None, **kwds): :: sage: M1 = Matroid(groundset='abc', circuits=['bc']) - sage: M2 = Matroid(bases=['ab', 'ac']) - sage: M1 == M2 - True A matroid specified by a list of circuits gets converted to a - :class:`BasisMatroid ` + :class:`CircuitsMatroid ` internally:: + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + sage: M2 = CircuitsMatroid(Matroid(bases=['ab', 'ac'])) + sage: M1 == M2 + True + + + sage: M = Matroid(groundset='abcd', circuits=['abc', 'abd', 'acd', ....: 'bcd']) sage: type(M) - <... 'sage.matroids.basis_matroid.BasisMatroid'> + Strange things can happen if the input does not satisfy the circuit - axioms, and these are not always caught by the + axioms, and these can be caught by the :meth:`is_valid() ` method. So always check whether your input makes sense! @@ -324,11 +329,7 @@ def Matroid(groundset=None, data=None, **kwds): sage: M = Matroid('abcd', circuits=['ab', 'acd']) sage: M.is_valid() - True - sage: [sorted(C) for C in M.circuits()] # random - [['a']] - - + False #. Graph: @@ -762,17 +763,7 @@ def Matroid(groundset=None, data=None, **kwds): groundset = set() for C in data: groundset.update(C) - # determine the rank by computing a basis element - b = set(groundset) - for C in data: - I = b.intersection(C) - if len(I) >= len(C): - b.discard(I.pop()) - rk = len(b) - # Construct the basis matroid of appropriate rank. Note: slow! - BB = [frozenset(B) for B in combinations(groundset, rk) - if not any(frozenset(C).issubset(B) for C in data)] - M = BasisMatroid(groundset=groundset, bases=BB) + M = CircuitsMatroid(groundset=groundset, circuits=data) # Nonspanning circuits: elif key == 'nonspanning_circuits': @@ -796,10 +787,13 @@ def Matroid(groundset=None, data=None, **kwds): break if flag: B += [list(b)] - M = BasisMatroid(groundset=groundset, bases=B) + # convert to circuits matroid defined by non-spanning circuits + M = CircuitsMatroid( + BasisMatroid(groundset=groundset, bases=B), + nsc_defined=True + ) # Graphs: - elif key == 'graph': from sage.graphs.graph import Graph diff --git a/src/sage/matroids/database_matroids.py b/src/sage/matroids/database_matroids.py index 1272efefff5..73ef805ea34 100644 --- a/src/sage/matroids/database_matroids.py +++ b/src/sage/matroids/database_matroids.py @@ -1308,7 +1308,7 @@ def R9(): EXAMPLES:: sage: M = matroids.catalog.R9(); M - R9: Matroid of rank 3 on 9 elements with 69 bases + R9: Matroid of rank 3 on 9 elements with 15 non-spanning circuits sage: M.is_valid() True sage: len(M.nonspanning_circuits()) @@ -2105,7 +2105,7 @@ def Spike(r, t=True, C3=[]): INPUT: - ``r`` -- an integer (`r \ge 3`); the rank of the spike - - ``t`` -- a boolean (default: ``True``); whether the spike is tipped + - ``t`` -- boolean (default: ``True``); whether the spike is tipped - ``C3`` -- a list (default: ``[]``); a list of extra nonspanning circuits. The default (i.e. the empty list) results in a free `r`-spike @@ -2116,7 +2116,8 @@ def Spike(r, t=True, C3=[]): EXAMPLES:: sage: M = matroids.Spike(3, False); M - Free 3-spike\t: Matroid of rank 3 on 6 elements with 20 bases + Free 3-spike\t: M \ {'t'}, where M is Matroid of rank 3 on 7 elements + with 3 non-spanning circuits sage: M.is_isomorphic(matroids.Uniform(3, 6)) True sage: len(matroids.Spike(8).bases()) diff --git a/src/sage/matroids/unpickling.pyx b/src/sage/matroids/unpickling.pyx index d49cf378a63..c791c3aa660 100644 --- a/src/sage/matroids/unpickling.pyx +++ b/src/sage/matroids/unpickling.pyx @@ -28,13 +28,15 @@ AUTHORS: from sage.data_structures.bitset_base cimport * import sage.matroids.matroid import sage.matroids.basis_exchange_matroid -from sage.matroids.minor_matroid import MinorMatroid -from sage.matroids.dual_matroid import DualMatroid -from sage.matroids.circuit_closures_matroid cimport CircuitClosuresMatroid from sage.matroids.basis_matroid cimport BasisMatroid -from sage.matroids.linear_matroid cimport LinearMatroid, RegularMatroid, BinaryMatroid, TernaryMatroid, QuaternaryMatroid +from sage.matroids.circuit_closures_matroid cimport CircuitClosuresMatroid +from sage.matroids.circuits_matroid cimport CircuitsMatroid +from sage.matroids.dual_matroid import DualMatroid from sage.matroids.lean_matrix cimport GenericMatrix, BinaryMatrix, TernaryMatrix, QuaternaryMatrix, PlusMinusOneMatrix, RationalMatrix from sage.matroids.graphic_matroid import GraphicMatroid +from sage.matroids.linear_matroid cimport LinearMatroid, RegularMatroid, BinaryMatroid, TernaryMatroid, QuaternaryMatroid +from sage.matroids.minor_matroid import MinorMatroid + from sage.rings.rational cimport Rational from sage.libs.gmp.mpq cimport mpq_set @@ -88,6 +90,49 @@ def unpickle_basis_matroid(version, data): return M +############################################################################# +# CircuitsMatroid +############################################################################# + +def unpickle_circuits_matroid(version, data): + """ + Unpickle a CircuitsMatroid. + + *Pickling* is Python's term for the loading and saving of objects. + Functions like these serve to reconstruct a saved object. This all happens + transparently through the ``load`` and ``save`` commands, and you should + never have to call this function directly. + + INPUT: + + - ``version`` -- an integer, expected to be 0 + - ``data`` -- a tuple ``(E, C, name)`` in which ``E`` is the groundset + of the matroid, ``C`` is the list of circuits , and ``name`` is a custom + name. + + OUTPUT: + + A matroid. + + .. WARNING:: + + Users should never call this function directly. + + EXAMPLES:: + + sage: M = matroids.Theta(5) + sage: M == loads(dumps(M)) # indirect doctest + True + """ + cdef CircuitsMatroid M + if version != 0: + raise TypeError("object was created with newer version of Sage. Please upgrade.") + M = CircuitsMatroid(groundset=data[0], circuits=data[1]) + if data[2] is not None: + M.rename(data[2]) + return M + + ############################################################################# # CircuitClosuresMatroid ############################################################################# From bed97d8176a726be6cbd7c1e281eb3dd55a2a9cf Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Sat, 3 Feb 2024 14:58:00 +0200 Subject: [PATCH 02/10] Small docstrings edits 1-line outputs and iterable to SetSystem --- src/sage/matroids/circuits_matroid.pyx | 62 +++++++------------------- 1 file changed, 15 insertions(+), 47 deletions(-) diff --git a/src/sage/matroids/circuits_matroid.pyx b/src/sage/matroids/circuits_matroid.pyx index 3c211cc74d3..4eedbfcf8b8 100644 --- a/src/sage/matroids/circuits_matroid.pyx +++ b/src/sage/matroids/circuits_matroid.pyx @@ -92,9 +92,7 @@ cdef class CircuitsMatroid(Matroid): The groundset is the set of elements that comprise the matroid. - OUTPUT: - - a set + OUTPUT: a set EXAMPLES:: @@ -115,9 +113,7 @@ cdef class CircuitsMatroid(Matroid): - ``X`` -- an object with Python's ``frozenset`` interface - OUTPUT: - - an integer; the rank of ``X`` in the matroid + OUTPUT: an integer; the rank of ``X`` in the matroid EXAMPLES:: @@ -136,9 +132,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: an integer; the rank of the matroid EXAMPLES:: @@ -157,9 +151,7 @@ cdef class CircuitsMatroid(Matroid): - ``X`` -- An object with Python's ``frozenset`` interface containing a subset of ``self.groundset()`` - OUTPUT: - - boolean + OUTPUT: boolean """ I = set(F) s = len(F) @@ -179,9 +171,7 @@ cdef class CircuitsMatroid(Matroid): - ``X`` -- An object with Python's ``frozenset`` interface containing a subset of ``self.groundset()`` - OUTPUT: - - a frozenset; a maximal independent subset of ``X`` + OUTPUT: a frozenset; a maximal independent subset of ``X`` """ I = set(F) for i in self._k_C: @@ -203,10 +193,8 @@ cdef class CircuitsMatroid(Matroid): - ``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. Otherwise an - error is raised. + OUTPUT: a frozenset; a circuit contained in ``X``, if it exists. + Otherwise an error is raised. """ I = set(F) for C in self.circuits(): @@ -223,9 +211,7 @@ cdef class CircuitsMatroid(Matroid): - ``other`` -- a matroid - ``certificate`` -- boolean (optional) - OUTPUT: - - boolean, and, if certificate = True, a dictionary giving the + OUTPUT: boolean, and, if certificate = True, a dictionary giving the isomorphism or None .. NOTE:: @@ -394,9 +380,7 @@ cdef class CircuitsMatroid(Matroid): r""" Return the bases of the matroid. - OUTPUT: - - an iterable + OUTPUT: a SetSystem EXAMPLES:: @@ -418,11 +402,7 @@ cdef class CircuitsMatroid(Matroid): def bases_iterator(self): r""" - Return the bases of the matroid. - - OUTPUT: - - an iterable + Return an iterator over the bases of the matroid. EXAMPLES:: @@ -441,11 +421,9 @@ cdef class CircuitsMatroid(Matroid): cpdef circuits(self, k=None) noexcept: """ - Return the list of circuits of the matroid. + Return the circuits of the matroid. - OUTPUT: - - a SetSystem + OUTPUT: a SetSystem """ cdef SetSystem C C = SetSystem(list(self.groundset())) @@ -461,10 +439,6 @@ cdef class CircuitsMatroid(Matroid): def circuits_iterator(self, k=None): """ Return an iterator over the circuits of the matroid. - - OUTPUT: - - an iterator """ if k: for C in self._k_C[k]: @@ -478,9 +452,7 @@ cdef class CircuitsMatroid(Matroid): """ Return the list of nonspanning circuits of the matroid. - OUTPUT: - - a SetSystem + OUTPUT: a SetSystem """ cdef SetSystem NSC NSC = SetSystem(list(self.groundset())) @@ -568,9 +540,7 @@ cdef class CircuitsMatroid(Matroid): A matroid is paving if each of its circuits has size `r` or `r+1`. - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: @@ -589,9 +559,7 @@ cdef class CircuitsMatroid(Matroid): For a matroid defined by its circuits, we check the circuit axioms. - OUTPUT: - - boolean + OUTPUT: boolean EXAMPLES:: From 319cc307bc344a367cf659f4fb40547ccecf601a Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Tue, 6 Feb 2024 16:07:11 +0200 Subject: [PATCH 03/10] Impovements suggested by tscrim --- src/sage/matroids/circuits_matroid.pyx | 88 ++++++++++++++++++-------- src/sage/matroids/matroid.pyx | 5 +- 2 files changed, 67 insertions(+), 26 deletions(-) diff --git a/src/sage/matroids/circuits_matroid.pyx b/src/sage/matroids/circuits_matroid.pyx index 4eedbfcf8b8..d457065d236 100644 --- a/src/sage/matroids/circuits_matroid.pyx +++ b/src/sage/matroids/circuits_matroid.pyx @@ -17,12 +17,6 @@ access to the ``CircuitsMatroid`` constructor, run:: AUTHORS: - Giorgos Mousa (2023-12-23): initial version - -TESTS:: - - sage: from sage.matroids.circuits_matroid import CircuitsMatroid - sage: M = CircuitsMatroid(matroids.catalog.Fano()) - sage: TestSuite(M).run() """ # **************************************************************************** @@ -43,19 +37,16 @@ from cpython.object cimport Py_EQ, Py_NE cdef class CircuitsMatroid(Matroid): r""" + A matroid defined by its circuits. + 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 the matroid - - OUTPUT: - - - If the input is a matroid ``M``, return a ``CircuitsMatroid`` instance - representing ``M``. - - Otherwise, return a ``CircuitsMatroid`` instance based on the - ``groundset`` and ``circuits``. + - ``nsc_defined`` -- boolean (default: ``False``); whether the matroid was + defined by its nonspanning circuits .. NOTE:: @@ -68,6 +59,12 @@ cdef class CircuitsMatroid(Matroid): """ Initialization of the matroid. See class docstring for full documentation. + + TESTS:: + + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + sage: M = CircuitsMatroid(matroids.catalog.Fano()) + sage: TestSuite(M).run() """ if M is not None: self._groundset = frozenset(M.groundset()) @@ -153,8 +150,8 @@ cdef class CircuitsMatroid(Matroid): OUTPUT: boolean """ - I = set(F) - s = len(F) + 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]: @@ -173,7 +170,7 @@ cdef class CircuitsMatroid(Matroid): OUTPUT: a frozenset; a maximal independent subset of ``X`` """ - I = set(F) + 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: @@ -196,8 +193,8 @@ cdef class CircuitsMatroid(Matroid): OUTPUT: a frozenset; a circuit contained in ``X``, if it exists. Otherwise an error is raised. """ - I = set(F) - for C in self.circuits(): + cdef set I = set(F) + for C in self._C: if C <= I: return C raise ValueError("no circuit in independent set") @@ -386,6 +383,8 @@ cdef class CircuitsMatroid(Matroid): sage: from sage.matroids.circuits_matroid import CircuitsMatroid sage: M = CircuitsMatroid(matroids.Uniform(2, 4)) + sage: len(M.bases()) + 6 """ cdef SetSystem B B = SetSystem(list(self.groundset())) @@ -408,6 +407,9 @@ cdef class CircuitsMatroid(Matroid): sage: from sage.matroids.circuits_matroid import CircuitsMatroid sage: M = CircuitsMatroid(matroids.Uniform(2, 4)) + sage: it = M.bases_iterator() + sage: it.__next__() + frozenset({0, 1}) """ from itertools import combinations for B in combinations(self._groundset, self._matroid_rank): @@ -424,6 +426,13 @@ cdef class CircuitsMatroid(Matroid): Return the circuits of the matroid. OUTPUT: a SetSystem + + EXAMPLES:: + + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + sage: M = CircuitsMatroid(matroids.Uniform(2, 4)) + sage: M.circuits() + Iterator over a system of subsets """ cdef SetSystem C C = SetSystem(list(self.groundset())) @@ -439,6 +448,13 @@ cdef class CircuitsMatroid(Matroid): def circuits_iterator(self, k=None): """ Return an iterator over the circuits of the matroid. + + EXAMPLES:: + + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + sage: M = CircuitsMatroid(matroids.Uniform(2, 4)) + sage: sum(1 for C in M.circuits_iterator()) + 4 """ if k: for C in self._k_C[k]: @@ -453,6 +469,13 @@ cdef class CircuitsMatroid(Matroid): Return the list of nonspanning circuits of the matroid. OUTPUT: a SetSystem + + EXAMPLES:: + + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + sage: M = CircuitsMatroid(matroids.Uniform(2, 4)) + sage: M.nonspanning_circuits() + Iterator over a system of subsets """ cdef SetSystem NSC NSC = SetSystem(list(self.groundset())) @@ -462,7 +485,7 @@ cdef class CircuitsMatroid(Matroid): NSC.append(C) return NSC - def no_broken_circuits_sets(self, order=None): + cpdef no_broken_circuits_sets(self, order=None) noexcept: r""" Return the no broken circuits (NBC) sets of ``self``. @@ -473,6 +496,8 @@ cdef class CircuitsMatroid(Matroid): - ``order`` -- a total ordering of the groundset given as a list + OUTPUT: a list of frozensets + EXAMPLES:: sage: M = Matroid(circuits=[[1,2,3], [3,4,5], [1,2,4,5]]) @@ -489,6 +514,16 @@ cdef class CircuitsMatroid(Matroid): 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: 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: C2 = SimplicialComplex(M.no_broken_circuits_sets()) + sage: C1 == C2 + True """ if order is None: order = sorted(self.groundset(), key=str) @@ -497,14 +532,14 @@ cdef class CircuitsMatroid(Matroid): raise ValueError("not an ordering of the groundset") # compute broken circuits - BC = [] - for C in self.circuits(): + cdef list BC = [] + for C in self._C: for e in order: if e in C: BC.append(C - set([e])) break - # the facets suffice + cdef list F = [] # broken circuit complex facets for B in self.bases(): flag = True for bc in BC: @@ -512,7 +547,10 @@ cdef class CircuitsMatroid(Matroid): flag = False break if flag: - yield B + F.append(B) + + from sage.topology.simplicial_complex import SimplicialComplex + return [frozenset(f) for f in SimplicialComplex(F).face_iterator()] # properties @@ -532,7 +570,7 @@ cdef class CircuitsMatroid(Matroid): [Oxl2011]_, p. 327. """ - return min([i for i in self._k_C], default=float('inf')) + return min(self._k_C, default=float('inf')) cpdef is_paving(self) noexcept: """ @@ -555,7 +593,7 @@ cdef class CircuitsMatroid(Matroid): cpdef is_valid(self) noexcept: r""" - Test if self obeys the matroid axioms. + Test if ``self`` obeys the matroid axioms. For a matroid defined by its circuits, we check the circuit axioms. diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index b2d86f1e64a..9bd50d2053b 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -2956,9 +2956,12 @@ cdef class Matroid(SageObject): - ``ordering`` -- a total ordering of the groundset given as a list + OUTPUT: a list of frozensets + EXAMPLES:: - sage: M = Matroid(circuits=[[1,2,3], [3,4,5], [1,2,4,5]]) + sage: from sage.matroids.basis_matroid import BasisMatroid + sage: M = BasisMatroid(Matroid(circuits=[[1,2,3], [3,4,5], [1,2,4,5]])) sage: SimplicialComplex(M.no_broken_circuits_sets()) # needs sage.graphs Simplicial complex with vertex set (1, 2, 3, 4, 5) and facets {(1, 2, 4), (1, 2, 5), (1, 3, 4), (1, 3, 5)} From 29a08652a9a185164013fdc49ef4d9462125a0c2 Mon Sep 17 00:00:00 2001 From: gmou3 <32706872+gmou3@users.noreply.github.com> Date: Tue, 6 Feb 2024 16:09:41 +0200 Subject: [PATCH 04/10] Edit amount of empty lines Co-authored-by: Travis Scrimshaw --- src/sage/matroids/constructor.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/matroids/constructor.py b/src/sage/matroids/constructor.py index f404ca57926..137f4c28230 100644 --- a/src/sage/matroids/constructor.py +++ b/src/sage/matroids/constructor.py @@ -313,8 +313,6 @@ def Matroid(groundset=None, data=None, **kwds): sage: M1 == M2 True - - sage: M = Matroid(groundset='abcd', circuits=['abc', 'abd', 'acd', ....: 'bcd']) sage: type(M) From 3767c65bb022ed3a0c18efd60cd9f7fcf7a191ec Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Tue, 6 Feb 2024 21:14:59 +0200 Subject: [PATCH 05/10] Update circuits_matroid.p* Change 'order' to 'ordering'; use 'ordering' for consistency with matroid.p*. Add nonspanning_circuits_iterator() and improve docstrings. --- src/sage/matroids/circuits_matroid.pxd | 1 + src/sage/matroids/circuits_matroid.pyx | 45 ++++++++++++++++++++------ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/sage/matroids/circuits_matroid.pxd b/src/sage/matroids/circuits_matroid.pxd index 2452e639726..2de06bd16ab 100644 --- a/src/sage/matroids/circuits_matroid.pxd +++ b/src/sage/matroids/circuits_matroid.pxd @@ -18,6 +18,7 @@ cdef class CircuitsMatroid(Matroid): cpdef bases(self) noexcept cpdef circuits(self, k=*) noexcept cpdef nonspanning_circuits(self) noexcept + cpdef no_broken_circuits_sets(self, ordering=*) noexcept # properties cpdef girth(self) noexcept diff --git a/src/sage/matroids/circuits_matroid.pyx b/src/sage/matroids/circuits_matroid.pyx index d457065d236..46e0b989d95 100644 --- a/src/sage/matroids/circuits_matroid.pyx +++ b/src/sage/matroids/circuits_matroid.pyx @@ -2,15 +2,16 @@ r""" Circuits matroids Matroids are characterized by a list of circuits, which are minimal dependent -sets. The CircuitsMatroid class implements matroids using this information as -data. +sets. The ``CircuitsMatroid`` class implements matroids using this information +as data. A ``CircuitsMatroid`` can be created from another matroid or from a list of circuits. For a full description of allowed inputs, see :class:`below `. It is recommended to use the :func:`Matroid() ` -function for a more flexible construction of a ``CircuitsMatroid``. For direct -access to the ``CircuitsMatroid`` constructor, run:: +function for a more flexible way of constructing a ``CircuitsMatroid`` and +other classes of matroids. For direct access to the ``CircuitsMatroid`` +constructor, run:: sage: from sage.matroids.circuits_matroid import CircuitsMatroid @@ -425,6 +426,10 @@ cdef class CircuitsMatroid(Matroid): """ Return the circuits of the matroid. + INPUT: + + - ``k`` -- an integer (optional); the length of the circuits + OUTPUT: a SetSystem EXAMPLES:: @@ -449,6 +454,10 @@ cdef class CircuitsMatroid(Matroid): """ Return an iterator over the circuits of the matroid. + INPUT: + + - ``k`` -- an integer (optional); the length of the circuits + EXAMPLES:: sage: from sage.matroids.circuits_matroid import CircuitsMatroid @@ -485,7 +494,23 @@ cdef class CircuitsMatroid(Matroid): NSC.append(C) return NSC - cpdef no_broken_circuits_sets(self, order=None) noexcept: + def nonspanning_circuits_iterator(self): + """ + Return an iterator over the nonspanning circuits of the matroid. + + EXAMPLES:: + + sage: from sage.matroids.circuits_matroid import CircuitsMatroid + sage: M = CircuitsMatroid(matroids.Uniform(2, 4)) + sage: list(M.nonspanning_circuits_iterator()) + [] + """ + for i in self._k_C: + if i <= self.rank(): + for C in self._k_C[i]: + yield C + + cpdef no_broken_circuits_sets(self, ordering=None) noexcept: r""" Return the no broken circuits (NBC) sets of ``self``. @@ -494,7 +519,7 @@ cdef class CircuitsMatroid(Matroid): INPUT: - - ``order`` -- a total ordering of the groundset given as a list + - ``ordering`` -- a total ordering of the groundset given as a list OUTPUT: a list of frozensets @@ -525,16 +550,16 @@ cdef class CircuitsMatroid(Matroid): sage: C1 == C2 True """ - if order is None: - order = sorted(self.groundset(), key=str) + if ordering is None: + ordering = sorted(self.groundset(), key=str) else: - if frozenset(order) != self.groundset(): + if frozenset(ordering) != self.groundset(): raise ValueError("not an ordering of the groundset") # compute broken circuits cdef list BC = [] for C in self._C: - for e in order: + for e in ordering: if e in C: BC.append(C - set([e])) break From d5646693218d2110c65583be1deef55f7f8224ba Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Wed, 7 Feb 2024 15:17:58 +0200 Subject: [PATCH 06/10] More suggestions by tscrim and docstring improvements More examples and other mostly minor improvements Docstring improvements: 1-line references and outputs, 95 column limit in examples --- src/sage/matroids/circuits_matroid.pyx | 123 ++++++-- src/sage/matroids/database_collections.py | 12 +- src/sage/matroids/database_matroids.py | 368 +++++++--------------- src/sage/matroids/matroid.pyx | 16 +- 4 files changed, 207 insertions(+), 312 deletions(-) diff --git a/src/sage/matroids/circuits_matroid.pyx b/src/sage/matroids/circuits_matroid.pyx index 46e0b989d95..5ab01ab74b3 100644 --- a/src/sage/matroids/circuits_matroid.pyx +++ b/src/sage/matroids/circuits_matroid.pyx @@ -150,6 +150,14 @@ cdef class CircuitsMatroid(Matroid): a subset of ``self.groundset()`` OUTPUT: boolean + + EXAMPLES:: + + sage: M = matroids.Theta(4) + sage: M._is_independent(['y0', 'y1', 'y3', 'x2']) + False + sage: M._is_independent(['y0', 'y2', 'y3', 'x2']) + True """ cdef set I = set(F) cdef int s = len(F) @@ -170,14 +178,19 @@ cdef class CircuitsMatroid(Matroid): a subset of ``self.groundset()`` OUTPUT: a frozenset; a maximal independent subset of ``X`` + + EXAMPLES:: + + sage: M = matroids.Theta(6) + 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: - for e in C: - break + e = next(iter(C)) I.remove(e) return frozenset(I) @@ -193,6 +206,16 @@ cdef class CircuitsMatroid(Matroid): OUTPUT: a frozenset; a circuit contained in ``X``, if it exists. Otherwise an error is raised. + + EXAMPLES:: + + sage: M = matroids.Theta(4) + sage: sorted(M._circuit(['y0', 'y1', 'y3', 'x2'])) + ['x2', 'y0', 'y1', 'y3'] + sage: M._circuit(['y0', 'y2', 'y3', 'x2']) + Traceback (most recent call last): + ... + ValueError: no circuit in independent set """ cdef set I = set(F) for C in self._C: @@ -212,6 +235,17 @@ cdef class CircuitsMatroid(Matroid): OUTPUT: boolean, and, if certificate = True, a dictionary giving the isomorphism or None + EXAMPLES:: + + sage: M = matroids.Spike(3) + sage: from sage.matroids.basis_matroid import BasisMatroid + sage: N = BasisMatroid(M) + sage: M.is_isomorphic(N) + True + sage: N = matroids.catalog.Vamos() + sage: M.is_isomorphic(N) + False + .. NOTE:: Internal version that does no input checking. @@ -226,9 +260,16 @@ cdef class CircuitsMatroid(Matroid): def _repr_(self): """ Return a string representation of the matroid. + + EXAMPLES:: + + sage: matroids.Theta(10) + Theta_10: Matroid of rank 10 on 20 elements with 490 circuits + sage: matroids.catalog.NonDesargues() + NonDesargues: Matroid of rank 3 on 10 elements with 9 nonspanning circuits """ if self._nsc_defined: - return Matroid._repr_(self) + " with " + str(len(self.nonspanning_circuits())) + " non-spanning circuits" + return Matroid._repr_(self) + " with " + str(len(self.nonspanning_circuits())) + " nonspanning circuits" else: return Matroid._repr_(self) + " with " + str(len(self._C)) + " circuits" @@ -387,13 +428,16 @@ cdef class CircuitsMatroid(Matroid): sage: len(M.bases()) 6 """ - cdef SetSystem B + cdef SetSystem B, NSC + cdef bint flag B = SetSystem(list(self.groundset())) + NSC = self.nonspanning_circuits() from itertools import combinations for S in combinations(self._groundset, self._matroid_rank): flag = True - for C in self.nonspanning_circuits(): - if C <= set(S): + S = frozenset(S) + for C in NSC: + if C <= S: flag = False break if flag: @@ -411,16 +455,20 @@ cdef class CircuitsMatroid(Matroid): sage: it = M.bases_iterator() sage: it.__next__() frozenset({0, 1}) + sage: sorted(M.bases_iterator(), key=str) + [frozenset({0, 1}), + frozenset({0, 2}), + frozenset({0, 3}), + frozenset({1, 2}), + frozenset({1, 3}), + frozenset({2, 3})] """ from itertools import combinations + cdef SetSystem NSC = self.nonspanning_circuits() for B in combinations(self._groundset, self._matroid_rank): - flag = True - for C in self.nonspanning_circuits(): - if C <= set(B): - flag = False - break - if flag: - yield frozenset(B) + B = frozenset(B) + if not any(C <= B for C in NSC): + yield B cpdef circuits(self, k=None) noexcept: """ @@ -438,12 +486,20 @@ cdef class CircuitsMatroid(Matroid): sage: M = CircuitsMatroid(matroids.Uniform(2, 4)) sage: M.circuits() Iterator over a system of subsets + sage: list(M.circuits(0)) + [] + sage: sorted(M.circuits(3), key=str) + [frozenset({0, 1, 2}), + frozenset({0, 1, 3}), + frozenset({0, 2, 3}), + frozenset({1, 2, 3})] """ cdef SetSystem C C = SetSystem(list(self.groundset())) - if k: - for c in self._k_C[k]: - C.append(c) + if k is not None: + if k in self._k_C: + for c in self._k_C[k]: + C.append(c) else: for i in self._k_C: for c in self._k_C[i]: @@ -464,10 +520,18 @@ cdef class CircuitsMatroid(Matroid): sage: M = CircuitsMatroid(matroids.Uniform(2, 4)) sage: sum(1 for C in M.circuits_iterator()) 4 - """ - if k: - for C in self._k_C[k]: - yield C + sage: list(M.circuits_iterator(0)) + [] + sage: sorted(M.circuits_iterator(3), key=str) + [frozenset({0, 1, 2}), + frozenset({0, 1, 3}), + frozenset({0, 2, 3}), + frozenset({1, 2, 3})] + """ + if k is not None: + if k in self._k_C: + for C in self._k_C[k]: + yield C else: for i in self._k_C: for C in self._k_C[i]: @@ -475,7 +539,7 @@ cdef class CircuitsMatroid(Matroid): cpdef nonspanning_circuits(self) noexcept: """ - Return the list of nonspanning circuits of the matroid. + Return the nonspanning circuits of the matroid. OUTPUT: a SetSystem @@ -486,13 +550,11 @@ cdef class CircuitsMatroid(Matroid): sage: M.nonspanning_circuits() Iterator over a system of subsets """ - cdef SetSystem NSC - NSC = SetSystem(list(self.groundset())) + cdef list NSC = [] for i in self._k_C: if i <= self.rank(): - for C in self._k_C[i]: - NSC.append(C) - return NSC + NSC.extend(self._k_C[i]) + return SetSystem(list(self.groundset()), NSC) def nonspanning_circuits_iterator(self): """ @@ -591,9 +653,7 @@ cdef class CircuitsMatroid(Matroid): sage: matroids.Theta(10).girth() 3 - REFERENCES: - - [Oxl2011]_, p. 327. + REFERENCES: [Oxl2011]_, p. 327. """ return min(self._k_C, default=float('inf')) @@ -655,16 +715,17 @@ cdef class CircuitsMatroid(Matroid): for j in self._k_C: if i <= j: for C1 in self._k_C[i]: - if len(C1) == 0: + if not C1: return False for C2 in self._k_C[j]: if C1 < C2: return False if C1 == C2: break + UC12 = set(C1) | set(C2) for e in C1 & C2: flag = False - S = (set(C1) | set(C2)) - {e} + S = UC12 - {e} for k in self._k_C: if k <= len(S) and not flag: for C3 in self._k_C[k]: diff --git a/src/sage/matroids/database_collections.py b/src/sage/matroids/database_collections.py index 7480df75e62..f7c67431b07 100644 --- a/src/sage/matroids/database_collections.py +++ b/src/sage/matroids/database_collections.py @@ -102,10 +102,8 @@ def AllMatroids(n, r=None, type="all"): AttributeError: The type "nice" is not available. There needs to be an "is_nice()" attribute for the type to be supported. - REFERENCES: - - The underlying database was retrieved from Yoshitake Matsumoto's Database - of Matroids; see [Mat2012]_. + REFERENCES: The underlying database was retrieved from Yoshitake + Matsumoto's Database of Matroids; see [Mat2012]_. TESTS:: @@ -248,10 +246,8 @@ def OxleyMatroids(): :mod:`Matroid catalog `, under ``Oxley's matroid collection``. - REFERENCES: - - These matroids are the nonparametrized matroids that appear in the - Appendix ``Some Interesting Matroids`` in [Oxl2011]_ (p. 639-64). + REFERENCES: These matroids are the nonparametrized matroids that appear in + the Appendix ``Some Interesting Matroids`` in [Oxl2011]_ (p. 639-64). """ from sage.matroids.database_matroids import ( U24, U25, U35, K4, Whirl3, Q6, P6, U36, R6, diff --git a/src/sage/matroids/database_matroids.py b/src/sage/matroids/database_matroids.py index 73ef805ea34..a420a50b8cd 100644 --- a/src/sage/matroids/database_matroids.py +++ b/src/sage/matroids/database_matroids.py @@ -93,9 +93,7 @@ def U24(): sage: M.is_3connected() True - REFERENCES: - - [Oxl2011]_, p. 639. + REFERENCES: [Oxl2011]_, p. 639. """ M = Uniform(2, 4) return M @@ -116,9 +114,7 @@ def U25(): sage: U25.is_isomorphic(U35.dual()) True - REFERENCES: - - [Oxl2011]_, p. 640. + REFERENCES: [Oxl2011]_, p. 640. """ M = Uniform(2, 5) return M @@ -139,9 +135,7 @@ def U35(): sage: U35.is_isomorphic(U25.dual()) True - REFERENCES: - - [Oxl2011]_, p. 640. + REFERENCES: [Oxl2011]_, p. 640. """ M = Uniform(3, 5) return M @@ -173,9 +167,7 @@ def K4(): sage: M.automorphism_group().is_transitive() True - REFERENCES: - - [Oxl2011]_, p. 640. + REFERENCES: [Oxl2011]_, p. 640. """ M = CompleteGraphic(4) return M @@ -198,8 +190,8 @@ def Whirl3(): sage: W.automorphism_group().is_transitive() False - For all elements `e`, neither `\mathcal{W}_3 \setminus \{e\}` nor - `\mathcal{W}_3 / \{e\}` is `3`-connected:: + For all elements `e`, neither `\mathcal{W}_3 \setminus \{e\}` nor `\mathcal{W}_3 / \{e\}` + is `3`-connected:: sage: import random sage: e = random.choice(list(W.groundset())) @@ -208,9 +200,7 @@ def Whirl3(): sage: W.contract(e).is_3connected() False - REFERENCES: - - [Oxl2011]_, p. 641. + REFERENCES: [Oxl2011]_, p. 641. """ M = Whirl(3) return M @@ -238,9 +228,7 @@ def Q6(): sage: M.automorphism_group().is_transitive() False - REFERENCES: - - [Oxl2011]_, p. 641. + REFERENCES: [Oxl2011]_, p. 641. """ F = GF(4, 'x') x = F.gens()[0] @@ -266,17 +254,14 @@ def P6(): {2: {{'a', 'b', 'c'}}, 3: {{'a', 'b', 'c', 'd', 'e', 'f'}}} sage: len(set(M.nonspanning_circuits()).difference(M.nonbases())) == 0 True - sage: Matroid(matrix=random_matrix(GF(4, 'a'), ncols=5, - ....: nrows=5)).has_minor(M) + sage: Matroid(matrix=random_matrix(GF(4, 'a'), ncols=5, nrows=5)).has_minor(M) False sage: M.is_valid() True sage: M.automorphism_group().is_transitive() False - REFERENCES: - - [Oxl2011]_, p. 641-2. + REFERENCES: [Oxl2011]_, p. 641-2. """ E = 'abcdef' CC = {2: ['abc'], 3: [E]} @@ -305,9 +290,7 @@ def U36(): sage: U36.automorphism_group().structure_description() 'S6' - REFERENCES: - - [Oxl2011]_, p. 642. + REFERENCES: [Oxl2011]_, p. 642. """ M = Uniform(3, 6) return M @@ -334,9 +317,7 @@ def R6(): sage: M.automorphism_group().is_transitive() True - REFERENCES: - - [Oxl2011]_, p. 642. + REFERENCES: [Oxl2011]_, p. 642. """ A = Matrix( GF(3), [[1, 0, 0, 1, 1, 1], [0, 1, 0, 1, 2, 1], [0, 0, 1, 1, 0, 2]] @@ -383,9 +364,7 @@ def Fano(): sage: M.is_isomorphic(matroids.Z(3)) True - REFERENCES: - - [Oxl2011]_, p. 643. + REFERENCES: [Oxl2011]_, p. 643. """ A = Matrix( GF(2), @@ -422,9 +401,7 @@ def FanoDual(): sage: F7D.delete(e).is_isomorphic(K2_3) True - REFERENCES: - - [Oxl2011]_, p. 643. + REFERENCES: [Oxl2011]_, p. 643. """ M = Fano().dual() M.rename("F7*: " + repr(M)) @@ -445,16 +422,14 @@ def NonFano(): sage: M = matroids.catalog.NonFano(); M NonFano: Ternary matroid of rank 3 on 7 elements, type 0- sage: setprint(M.nonbases()) - [{'a', 'b', 'f'}, {'a', 'c', 'e'}, {'a', 'd', 'g'}, {'b', 'c', 'd'}, - {'b', 'e', 'g'}, {'c', 'f', 'g'}] + [{'a', 'b', 'f'}, {'a', 'c', 'e'}, {'a', 'd', 'g'}, + {'b', 'c', 'd'}, {'b', 'e', 'g'}, {'c', 'f', 'g'}] sage: M.delete('f').is_isomorphic(matroids.CompleteGraphic(4)) True sage: M.delete('g').is_isomorphic(matroids.CompleteGraphic(4)) False - REFERENCES: - - [Oxl2011]_, p. 643-4. + REFERENCES: [Oxl2011]_, p. 643-4. """ A = Matrix( GF(3), @@ -479,8 +454,8 @@ def NonFanoDual(): sage: sorted(M.groundset()) ['a', 'b', 'c', 'd', 'e', 'f', 'g'] - Every single-element contraction of `(F_7^-)^*` is isomorphic to `M(K_4)` - or `\mathcal{W}^3`:: + Every single-element contraction of `(F_7^-)^*` is isomorphic to `M(K_4)` or + `\mathcal{W}^3`:: sage: import random sage: e = random.choice(list(M.groundset())) @@ -490,9 +465,7 @@ def NonFanoDual(): sage: N.is_isomorphic(K4) or N.is_isomorphic(W3) True - REFERENCES: - - [Oxl2011]_, p. 643-4. + REFERENCES: [Oxl2011]_, p. 643-4. """ M = NonFano().dual() M.rename("NonFano*: " + repr(M)) @@ -516,9 +489,7 @@ def O7(): sage: M.tutte_polynomial() y^4 + x^3 + x*y^2 + 3*y^3 + 4*x^2 + 5*x*y + 5*y^2 + 4*x + 4*y - REFERENCES: - - [Oxl2011]_, p. 644. + REFERENCES: [Oxl2011]_, p. 644. """ A = Matrix( GF(3), @@ -549,9 +520,7 @@ def P7(): sage: M.is_valid() True - REFERENCES: - - [Oxl2011]_, p. 644-5. + REFERENCES: [Oxl2011]_, p. 644-5. """ A = Matrix( GF(3), @@ -585,8 +554,8 @@ def AG32(): sage: M.equals(M.dual()) True - Every single-element deletion is isomorphic to `F_7^*` and every - single-element contraction is isomorphic to `F_7`:: + Every single-element deletion is isomorphic to `F_7^*` and every single-element + contraction is isomorphic to `F_7`:: sage: F7 = matroids.catalog.Fano() sage: F7D = matroids.catalog.FanoDual() @@ -597,9 +566,7 @@ def AG32(): sage: M.contract(e).is_isomorphic(F7) True - REFERENCES: - - [Oxl2011]_, p. 645. + REFERENCES: [Oxl2011]_, p. 645. """ M = AG(3, 2) return M @@ -640,8 +607,8 @@ def AG32prime(): sage: M.is_isomorphic(M.dual()) and not M.equals(M.dual()) True - Every single-element deletion is isomorphic to `F_7^*` or `(F_7^-)^*` and - every single-element contraction is isomorphic to `F_7` or `F_7^-`:: + Every single-element deletion is isomorphic to `F_7^*` or `(F_7^-)^*` and every + single-element contraction is isomorphic to `F_7` or `F_7^-`:: sage: F7 = matroids.catalog.Fano() sage: F7D = matroids.catalog.FanoDual() @@ -655,9 +622,7 @@ def AG32prime(): sage: Me.is_isomorphic(F7) or Me.is_isomorphic(F7m) True - REFERENCES: - - [Oxl2011]_, p. 646. + REFERENCES: [Oxl2011]_, p. 646. """ CC = { 3: [ @@ -705,9 +670,7 @@ def R8(): sage: M.contract(e).is_isomorphic(F7m) True - REFERENCES: - - [Oxl2011]_, p. 646. + REFERENCES: [Oxl2011]_, p. 646. """ A = Matrix( GF(3), @@ -740,8 +703,7 @@ def F8(): {'a', 'e', 'f', 'h'}, {'b', 'c', 'd', 'g'}, {'b', 'c', 'e', 'f'}, {'c', 'd', 'e', 'h'}, {'c', 'f', 'g', 'h'}, {'d', 'e', 'f', 'g'}}, 4: {{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}}} - sage: D = get_nonisomorphic_matroids([M.contract(i) - ....: for i in M.groundset()]) + sage: D = get_nonisomorphic_matroids([M.contract(i) for i in M.groundset()]) sage: len(D) 3 sage: [N.is_isomorphic(matroids.catalog.Fano()) for N in D] @@ -755,9 +717,7 @@ def F8(): sage: M.automorphism_group().is_transitive() False - REFERENCES: - - [Oxl2011]_, p. 647. + REFERENCES: [Oxl2011]_, p. 647. """ CC = { 3: [ @@ -805,9 +765,7 @@ def Q8(): sage: M.automorphism_group().is_transitive() False - REFERENCES: - - [Oxl2011]_, p. 647. + REFERENCES: [Oxl2011]_, p. 647. """ CC = { 3: [ @@ -857,9 +815,7 @@ def L8(): sage: M.contract(e).is_isomorphic(K4ext) True - REFERENCES: - - [Oxl2011]_, p. 648. + REFERENCES: [Oxl2011]_, p. 648. """ CC = {3: ['abfg', 'bcdg', 'defg', 'cdeh', 'aefh', 'abch', 'aceg', 'bdfh'], 4: ['abcdefgh']} @@ -891,8 +847,7 @@ def S8(): sage: M.is_graphic() False sage: D = get_nonisomorphic_matroids( - ....: list(matroids.catalog.Fano().linear_coextensions( - ....: cosimple=True))) + ....: list(matroids.catalog.Fano().linear_coextensions(cosimple=True))) sage: len(D) 2 sage: [N.is_isomorphic(M) for N in D] @@ -902,9 +857,7 @@ def S8(): sage: M.automorphism_group().is_transitive() False - REFERENCES: - - [Oxl2011]_, p. 648. + REFERENCES: [Oxl2011]_, p. 648. """ A = Matrix( GF(2), @@ -948,9 +901,7 @@ def Vamos(): sage: M.automorphism_group().is_transitive() False - REFERENCES: - - [Oxl2011]_, p. 649. + REFERENCES: [Oxl2011]_, p. 649. """ CC = {3: ['abcd', 'abef', 'cdef', 'abgh', 'efgh'], 4: ['abcdefgh']} M = CircuitClosuresMatroid(groundset='abcdefgh', circuit_closures=CC) @@ -981,9 +932,7 @@ def T8(): sage: M.automorphism_group().is_transitive() False - REFERENCES: - - [Oxl2011]_, p. 649. + REFERENCES: [Oxl2011]_, p. 649. """ A = Matrix( GF(3), @@ -1022,9 +971,7 @@ def J(): sage: M.automorphism_group().is_transitive() False - REFERENCES: - - [Oxl2011]_, p. 650. + REFERENCES: [Oxl2011]_, p. 650. """ A = Matrix( GF(3), @@ -1055,15 +1002,12 @@ def P8(): P8: Ternary matroid of rank 4 on 8 elements, type 2+ sage: M.is_isomorphic(M.dual()) and not M.equals(M.dual()) True - sage: Matroid(matrix=random_matrix(GF(4, 'a'), ncols=5, - ....: nrows=5)).has_minor(M) + sage: Matroid(matrix=random_matrix(GF(4, 'a'), ncols=5, nrows=5)).has_minor(M) False sage: M.bicycle_dimension() 2 - REFERENCES: - - [Oxl2011]_, p. 650-1. + REFERENCES: [Oxl2011]_, p. 650-1. """ A = Matrix( GF(3), @@ -1099,15 +1043,12 @@ def P8pp(): 4: {{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}}} sage: M.is_isomorphic(M.dual()) and not M.equals(M.dual()) True - sage: len(get_nonisomorphic_matroids([M.contract(i) - ....: for i in M.groundset()])) + sage: len(get_nonisomorphic_matroids([M.contract(i) for i in M.groundset()])) 1 sage: M.is_valid() # long time True - REFERENCES: - - [Oxl2011]_, p. 651. + REFERENCES: [Oxl2011]_, p. 651. """ CC = {3: ['abfh', 'bceg', 'cdfh', 'adeg', 'acef', 'bdfg', 'acgh', 'bdeh'], 4: ['abcdefgh']} @@ -1134,9 +1075,7 @@ def Wheel4(): sage: M.automorphism_group().is_transitive() False - REFERENCES: - - [Oxl2011]_, p. 651-2. + REFERENCES: [Oxl2011]_, p. 651-2. """ M = Wheel(4) return M @@ -1160,9 +1099,7 @@ def Whirl4(): sage: M.automorphism_group().is_transitive() False - REFERENCES: - - [Oxl2011]_, p. 652. + REFERENCES: [Oxl2011]_, p. 652. """ M = Whirl(4) return M @@ -1181,17 +1118,14 @@ def K33dual(): sage: M = matroids.catalog.K33dual(); M M*(K3, 3): Regular matroid of rank 4 on 9 elements with 81 bases - sage: any(N.is_3connected() - ....: for N in M.linear_extensions(simple=True)) + sage: any(N.is_3connected() for N in M.linear_extensions(simple=True)) False sage: M.is_valid() True sage: M.automorphism_group().is_transitive() True - REFERENCES: - - [Oxl2011]_, p. 652-3. + REFERENCES: [Oxl2011]_, p. 652-3. """ from sage.graphs.graph_generators import graphs @@ -1219,9 +1153,7 @@ def K33(): sage: G1.is_isomorphic(G2) True - REFERENCES: - - [Oxl2011]_, p. 652-3. + REFERENCES: [Oxl2011]_, p. 652-3. """ from sage.graphs.graph_generators import graphs @@ -1253,9 +1185,7 @@ def AG23(): sage: M.automorphism_group().is_transitive() True - REFERENCES: - - [Oxl2011]_, p. 653. + REFERENCES: [Oxl2011]_, p. 653. """ M = AG(2, 3) return M @@ -1280,9 +1210,7 @@ def TernaryDowling3(): sage: M.automorphism_group().is_transitive() False - REFERENCES: - - [Oxl2011]_, p. 654. + REFERENCES: [Oxl2011]_, p. 654. """ A = Matrix( GF(3), @@ -1308,7 +1236,7 @@ def R9(): EXAMPLES:: sage: M = matroids.catalog.R9(); M - R9: Matroid of rank 3 on 9 elements with 15 non-spanning circuits + R9: Matroid of rank 3 on 9 elements with 15 nonspanning circuits sage: M.is_valid() True sage: len(M.nonspanning_circuits()) @@ -1318,9 +1246,7 @@ def R9(): sage: M.automorphism_group().is_transitive() False - REFERENCES: - - [Oxl2011]_, p. 654. + REFERENCES: [Oxl2011]_, p. 654. """ NSC = ['abc', 'abd', 'acd', 'aef', 'agh', 'bcd', 'bfh', 'bgi', 'ceg', 'cfi', 'deh', 'dei', 'dfg', 'dhi', 'ehi'] @@ -1358,9 +1284,7 @@ def Pappus(groundset=None): sage: M.automorphism_group().is_transitive() True - REFERENCES: - - [Oxl2011]_, p. 655. + REFERENCES: [Oxl2011]_, p. 655. """ CC = {2: ['abc', 'def', 'ceg', 'bfg', 'cdh', 'afh', 'bdi', 'aei', 'ghi'], 3: ['abcdefghi']} @@ -1396,9 +1320,7 @@ def NonPappus(): sage: M.automorphism_group().is_transitive() False - REFERENCES: - - [Oxl2011]_, p. 655. + REFERENCES: [Oxl2011]_, p. 655. """ CC = {2: ['abc', 'ceg', 'bfg', 'cdh', 'afh', 'bdi', 'aei', 'ghi'], 3: ['abcdefghi']} @@ -1423,9 +1345,7 @@ def K5(): sage: M.automorphism_group().is_transitive() True - REFERENCES: - - [Oxl2011]_, p. 656. + REFERENCES: [Oxl2011]_, p. 656. """ M = CompleteGraphic(5) return M @@ -1448,9 +1368,7 @@ def K5dual(): sage: G1.is_isomorphic(G2) True - REFERENCES: - - [Oxl2011]_, p. 656. + REFERENCES: [Oxl2011]_, p. 656. """ M = CompleteGraphic(5).dual() M.rename("M*(K5): " + repr(M)) @@ -1471,7 +1389,7 @@ def R10(): R10: Regular matroid of rank 5 on 10 elements with 162 bases sage: cct = [] sage: for i in M.circuits(): - ....: cct.append(len(i)) + ....: cct.append(len(i)) sage: Set(cct) {4, 6} sage: M.is_isomorphic(M.dual()) and not M.equals(M.dual()) @@ -1498,9 +1416,7 @@ def R10(): sage: matroids.catalog.R10().linear_extensions(simple=True) [] - REFERENCES: - - [Oxl2011]_, p. 656-7. + REFERENCES: [Oxl2011]_, p. 656-7. """ A = Matrix( ZZ, @@ -1527,15 +1443,14 @@ def NonDesargues(groundset=None): EXAMPLES:: - sage: M = matroids.catalog.NonDesargues() + sage: M = matroids.catalog.NonDesargues(); M + NonDesargues: Matroid of rank 3 on 10 elements with 9 nonspanning circuits sage: M.is_valid() True sage: M.automorphism_group().is_transitive() False - REFERENCES: - - [Oxl2011]_, p. 657. + REFERENCES: [Oxl2011]_, p. 657. """ NSC = ['acj', 'aef', 'bce', 'bfj', 'bgi', 'chi', 'dfg', 'dij', 'egh'] M = Matroid(rank=3, nonspanning_circuits=NSC) @@ -1563,9 +1478,7 @@ def R12(groundset='abcdefghijkl'): sage: M.automorphism_group().is_transitive() False - REFERENCES: - - [Oxl2011]_, p. 657. + REFERENCES: [Oxl2011]_, p. 657. """ A = Matrix( ZZ, @@ -1634,9 +1547,7 @@ def ExtendedTernaryGolayCode(): :class:`GolayCode ` - REFERENCES: - - [Oxl2011]_, p. 658. + REFERENCES: [Oxl2011]_, p. 658. """ A = Matrix(GF(3), [ [1, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 0], @@ -1672,9 +1583,7 @@ def T12(): sage: M.automorphism_group().is_transitive() True - REFERENCES: - - [Oxl2011]_, p. 658-9. + REFERENCES: [Oxl2011]_, p. 658-9. """ A = Matrix( GF(2), @@ -1708,9 +1617,7 @@ def PG23(): sage: M.automorphism_group().is_transitive() True - REFERENCES: - - [Oxl2011]_, p. 659. + REFERENCES: [Oxl2011]_, p. 659. """ M = PG(2, 3) return M @@ -1728,9 +1635,7 @@ def Wheel(r, field=None, ring=None): will be a regular matroid. - ``field`` -- any field; same as ``ring``, but only fields are allowed - OUTPUT: - - the rank-`r` wheel matroid, represented as a regular matroid + OUTPUT: the rank-`r` wheel matroid, represented as a regular matroid EXAMPLES:: @@ -1760,9 +1665,7 @@ def Wheel(r, field=None, ring=None): sage: M.automorphism_group().is_transitive() False - REFERENCES: - - [Oxl2011]_, p. 659-60. + REFERENCES: [Oxl2011]_, p. 659-60. """ base_ring = ZZ if field is not None and ring is not None: @@ -1802,9 +1705,7 @@ def Whirl(r): - ``r`` -- a positive integer; the rank of the desired matroid. - OUTPUT: - - the rank-`r` whirl matroid, represented as a ternary matroid + OUTPUT: the rank-`r` whirl matroid, represented as a ternary matroid EXAMPLES:: @@ -1813,8 +1714,8 @@ def Whirl(r): sage: M.is_valid() True sage: M.tutte_polynomial() - x^5 + y^5 + 5*x^4 + 5*x^3*y + 5*x^2*y^2 + 5*x*y^3 + 5*y^4 + 10*x^3 + - 15*x^2*y + 15*x*y^2 + 10*y^3 + 10*x^2 + 15*x*y + 10*y^2 + 5*x + 5*y + x^5 + y^5 + 5*x^4 + 5*x^3*y + 5*x^2*y^2 + 5*x*y^3 + 5*y^4 + 10*x^3 + 15*x^2*y + + 15*x*y^2 + 10*y^3 + 10*x^2 + 15*x*y + 10*y^2 + 5*x + 5*y sage: M.is_isomorphic(matroids.Wheel(5)) False sage: M = matroids.Whirl(3) @@ -1845,9 +1746,7 @@ def Whirl(r): ``[ 1 -1 0]`` ``[ 0 1 -1]`` - REFERENCES: - - [Oxl2011]_, p. 659-60. + REFERENCES: [Oxl2011]_, p. 659-60. """ A = Matrix(GF(3), r, 2 * r, sparse=True) for i in range(r): @@ -1876,9 +1775,7 @@ def Uniform(r, n): - ``n`` -- a nonnegative integer; the number of elements of the uniform matroid - OUTPUT: - - the uniform matroid `U_{r,n}` + OUTPUT: the uniform matroid `U_{r,n}` EXAMPLES:: @@ -1901,9 +1798,7 @@ def Uniform(r, n): sage: len(M.circuit_closures()) 0 - REFERENCES: - - [Oxl2011]_, p. 660. + REFERENCES: [Oxl2011]_, p. 660. """ E = range(n) if r < n: @@ -1930,9 +1825,7 @@ def PG(n, q, x=None): non-prime field, used for non-prime fields. If not supplied, ``'x'`` is used. - OUTPUT: - - a linear matroid whose elements are the points of `PG(n, q)` + OUTPUT: a linear matroid whose elements are the points of `PG(n, q)` EXAMPLES:: @@ -1942,12 +1835,10 @@ def PG(n, q, x=None): sage: matroids.PG(5, 4, 'z').size() == (4^6 - 1) / (4 - 1) True sage: M = matroids.PG(4, 7); M - PG(4, 7): Linear matroid of rank 5 on 2801 elements represented over - the Finite Field of size 7 - - REFERENCES: + PG(4, 7): Linear matroid of rank 5 on 2801 elements represented over the Finite Field + of size 7 - [Oxl2011]_, p. 660. + REFERENCES: [Oxl2011]_, p. 660. """ if x is None: x = 'x' @@ -1977,24 +1868,19 @@ def AG(n, q, x=None): non-prime field, used for non-prime fields. If not supplied, ``'x'`` is used. - OUTPUT: - - a linear matroid whose elements are the points of `AG(n, q)` + OUTPUT: a linear matroid whose elements are the points of `AG(n, q)` EXAMPLES:: sage: M = matroids.AG(2, 3).delete(8) sage: M.is_isomorphic(matroids.catalog.AG23minus()) True - sage: matroids.AG(5, 4, 'z').size() == ((4 ^ 6 - 1) / (4 - 1) - - ....: (4 ^ 5 - 1)/(4 - 1)) + sage: matroids.AG(5, 4, 'z').size() == ((4 ^ 6 - 1) / (4 - 1) - (4 ^ 5 - 1)/(4 - 1)) True sage: M = matroids.AG(4, 2); M AG(4, 2): Binary matroid of rank 5 on 16 elements, type (5, 0) - REFERENCES: - - [Oxl2011]_, p. 661. + REFERENCES: [Oxl2011]_, p. 661. """ if x is None: x = 'x' @@ -2019,9 +1905,7 @@ def Z(r, t=True): - ``r`` -- an integer (`r \ge 3`); the rank of the spike - ``t`` -- a Boolean (default: ``True``); whether the spike is tipped - OUTPUT: - - a matroid; the unique rank-`r` binary spike (tipped or tipless) + OUTPUT: a matroid; the unique rank-`r` binary spike (tipped or tipless) EXAMPLES:: @@ -2064,9 +1948,7 @@ def Z(r, t=True): sage: Z.automorphism_group().is_transitive() True - REFERENCES: - - [Oxl2011]_, p. 661-2. + REFERENCES: [Oxl2011]_, p. 661-2. """ from sage.matrix.special import identity_matrix, ones_matrix Id = Matrix(GF(2), identity_matrix(r)) @@ -2096,7 +1978,7 @@ def Spike(r, t=True, C3=[]): The groundset is `E = \{t, x_1, x_2, \ldots, x_r, y_1, y_2, \ldots, y_r\}` with `r(E) = r`. - The non-spanning circuits are `\{L_1, L_2, \ldots, L_r\}`, all sets of the + The nonspanning circuits are `\{L_1, L_2, \ldots, L_r\}`, all sets of the form `(L_i \cup L_j) \setminus t` for `1 \le i < j \le r`, and some (possibly empty) collection `C_3` of sets of the form `\{z_1, z_2, \ldots, z_r\}` where `z_i \in \{x_i, y_i\}` for all `i`, and no two members of @@ -2109,15 +1991,13 @@ def Spike(r, t=True, C3=[]): - ``C3`` -- a list (default: ``[]``); a list of extra nonspanning circuits. The default (i.e. the empty list) results in a free `r`-spike - OUTPUT: - - a matroid; a rank-`r` spike (tipped or tipless) + OUTPUT: a matroid; a rank-`r` spike (tipped or tipless) EXAMPLES:: sage: M = matroids.Spike(3, False); M - Free 3-spike\t: M \ {'t'}, where M is Matroid of rank 3 on 7 elements - with 3 non-spanning circuits + Free 3-spike\t: M \ {'t'}, where M is Matroid of rank 3 on 7 elements with 3 + nonspanning circuits sage: M.is_isomorphic(matroids.Uniform(3, 6)) True sage: len(matroids.Spike(8).bases()) @@ -2162,9 +2042,7 @@ def Spike(r, t=True, C3=[]): sage: M.equals(M.dual()) True - REFERENCES: - - [Oxl2011]_, p. 662. + REFERENCES: [Oxl2011]_, p. 662. """ if not (r >= 3): raise ValueError("The r-spike is defined for r >= 3.") @@ -2228,9 +2106,7 @@ def Theta(n): - ``n`` -- an integer (`n \ge 2`); the rank of the matroid - OUTPUT: - - a matroid (`\Theta_n`) + OUTPUT: a matroid (`\Theta_n`) EXAMPLES:: @@ -2254,8 +2130,7 @@ def Theta(n): sage: M.is_isomorphic(M.dual()) and not M.equals(M.dual()) True - For `n \le 3`, its automorphism group is transitive, while for `n \ge 4` - it is not:: + For `n \le 3`, its automorphism group is transitive, while for `n \ge 4` it is not:: sage: n = random.choice(range(4, 8)) sage: M = matroids.Theta(2 + n % 2) @@ -2265,9 +2140,7 @@ def Theta(n): sage: M.automorphism_group().is_transitive() False - REFERENCES: - - [Oxl2011]_, p. 663-4. + REFERENCES: [Oxl2011]_, p. 663-4. """ X = ['x'+str(i) for i in range(n)] Y = ['y'+str(i) for i in range(n)] @@ -2302,17 +2175,14 @@ def Psi(r): - ``r`` -- an integer (`r \ge 3`); the rank of the matroid - OUTPUT: - - a matroid (`\Psi_r`) + OUTPUT: a matroid (`\Psi_r`) EXAMPLES:: sage: matroids.Psi(7) Psi_7: Matroid of rank 7 on 14 elements with 2060 bases - The matroid `\Psi_r` is `3`-connected but, for all `r \ge 4`, not - `4`-connected:: + The matroid `\Psi_r` is `3`-connected but, for all `r \ge 4`, not `4`-connected:: sage: M = matroids.Psi(3) sage: M.is_4connected() @@ -2337,9 +2207,7 @@ def Psi(r): sage: M.automorphism_group().is_transitive() True - REFERENCES: - - [Oxl2011]_, p. 664. + REFERENCES: [Oxl2011]_, p. 664. """ A = ['a'+str(i) for i in range(0, r)] B = ['b'+str(i) for i in range(0, r)] @@ -2848,8 +2716,7 @@ def BB9gDY(): EXAMPLES:: sage: M = matroids.catalog.BB9gDY(); M - Segment cosegment exchange on BB9: Quaternary matroid of rank 5 on 9 - elements + Segment cosegment exchange on BB9: Quaternary matroid of rank 5 on 9 elements sage: M.is_valid() True """ @@ -4663,9 +4530,7 @@ def NonVamos(): sage: M.is_valid() # long time True - REFERENCES: - - [Oxl2011]_, p. 72, 84. + REFERENCES: [Oxl2011]_, p. 72, 84. """ E = 'abcdefgh' CC = { @@ -4691,9 +4556,7 @@ def NotP8(): sage: M.is_valid() True - REFERENCES: - - [Oxl1992]_, p.512 (the first edition). + REFERENCES: [Oxl1992]_, p.512 (the first edition). """ A = Matrix(GF(3), [ [1, 0, 0, 0, 0, 1, 1, -1], @@ -4724,9 +4587,7 @@ class of near-regular matroids. sage: M.is_valid() True - REFERENCES: - - [Oxl2011]_, p. 653. + REFERENCES: [Oxl2011]_, p. 653. """ E = 'abcdefgh' CC = {2: ['abc', 'ceh', 'fgh', 'adf', 'aeg', 'cdg', 'bdh', 'bef'], @@ -4747,10 +4608,8 @@ def P9(): sage: M.is_valid() True - REFERENCES: - - This is the matroid referred to as `P_9` by Oxley in his paper "The binary - matroids with no 4-wheel minor", [Oxl1987]_. + REFERENCES: This is the matroid referred to as `P_9` by Oxley in his paper + "The binary matroids with no 4-wheel minor", [Oxl1987]_. """ A = Matrix(GF(2), [ [1, 0, 0, 0, 1, 0, 0, 1, 1], @@ -4813,7 +4672,7 @@ def R9B(): def Block_9_4(): """ - Return the paving matroid whose non-spanning circuits form the blocks of a + Return the paving matroid whose nonspanning circuits form the blocks of a `2-(9, 4, 3)` design. EXAMPLES:: @@ -4850,9 +4709,7 @@ def TicTacToe(): sage: M.is_valid() # long time True - REFERENCES: - - [Hoc]_ + REFERENCES: [Hoc]_ """ E = 'abcdefghi' CC = { @@ -4880,9 +4737,7 @@ def N1(): sage: M.is_valid() True - REFERENCES: - - [Oxl2011]_, p. 554. + REFERENCES: [Oxl2011]_, p. 554. """ A = Matrix(GF(3), [ [1, 0, 0, 0, 0, 2, 0, 0, 1, 1], @@ -4898,7 +4753,7 @@ def N1(): def Block_10_5(): """ - Return the paving matroid whose non-spanning circuits form the blocks of a + Return the paving matroid whose nonspanning circuits form the blocks of a `3-(10, 5, 3)` design. EXAMPLES:: @@ -5008,9 +4863,7 @@ def N2(): sage: M.is_valid() True - REFERENCES: - - [Oxl2011]_, p. 554. + REFERENCES: [Oxl2011]_, p. 554. """ A = Matrix(GF(3), [ [1, 0, 0, 0, 0, 0, 2, 0, 0, 1, 1, 1], @@ -5041,9 +4894,7 @@ def D16(groundset='abcdefghijklmnop'): # A.K.A. the Carolyn Chun Matroid sage: M.is_valid() True - REFERENCES: - - [CMO2012]_ + REFERENCES: [CMO2012]_ """ A = Matrix(GF(2), [ [1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0], @@ -5074,9 +4925,7 @@ def Terrahawk(): # A.K.A. the Dillon Mayhew Matroid sage: M.is_valid() True - REFERENCES: - - [CMO2011]_ + REFERENCES: [CMO2011]_ """ A = Matrix(GF(2), [ [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -5100,8 +4949,7 @@ def ExtendedBinaryGolayCode(): EXAMPLES:: sage: M = matroids.catalog.ExtendedBinaryGolayCode(); M - Extended Binary Golay Code: Binary matroid of rank 12 on 24 elements, - type (12, 0) + Extended Binary Golay Code: Binary matroid of rank 12 on 24 elements, type (12, 0) sage: C = LinearCode(M.representation()) sage: C.is_permutation_equivalent(codes.GolayCode(GF(2))) True @@ -5152,9 +5000,7 @@ def CompleteGraphic(n): - ``n`` -- an integer, the number of vertices of the underlying complete graph. - OUTPUT: - - The graphic matroid associated with the `n`-vertex complete graph. + OUTPUT: The graphic matroid associated with the `n`-vertex complete graph. This matroid has rank `n - 1`. EXAMPLES:: diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index 9bd50d2053b..fc1f5dd9cc2 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -3124,9 +3124,7 @@ cdef class Matroid(SageObject): A 6-dimensional polyhedron in ZZ^7 defined as the convex hull of 29 vertices - REFERENCE: - - - [DLHK2007]_ + REFERENCES: [DLHK2007]_ """ from sage.geometry.polyhedron.constructor import Polyhedron from sage.modules.free_module import FreeModule @@ -3167,9 +3165,7 @@ cdef class Matroid(SageObject): A 7-dimensional polyhedron in ZZ^7 defined as the convex hull of 58 vertices - REFERENCE: - - [DLHK2007]_ + REFERENCES: [DLHK2007]_ """ from sage.geometry.polyhedron.constructor import Polyhedron from sage.modules.free_module import FreeModule @@ -5996,9 +5992,7 @@ cdef class Matroid(SageObject): sage: matroids.catalog.Vamos().girth() 4 - REFERENCES: - - [Oxl2011]_, p. 327. + REFERENCES: [Oxl2011]_, p. 327. """ for k in range(self.rank() + 2): for X in combinations(self.groundset(), k): @@ -7992,9 +7986,7 @@ cdef class Matroid(SageObject): sage: G.structure_description() 'M12' - REFERENCES: - - [Oxl2011]_, p. 189. + REFERENCES: [Oxl2011]_, p. 189. """ from sage.topology.simplicial_complex import SimplicialComplex return SimplicialComplex(self.bases()).automorphism_group() From f63109b2d103ff211dcc4df9cc28ef2e550b1d70 Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Wed, 7 Feb 2024 17:49:06 +0200 Subject: [PATCH 07/10] Less checks and indents in circuits is_valid() --- src/sage/matroids/circuits_matroid.pyx | 51 +++++++++++++------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/src/sage/matroids/circuits_matroid.pyx b/src/sage/matroids/circuits_matroid.pyx index 5ab01ab74b3..f0ddc97eaec 100644 --- a/src/sage/matroids/circuits_matroid.pyx +++ b/src/sage/matroids/circuits_matroid.pyx @@ -230,10 +230,10 @@ cdef class CircuitsMatroid(Matroid): INPUT: - ``other`` -- a matroid - - ``certificate`` -- boolean (optional) + - ``certificate`` -- boolean (default: ``False``) - OUTPUT: boolean, and, if certificate = True, a dictionary giving the - isomorphism or None + OUTPUT: boolean, and, if ``certificate=True``, a dictionary giving the + isomorphism or ``None`` EXAMPLES:: @@ -711,27 +711,28 @@ cdef class CircuitsMatroid(Matroid): sage: M.is_valid() False """ - for i in self._k_C: - for j in self._k_C: - if i <= j: - for C1 in self._k_C[i]: - if not C1: + from itertools import combinations_with_replacement + for (i, j) in combinations_with_replacement(sorted(self._k_C), 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 + return False + for C2 in self._k_C[j]: + if C1 < C2: # a circuit can't be a subset of another circuit + return False + if C1 == C2: + break + # check circuit elimination axiom + UC12 = set(C1) | set(C2) + for e in C1 & C2: + flag = False + S = UC12 - {e} + for k in self._k_C: + if k <= len(S) and not flag: + for C3 in self._k_C[k]: + if C3 <= S: + flag = True + break + if not flag: return False - for C2 in self._k_C[j]: - if C1 < C2: - return False - if C1 == C2: - break - UC12 = set(C1) | set(C2) - for e in C1 & C2: - flag = False - S = UC12 - {e} - for k in self._k_C: - if k <= len(S) and not flag: - for C3 in self._k_C[k]: - if C3 <= S: - flag = True - break - if not flag: - return False return True From 2d18429024338a7df8879fefb0ebc2c84d5e1327 Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Thu, 8 Feb 2024 00:56:06 +0200 Subject: [PATCH 08/10] Revert formatting of references --- src/sage/matroids/circuits_matroid.pyx | 4 +- src/sage/matroids/database_collections.py | 12 +- src/sage/matroids/database_matroids.py | 250 ++++++++++++++++------ src/sage/matroids/matroid.pyx | 16 +- 4 files changed, 210 insertions(+), 72 deletions(-) diff --git a/src/sage/matroids/circuits_matroid.pyx b/src/sage/matroids/circuits_matroid.pyx index f0ddc97eaec..4cf16b6ee32 100644 --- a/src/sage/matroids/circuits_matroid.pyx +++ b/src/sage/matroids/circuits_matroid.pyx @@ -653,7 +653,9 @@ cdef class CircuitsMatroid(Matroid): sage: matroids.Theta(10).girth() 3 - REFERENCES: [Oxl2011]_, p. 327. + REFERENCES: + + [Oxl2011]_, p. 327. """ return min(self._k_C, default=float('inf')) diff --git a/src/sage/matroids/database_collections.py b/src/sage/matroids/database_collections.py index f7c67431b07..c3276be61d6 100644 --- a/src/sage/matroids/database_collections.py +++ b/src/sage/matroids/database_collections.py @@ -102,8 +102,10 @@ def AllMatroids(n, r=None, type="all"): AttributeError: The type "nice" is not available. There needs to be an "is_nice()" attribute for the type to be supported. - REFERENCES: The underlying database was retrieved from Yoshitake - Matsumoto's Database of Matroids; see [Mat2012]_. + REFERENCES: + + The underlying database was retrieved from Yoshitake Matsumoto's Database + of Matroids; see [Mat2012]_. TESTS:: @@ -246,8 +248,10 @@ def OxleyMatroids(): :mod:`Matroid catalog `, under ``Oxley's matroid collection``. - REFERENCES: These matroids are the nonparametrized matroids that appear in - the Appendix ``Some Interesting Matroids`` in [Oxl2011]_ (p. 639-64). + REFERENCES: + + These matroids are the nonparametrized matroids that appear in the Appendix + ``Some Interesting Matroids`` in [Oxl2011]_ (p. 639-64). """ from sage.matroids.database_matroids import ( U24, U25, U35, K4, Whirl3, Q6, P6, U36, R6, diff --git a/src/sage/matroids/database_matroids.py b/src/sage/matroids/database_matroids.py index a420a50b8cd..0a75ce22283 100644 --- a/src/sage/matroids/database_matroids.py +++ b/src/sage/matroids/database_matroids.py @@ -93,7 +93,9 @@ def U24(): sage: M.is_3connected() True - REFERENCES: [Oxl2011]_, p. 639. + REFERENCES: + + [Oxl2011]_, p. 639. """ M = Uniform(2, 4) return M @@ -114,7 +116,9 @@ def U25(): sage: U25.is_isomorphic(U35.dual()) True - REFERENCES: [Oxl2011]_, p. 640. + REFERENCES: + + [Oxl2011]_, p. 640. """ M = Uniform(2, 5) return M @@ -135,7 +139,9 @@ def U35(): sage: U35.is_isomorphic(U25.dual()) True - REFERENCES: [Oxl2011]_, p. 640. + REFERENCES: + + [Oxl2011]_, p. 640. """ M = Uniform(3, 5) return M @@ -167,7 +173,9 @@ def K4(): sage: M.automorphism_group().is_transitive() True - REFERENCES: [Oxl2011]_, p. 640. + REFERENCES: + + [Oxl2011]_, p. 640. """ M = CompleteGraphic(4) return M @@ -200,7 +208,9 @@ def Whirl3(): sage: W.contract(e).is_3connected() False - REFERENCES: [Oxl2011]_, p. 641. + REFERENCES: + + [Oxl2011]_, p. 641. """ M = Whirl(3) return M @@ -228,7 +238,9 @@ def Q6(): sage: M.automorphism_group().is_transitive() False - REFERENCES: [Oxl2011]_, p. 641. + REFERENCES: + + [Oxl2011]_, p. 641. """ F = GF(4, 'x') x = F.gens()[0] @@ -261,7 +273,9 @@ def P6(): sage: M.automorphism_group().is_transitive() False - REFERENCES: [Oxl2011]_, p. 641-2. + REFERENCES: + + [Oxl2011]_, p. 641-2. """ E = 'abcdef' CC = {2: ['abc'], 3: [E]} @@ -290,7 +304,9 @@ def U36(): sage: U36.automorphism_group().structure_description() 'S6' - REFERENCES: [Oxl2011]_, p. 642. + REFERENCES: + + [Oxl2011]_, p. 642. """ M = Uniform(3, 6) return M @@ -317,7 +333,9 @@ def R6(): sage: M.automorphism_group().is_transitive() True - REFERENCES: [Oxl2011]_, p. 642. + REFERENCES: + + [Oxl2011]_, p. 642. """ A = Matrix( GF(3), [[1, 0, 0, 1, 1, 1], [0, 1, 0, 1, 2, 1], [0, 0, 1, 1, 0, 2]] @@ -364,7 +382,9 @@ def Fano(): sage: M.is_isomorphic(matroids.Z(3)) True - REFERENCES: [Oxl2011]_, p. 643. + REFERENCES: + + [Oxl2011]_, p. 643. """ A = Matrix( GF(2), @@ -401,7 +421,9 @@ def FanoDual(): sage: F7D.delete(e).is_isomorphic(K2_3) True - REFERENCES: [Oxl2011]_, p. 643. + REFERENCES: + + [Oxl2011]_, p. 643. """ M = Fano().dual() M.rename("F7*: " + repr(M)) @@ -429,7 +451,9 @@ def NonFano(): sage: M.delete('g').is_isomorphic(matroids.CompleteGraphic(4)) False - REFERENCES: [Oxl2011]_, p. 643-4. + REFERENCES: + + [Oxl2011]_, p. 643-4. """ A = Matrix( GF(3), @@ -465,7 +489,9 @@ def NonFanoDual(): sage: N.is_isomorphic(K4) or N.is_isomorphic(W3) True - REFERENCES: [Oxl2011]_, p. 643-4. + REFERENCES: + + [Oxl2011]_, p. 643-4. """ M = NonFano().dual() M.rename("NonFano*: " + repr(M)) @@ -489,7 +515,9 @@ def O7(): sage: M.tutte_polynomial() y^4 + x^3 + x*y^2 + 3*y^3 + 4*x^2 + 5*x*y + 5*y^2 + 4*x + 4*y - REFERENCES: [Oxl2011]_, p. 644. + REFERENCES: + + [Oxl2011]_, p. 644. """ A = Matrix( GF(3), @@ -520,7 +548,9 @@ def P7(): sage: M.is_valid() True - REFERENCES: [Oxl2011]_, p. 644-5. + REFERENCES: + + [Oxl2011]_, p. 644-5. """ A = Matrix( GF(3), @@ -566,7 +596,9 @@ def AG32(): sage: M.contract(e).is_isomorphic(F7) True - REFERENCES: [Oxl2011]_, p. 645. + REFERENCES: + + [Oxl2011]_, p. 645. """ M = AG(3, 2) return M @@ -622,7 +654,9 @@ def AG32prime(): sage: Me.is_isomorphic(F7) or Me.is_isomorphic(F7m) True - REFERENCES: [Oxl2011]_, p. 646. + REFERENCES: + + [Oxl2011]_, p. 646. """ CC = { 3: [ @@ -670,7 +704,9 @@ def R8(): sage: M.contract(e).is_isomorphic(F7m) True - REFERENCES: [Oxl2011]_, p. 646. + REFERENCES: + + [Oxl2011]_, p. 646. """ A = Matrix( GF(3), @@ -717,7 +753,9 @@ def F8(): sage: M.automorphism_group().is_transitive() False - REFERENCES: [Oxl2011]_, p. 647. + REFERENCES: + + [Oxl2011]_, p. 647. """ CC = { 3: [ @@ -765,7 +803,9 @@ def Q8(): sage: M.automorphism_group().is_transitive() False - REFERENCES: [Oxl2011]_, p. 647. + REFERENCES: + + [Oxl2011]_, p. 647. """ CC = { 3: [ @@ -815,7 +855,9 @@ def L8(): sage: M.contract(e).is_isomorphic(K4ext) True - REFERENCES: [Oxl2011]_, p. 648. + REFERENCES: + + [Oxl2011]_, p. 648. """ CC = {3: ['abfg', 'bcdg', 'defg', 'cdeh', 'aefh', 'abch', 'aceg', 'bdfh'], 4: ['abcdefgh']} @@ -857,7 +899,9 @@ def S8(): sage: M.automorphism_group().is_transitive() False - REFERENCES: [Oxl2011]_, p. 648. + REFERENCES: + + [Oxl2011]_, p. 648. """ A = Matrix( GF(2), @@ -901,7 +945,9 @@ def Vamos(): sage: M.automorphism_group().is_transitive() False - REFERENCES: [Oxl2011]_, p. 649. + REFERENCES: + + [Oxl2011]_, p. 649. """ CC = {3: ['abcd', 'abef', 'cdef', 'abgh', 'efgh'], 4: ['abcdefgh']} M = CircuitClosuresMatroid(groundset='abcdefgh', circuit_closures=CC) @@ -932,7 +978,9 @@ def T8(): sage: M.automorphism_group().is_transitive() False - REFERENCES: [Oxl2011]_, p. 649. + REFERENCES: + + [Oxl2011]_, p. 649. """ A = Matrix( GF(3), @@ -971,7 +1019,9 @@ def J(): sage: M.automorphism_group().is_transitive() False - REFERENCES: [Oxl2011]_, p. 650. + REFERENCES: + + [Oxl2011]_, p. 650. """ A = Matrix( GF(3), @@ -1007,7 +1057,9 @@ def P8(): sage: M.bicycle_dimension() 2 - REFERENCES: [Oxl2011]_, p. 650-1. + REFERENCES: + + [Oxl2011]_, p. 650-1. """ A = Matrix( GF(3), @@ -1048,7 +1100,9 @@ def P8pp(): sage: M.is_valid() # long time True - REFERENCES: [Oxl2011]_, p. 651. + REFERENCES: + + [Oxl2011]_, p. 651. """ CC = {3: ['abfh', 'bceg', 'cdfh', 'adeg', 'acef', 'bdfg', 'acgh', 'bdeh'], 4: ['abcdefgh']} @@ -1075,7 +1129,9 @@ def Wheel4(): sage: M.automorphism_group().is_transitive() False - REFERENCES: [Oxl2011]_, p. 651-2. + REFERENCES: + + [Oxl2011]_, p. 651-2. """ M = Wheel(4) return M @@ -1099,7 +1155,9 @@ def Whirl4(): sage: M.automorphism_group().is_transitive() False - REFERENCES: [Oxl2011]_, p. 652. + REFERENCES: + + [Oxl2011]_, p. 652. """ M = Whirl(4) return M @@ -1125,7 +1183,9 @@ def K33dual(): sage: M.automorphism_group().is_transitive() True - REFERENCES: [Oxl2011]_, p. 652-3. + REFERENCES: + + [Oxl2011]_, p. 652-3. """ from sage.graphs.graph_generators import graphs @@ -1153,7 +1213,9 @@ def K33(): sage: G1.is_isomorphic(G2) True - REFERENCES: [Oxl2011]_, p. 652-3. + REFERENCES: + + [Oxl2011]_, p. 652-3. """ from sage.graphs.graph_generators import graphs @@ -1185,7 +1247,9 @@ def AG23(): sage: M.automorphism_group().is_transitive() True - REFERENCES: [Oxl2011]_, p. 653. + REFERENCES: + + [Oxl2011]_, p. 653. """ M = AG(2, 3) return M @@ -1210,7 +1274,9 @@ def TernaryDowling3(): sage: M.automorphism_group().is_transitive() False - REFERENCES: [Oxl2011]_, p. 654. + REFERENCES: + + [Oxl2011]_, p. 654. """ A = Matrix( GF(3), @@ -1246,7 +1312,9 @@ def R9(): sage: M.automorphism_group().is_transitive() False - REFERENCES: [Oxl2011]_, p. 654. + REFERENCES: + + [Oxl2011]_, p. 654. """ NSC = ['abc', 'abd', 'acd', 'aef', 'agh', 'bcd', 'bfh', 'bgi', 'ceg', 'cfi', 'deh', 'dei', 'dfg', 'dhi', 'ehi'] @@ -1284,7 +1352,9 @@ def Pappus(groundset=None): sage: M.automorphism_group().is_transitive() True - REFERENCES: [Oxl2011]_, p. 655. + REFERENCES: + + [Oxl2011]_, p. 655. """ CC = {2: ['abc', 'def', 'ceg', 'bfg', 'cdh', 'afh', 'bdi', 'aei', 'ghi'], 3: ['abcdefghi']} @@ -1320,7 +1390,9 @@ def NonPappus(): sage: M.automorphism_group().is_transitive() False - REFERENCES: [Oxl2011]_, p. 655. + REFERENCES: + + [Oxl2011]_, p. 655. """ CC = {2: ['abc', 'ceg', 'bfg', 'cdh', 'afh', 'bdi', 'aei', 'ghi'], 3: ['abcdefghi']} @@ -1345,7 +1417,9 @@ def K5(): sage: M.automorphism_group().is_transitive() True - REFERENCES: [Oxl2011]_, p. 656. + REFERENCES: + + [Oxl2011]_, p. 656. """ M = CompleteGraphic(5) return M @@ -1368,7 +1442,9 @@ def K5dual(): sage: G1.is_isomorphic(G2) True - REFERENCES: [Oxl2011]_, p. 656. + REFERENCES: + + [Oxl2011]_, p. 656. """ M = CompleteGraphic(5).dual() M.rename("M*(K5): " + repr(M)) @@ -1416,7 +1492,9 @@ def R10(): sage: matroids.catalog.R10().linear_extensions(simple=True) [] - REFERENCES: [Oxl2011]_, p. 656-7. + REFERENCES: + + [Oxl2011]_, p. 656-7. """ A = Matrix( ZZ, @@ -1450,7 +1528,9 @@ def NonDesargues(groundset=None): sage: M.automorphism_group().is_transitive() False - REFERENCES: [Oxl2011]_, p. 657. + REFERENCES: + + [Oxl2011]_, p. 657. """ NSC = ['acj', 'aef', 'bce', 'bfj', 'bgi', 'chi', 'dfg', 'dij', 'egh'] M = Matroid(rank=3, nonspanning_circuits=NSC) @@ -1478,7 +1558,9 @@ def R12(groundset='abcdefghijkl'): sage: M.automorphism_group().is_transitive() False - REFERENCES: [Oxl2011]_, p. 657. + REFERENCES: + + [Oxl2011]_, p. 657. """ A = Matrix( ZZ, @@ -1547,7 +1629,9 @@ def ExtendedTernaryGolayCode(): :class:`GolayCode ` - REFERENCES: [Oxl2011]_, p. 658. + REFERENCES: + + [Oxl2011]_, p. 658. """ A = Matrix(GF(3), [ [1, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 0], @@ -1583,7 +1667,9 @@ def T12(): sage: M.automorphism_group().is_transitive() True - REFERENCES: [Oxl2011]_, p. 658-9. + REFERENCES: + + [Oxl2011]_, p. 658-9. """ A = Matrix( GF(2), @@ -1617,7 +1703,9 @@ def PG23(): sage: M.automorphism_group().is_transitive() True - REFERENCES: [Oxl2011]_, p. 659. + REFERENCES: + + [Oxl2011]_, p. 659. """ M = PG(2, 3) return M @@ -1665,7 +1753,9 @@ def Wheel(r, field=None, ring=None): sage: M.automorphism_group().is_transitive() False - REFERENCES: [Oxl2011]_, p. 659-60. + REFERENCES: + + [Oxl2011]_, p. 659-60. """ base_ring = ZZ if field is not None and ring is not None: @@ -1746,7 +1836,9 @@ def Whirl(r): ``[ 1 -1 0]`` ``[ 0 1 -1]`` - REFERENCES: [Oxl2011]_, p. 659-60. + REFERENCES: + + [Oxl2011]_, p. 659-60. """ A = Matrix(GF(3), r, 2 * r, sparse=True) for i in range(r): @@ -1798,7 +1890,9 @@ def Uniform(r, n): sage: len(M.circuit_closures()) 0 - REFERENCES: [Oxl2011]_, p. 660. + REFERENCES: + + [Oxl2011]_, p. 660. """ E = range(n) if r < n: @@ -1838,7 +1932,9 @@ def PG(n, q, x=None): PG(4, 7): Linear matroid of rank 5 on 2801 elements represented over the Finite Field of size 7 - REFERENCES: [Oxl2011]_, p. 660. + REFERENCES: + + [Oxl2011]_, p. 660. """ if x is None: x = 'x' @@ -1880,7 +1976,9 @@ def AG(n, q, x=None): sage: M = matroids.AG(4, 2); M AG(4, 2): Binary matroid of rank 5 on 16 elements, type (5, 0) - REFERENCES: [Oxl2011]_, p. 661. + REFERENCES: + + [Oxl2011]_, p. 661. """ if x is None: x = 'x' @@ -1948,7 +2046,9 @@ def Z(r, t=True): sage: Z.automorphism_group().is_transitive() True - REFERENCES: [Oxl2011]_, p. 661-2. + REFERENCES: + + [Oxl2011]_, p. 661-2. """ from sage.matrix.special import identity_matrix, ones_matrix Id = Matrix(GF(2), identity_matrix(r)) @@ -2042,7 +2142,9 @@ def Spike(r, t=True, C3=[]): sage: M.equals(M.dual()) True - REFERENCES: [Oxl2011]_, p. 662. + REFERENCES: + + [Oxl2011]_, p. 662. """ if not (r >= 3): raise ValueError("The r-spike is defined for r >= 3.") @@ -2140,7 +2242,9 @@ def Theta(n): sage: M.automorphism_group().is_transitive() False - REFERENCES: [Oxl2011]_, p. 663-4. + REFERENCES: + + [Oxl2011]_, p. 663-4. """ X = ['x'+str(i) for i in range(n)] Y = ['y'+str(i) for i in range(n)] @@ -2207,7 +2311,9 @@ def Psi(r): sage: M.automorphism_group().is_transitive() True - REFERENCES: [Oxl2011]_, p. 664. + REFERENCES: + + [Oxl2011]_, p. 664. """ A = ['a'+str(i) for i in range(0, r)] B = ['b'+str(i) for i in range(0, r)] @@ -4530,7 +4636,9 @@ def NonVamos(): sage: M.is_valid() # long time True - REFERENCES: [Oxl2011]_, p. 72, 84. + REFERENCES: + + [Oxl2011]_, p. 72, 84. """ E = 'abcdefgh' CC = { @@ -4556,7 +4664,9 @@ def NotP8(): sage: M.is_valid() True - REFERENCES: [Oxl1992]_, p.512 (the first edition). + REFERENCES: + + [Oxl1992]_, p.512 (the first edition). """ A = Matrix(GF(3), [ [1, 0, 0, 0, 0, 1, 1, -1], @@ -4587,7 +4697,9 @@ class of near-regular matroids. sage: M.is_valid() True - REFERENCES: [Oxl2011]_, p. 653. + REFERENCES: + + [Oxl2011]_, p. 653. """ E = 'abcdefgh' CC = {2: ['abc', 'ceh', 'fgh', 'adf', 'aeg', 'cdg', 'bdh', 'bef'], @@ -4608,8 +4720,10 @@ def P9(): sage: M.is_valid() True - REFERENCES: This is the matroid referred to as `P_9` by Oxley in his paper - "The binary matroids with no 4-wheel minor", [Oxl1987]_. + REFERENCES: + + This is the matroid referred to as `P_9` by Oxley in his paper "The binary + matroids with no 4-wheel minor", [Oxl1987]_. """ A = Matrix(GF(2), [ [1, 0, 0, 0, 1, 0, 0, 1, 1], @@ -4709,7 +4823,9 @@ def TicTacToe(): sage: M.is_valid() # long time True - REFERENCES: [Hoc]_ + REFERENCES: + + [Hoc]_ """ E = 'abcdefghi' CC = { @@ -4737,7 +4853,9 @@ def N1(): sage: M.is_valid() True - REFERENCES: [Oxl2011]_, p. 554. + REFERENCES: + + [Oxl2011]_, p. 554. """ A = Matrix(GF(3), [ [1, 0, 0, 0, 0, 2, 0, 0, 1, 1], @@ -4863,7 +4981,9 @@ def N2(): sage: M.is_valid() True - REFERENCES: [Oxl2011]_, p. 554. + REFERENCES: + + [Oxl2011]_, p. 554. """ A = Matrix(GF(3), [ [1, 0, 0, 0, 0, 0, 2, 0, 0, 1, 1, 1], @@ -4894,7 +5014,9 @@ def D16(groundset='abcdefghijklmnop'): # A.K.A. the Carolyn Chun Matroid sage: M.is_valid() True - REFERENCES: [CMO2012]_ + REFERENCES: + + [CMO2012]_ """ A = Matrix(GF(2), [ [1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0], @@ -4925,7 +5047,9 @@ def Terrahawk(): # A.K.A. the Dillon Mayhew Matroid sage: M.is_valid() True - REFERENCES: [CMO2011]_ + REFERENCES: + + [CMO2011]_ """ A = Matrix(GF(2), [ [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index fc1f5dd9cc2..2338c144190 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -3124,7 +3124,9 @@ cdef class Matroid(SageObject): A 6-dimensional polyhedron in ZZ^7 defined as the convex hull of 29 vertices - REFERENCES: [DLHK2007]_ + REFERENCES: + + [DLHK2007]_ """ from sage.geometry.polyhedron.constructor import Polyhedron from sage.modules.free_module import FreeModule @@ -3165,7 +3167,9 @@ cdef class Matroid(SageObject): A 7-dimensional polyhedron in ZZ^7 defined as the convex hull of 58 vertices - REFERENCES: [DLHK2007]_ + REFERENCES: + + [DLHK2007]_ """ from sage.geometry.polyhedron.constructor import Polyhedron from sage.modules.free_module import FreeModule @@ -5992,7 +5996,9 @@ cdef class Matroid(SageObject): sage: matroids.catalog.Vamos().girth() 4 - REFERENCES: [Oxl2011]_, p. 327. + REFERENCES: + + [Oxl2011]_, p. 327. """ for k in range(self.rank() + 2): for X in combinations(self.groundset(), k): @@ -7986,7 +7992,9 @@ cdef class Matroid(SageObject): sage: G.structure_description() 'M12' - REFERENCES: [Oxl2011]_, p. 189. + REFERENCES: + + [Oxl2011]_, p. 189. """ from sage.topology.simplicial_complex import SimplicialComplex return SimplicialComplex(self.bases()).automorphism_group() From d06d2830494110fefd2254b23e16dc29d0770332 Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Thu, 8 Feb 2024 12:11:33 +0200 Subject: [PATCH 09/10] Optimizations suggested by tscrim --- src/sage/matroids/circuits_matroid.pyx | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/sage/matroids/circuits_matroid.pyx b/src/sage/matroids/circuits_matroid.pyx index 4cf16b6ee32..bbcf6ce8319 100644 --- a/src/sage/matroids/circuits_matroid.pyx +++ b/src/sage/matroids/circuits_matroid.pyx @@ -714,27 +714,37 @@ 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): # 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 return False for C2 in self._k_C[j]: - if C1 < C2: # a circuit can't be a subset of another circuit + I12 = C1 & C2 + if not I12: # C1 and C2 are disjoint; nothing to test + continue + if len(I12) == len(C1): + if len(C1) == len(C2): # they are the same circuit + break + # C1 < C2; a circuit can't be a subset of another circuit return False - if C1 == C2: - break # check circuit elimination axiom - UC12 = set(C1) | set(C2) - for e in C1 & C2: + U12 = C1 | C2 + S_len = len(U12) - 1 # the size of S below + for e in I12: flag = False - S = UC12 - {e} + S = U12 - {e} for k in self._k_C: - if k <= len(S) and not flag: + if k <= S_len: for C3 in self._k_C[k]: if C3 <= S: flag = True break + if flag: + break if not flag: return False return True From e3b61195711ae2a8180c29bbfd65db4f15cd6cb9 Mon Sep 17 00:00:00 2001 From: Giorgos Mousa Date: Fri, 9 Feb 2024 13:31:28 +0200 Subject: [PATCH 10/10] Edit unpickling.pyx imports --- src/sage/matroids/unpickling.pyx | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/sage/matroids/unpickling.pyx b/src/sage/matroids/unpickling.pyx index c791c3aa660..2cd946d7503 100644 --- a/src/sage/matroids/unpickling.pyx +++ b/src/sage/matroids/unpickling.pyx @@ -26,22 +26,19 @@ AUTHORS: # **************************************************************************** from sage.data_structures.bitset_base cimport * -import sage.matroids.matroid -import sage.matroids.basis_exchange_matroid +from sage.libs.gmp.mpq cimport mpq_set +from sage.rings.rational cimport Rational + from sage.matroids.basis_matroid cimport BasisMatroid -from sage.matroids.circuit_closures_matroid cimport CircuitClosuresMatroid from sage.matroids.circuits_matroid cimport CircuitsMatroid +from sage.matroids.circuit_closures_matroid cimport CircuitClosuresMatroid from sage.matroids.dual_matroid import DualMatroid -from sage.matroids.lean_matrix cimport GenericMatrix, BinaryMatrix, TernaryMatrix, QuaternaryMatrix, PlusMinusOneMatrix, RationalMatrix from sage.matroids.graphic_matroid import GraphicMatroid +from sage.matroids.lean_matrix cimport GenericMatrix, BinaryMatrix, TernaryMatrix, QuaternaryMatrix, PlusMinusOneMatrix, RationalMatrix from sage.matroids.linear_matroid cimport LinearMatroid, RegularMatroid, BinaryMatroid, TernaryMatroid, QuaternaryMatroid from sage.matroids.minor_matroid import MinorMatroid -from sage.rings.rational cimport Rational -from sage.libs.gmp.mpq cimport mpq_set - - ############################################################################# # BasisMatroid ############################################################################# @@ -403,11 +400,11 @@ def unpickle_rational_matrix(version, data): mpq_set(A._entries[i], ( data[2][i]).value) return A + ############################################################################# # LinearMatroid and subclasses ############################################################################# - def unpickle_linear_matroid(version, data): """ Unpickle a LinearMatroid. @@ -688,11 +685,11 @@ def unpickle_minor_matroid(version, data): M.rename(data[3]) return M + ############################################################################# # Graphic Matroids ############################################################################# - def unpickle_graphic_matroid(version, data): """ Unpickle a GraphicMatroid.