diff --git a/src/sage/matroids/database_matroids.py b/src/sage/matroids/database_matroids.py index 28a149436f3..c1d92ce7f87 100644 --- a/src/sage/matroids/database_matroids.py +++ b/src/sage/matroids/database_matroids.py @@ -1489,7 +1489,7 @@ def K5dual(groundset='abcdefghij'): EXAMPLES:: sage: M = matroids.catalog.K5dual(); M - M*(K5): Matroid of rank 6 on 10 elements with 15 circuits + M*(K5): Dual of 'Graphic matroid of rank 4 on 10 elements' sage: M.is_3connected() True sage: G1 = M.automorphism_group() @@ -1502,7 +1502,6 @@ def K5dual(groundset='abcdefghij'): [Oxl2011]_, p. 656. """ M = CompleteGraphic(5).dual() - M = Matroid(circuits=list(M.circuits())) M = _rename_and_relabel(M, "M*(K5)", groundset) return M diff --git a/src/sage/matroids/dual_matroid.py b/src/sage/matroids/dual_matroid.py index 37b9e6c046b..44937d0a12f 100644 --- a/src/sage/matroids/dual_matroid.py +++ b/src/sage/matroids/dual_matroid.py @@ -4,7 +4,7 @@ Theory ====== -Let `M` be a matroid with ground set `E`. If `B` is the set of bases of `M`, +Let `M` be a matroid with groundset `E`. If `B` is the set of bases of `M`, then the set `\{E - b : b \in B\}` is the set of bases of another matroid, the dual of `M`. @@ -24,10 +24,9 @@ The class ``DualMatroid`` wraps around a matroid instance to represent its dual. Only useful for classes that don't have an explicit construction of the -dual (such as :class:`RankMatroid ` -and +dual (such as :class:`RankMatroid ` and :class:`CircuitClosuresMatroid `). -It is also used as default implementation of the method +It is also used as the default implementation of the method :meth:`M.dual() `. For direct access to the ``DualMatroid`` constructor, run:: @@ -35,14 +34,11 @@ See also :mod:`sage.matroids.advanced`. - AUTHORS: - Rudi Pendavingh, Michael Welsh, Stefan van Zwam (2013-04-01): initial version - -Methods -======= """ + # **************************************************************************** # Copyright (C) 2013 Rudi Pendavingh # Copyright (C) 2013 Michael Welsh @@ -57,19 +53,18 @@ from .matroid import Matroid - class DualMatroid(Matroid): r""" Dual of a matroid. For some matroid representations it can be computationally expensive to derive an explicit representation of the dual. This class wraps around any - matroid to provide an abstract dual. It also serves as default - implementation. + matroid to provide an abstract dual. It also serves as the default + implementation of the dual. INPUT: - - ``matroid`` - a matroid. + - ``matroid`` -- matroid EXAMPLES:: @@ -103,9 +98,17 @@ def __init__(self, matroid): {'a', 'b', 'g', 'h'}, {'c', 'd', 'e', 'f'}, {'e', 'f', 'g', 'h'}}, 4: {{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}}}' + + TESTS:: + + sage: from sage.matroids.dual_matroid import DualMatroid + sage: DualMatroid([]) + Traceback (most recent call last): + ... + TypeError: no matroid provided to take the dual of """ if not isinstance(matroid, Matroid): - raise TypeError("no matroid provided to take dual of.") + raise TypeError("no matroid provided to take the dual of") self._matroid = matroid def groundset(self): @@ -114,9 +117,7 @@ def groundset(self): The groundset is the set of elements that comprise the matroid. - OUTPUT: - - A set. + OUTPUT: set EXAMPLES:: @@ -135,11 +136,9 @@ def _rank(self, X): INPUT: - - ``X`` -- an object with Python's ``frozenset`` interface. - - OUTPUT: + - ``X`` -- an object with Python's ``frozenset`` interface - The rank of ``X`` in the matroid. + OUTPUT: integer EXAMPLES:: @@ -155,12 +154,10 @@ def _corank(self, X): INPUT: - - ``X`` -- An object with Python's ``frozenset`` interface - containing a subset of ``self.groundset()``. + - ``X`` -- an object with Python's ``frozenset`` interface + containing a subset of ``self.groundset()`` - OUTPUT: - - The corank of ``X``. + OUTPUT: integer EXAMPLES:: @@ -176,12 +173,10 @@ def _max_independent(self, X): INPUT: - - ``X`` -- An object with Python's ``frozenset`` interface containing - a subset of ``self.groundset()``. - - OUTPUT: + - ``X`` -- an object with Python's ``frozenset`` interface containing + a subset of ``self.groundset()`` - A maximal independent subset of ``X``. + OUTPUT: a maximal independent subset of ``X`` EXAMPLES:: @@ -202,13 +197,11 @@ def _circuit(self, X): INPUT: - - ``X`` -- An object with Python's ``frozenset`` interface containing - a subset of ``self.groundset()``. - - OUTPUT: + - ``X`` -- an object with Python's ``frozenset`` interface containing + a subset of ``self.groundset()`` - A circuit contained in ``X``, if it exists. Otherwise an error is - raised. + OUTPUT: a circuit contained in ``X``, if it exists; otherwise, an error is + raised EXAMPLES:: @@ -230,12 +223,10 @@ def _closure(self, X): INPUT: - - ``X`` -- An object with Python's ``frozenset`` interface containing - a subset of ``self.groundset()``. - - OUTPUT: + - ``X`` -- an object with Python's ``frozenset`` interface containing + a subset of ``self.groundset()`` - The smallest closed set containing ``X``. + OUTPUT: the smallest closed set containing ``X`` EXAMPLES:: @@ -251,12 +242,10 @@ def _max_coindependent(self, X): INPUT: - - ``X`` -- An object with Python's ``frozenset`` interface containing - a subset of ``self.groundset()``. - - OUTPUT: + - ``X`` -- an object with Python's ``frozenset`` interface containing + a subset of ``self.groundset()`` - A maximal coindependent subset of ``X``. + OUTPUT: a maximal coindependent subset of ``X`` EXAMPLES:: @@ -277,12 +266,10 @@ def _coclosure(self, X): INPUT: - - ``X`` -- An object with Python's ``frozenset`` interface containing - a subset of ``self.groundset()``. + - ``X`` -- an object with Python's ``frozenset`` interface containing + a subset of ``self.groundset()`` - OUTPUT: - - The smallest coclosed set containing ``X``. + OUTPUT: the smallest coclosed set containing ``X`` EXAMPLES:: @@ -298,13 +285,11 @@ def _cocircuit(self, X): INPUT: - - ``X`` -- An object with Python's ``frozenset`` interface containing - a subset of ``self.groundset()``. - - OUTPUT: + - ``X`` -- an object with Python's ``frozenset`` interface containing + a subset of ``self.groundset()`` - A cocircuit contained in ``X``, if it exists. Otherwise an error is - raised. + OUTPUT: a cocircuit contained in ``X``, if it exists; otherwise, an error is + raised EXAMPLES:: @@ -324,14 +309,12 @@ def _minor(self, contractions=None, deletions=None): INPUT: - - ``contractions`` -- An object with Python's ``frozenset`` interface - containing a subset of ``self.groundset()``. - - ``deletions`` -- An object with Python's ``frozenset`` interface - containing a subset of ``self.groundset()``. + - ``contractions`` -- an object with Python's ``frozenset`` interface + containing a subset of ``self.groundset()`` + - ``deletions`` -- an object with Python's ``frozenset`` interface + containing a subset of ``self.groundset()`` - OUTPUT: - - A ``DualMatroid`` instance representing + OUTPUT: a :class:`DualMatroid` representing `(``self._matroid`` / ``deletions`` \ ``contractions``)^*` .. NOTE:: @@ -339,8 +322,8 @@ def _minor(self, contractions=None, deletions=None): This method does NOT do any checks. Besides the assumptions above, we assume the following: - - ``contractions`` is independent - - ``deletions`` is coindependent + - ``contractions`` is independent; + - ``deletions`` is coindependent; - ``contractions`` and ``deletions`` are disjoint. EXAMPLES:: @@ -364,16 +347,13 @@ def dual(self): r""" Return the dual of the matroid. - Let `M` be a matroid with ground set `E`. If `B` is the set of bases + Let `M` be a matroid with groundset `E`. If `B` is the set of bases of `M`, then the set `\{E - b : b \in B\}` is the set of bases of another matroid, the *dual* of `M`. Note that the dual of the dual of - `M` equals `M`, so if this is the - :class:`DualMatroid` instance + `M` equals `M`, so if this is the :class:`DualMatroid` instance wrapping `M` then the returned matroid is `M`. - OUTPUT: - - The dual matroid. + OUTPUT: the dual matroid EXAMPLES:: @@ -439,11 +419,9 @@ def __eq__(self, other): INPUT: - - ``other`` -- A matroid. + - ``other`` -- matroid - OUTPUT: - - Boolean. + OUTPUT: boolean EXAMPLES:: @@ -471,11 +449,9 @@ def __ne__(self, other): INPUT: - - ``other`` -- A matroid. - - OUTPUT: + - ``other`` -- matroid - Boolean. + OUTPUT: boolean EXAMPLES:: @@ -526,3 +502,64 @@ def __reduce__(self): data = (self._matroid, self.get_custom_name()) version = 0 return sage.matroids.unpickling.unpickle_dual_matroid, (version, data) + + def relabel(self, mapping): + r""" + Return an isomorphic matroid with relabeled groundset. + + The output is obtained by relabeling each element ``e`` by + ``mapping[e]``, where ``mapping`` is a given injective map. If + ``e not in mapping`` then the identity map is assumed. + + INPUT: + + - ``mapping`` -- a python object such that `mapping[e]` is the new + label of `e` + + OUTPUT: matroid + + EXAMPLES:: + + sage: M = matroids.catalog.K5dual(range(10)) + sage: type(M) + + sage: sorted(M.groundset()) + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + sage: N = M.dual().relabel({0:10}) + sage: sorted(N.groundset()) + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + sage: N.is_isomorphic(matroids.catalog.K5()) + True + + TESTS:: + + sage: M = matroids.catalog.K5dual(range(10)) + sage: f = {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', + ....: 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j'} + sage: N = M.relabel(f) + sage: for S in powerset(M.groundset()): + ....: assert M.rank(S) == N.rank([f[x] for x in S]) + """ + M = self._matroid.relabel(mapping).dual() + return M + + def is_valid(self): + """ + Test if ``self`` obeys the matroid axioms. + + For a :class:`DualMatroid`, we check its dual. + + OUTPUT: boolean + + EXAMPLES:: + + sage: M = matroids.catalog.K5dual() + sage: type(M) + + sage: M.is_valid() + True + sage: M = Matroid([[0, 1], [2, 3]]) + sage: M.dual().is_valid() + False + """ + return self._matroid.is_valid()