Skip to content

Commit

Permalink
Trac #18751: Add test if a matroid is ternary
Browse files Browse the repository at this point in the history
There is a straightforward test to see if a matroid is ternary: generate
the ternary representation local to a basis, and check matroid
isomorphism. Implement this algorithm. See Matroid.is_binary(), ticket
#18448.

URL: http://trac.sagemath.org/18751
Reported by: Rudi
Ticket author(s): Rudi Pendavingh
Reviewer(s): Michael Welsh
  • Loading branch information
Release Manager authored and vbraun committed Jun 23, 2015
2 parents 550daca + 032b0a0 commit 446a0a5
Show file tree
Hide file tree
Showing 3 changed files with 313 additions and 3 deletions.
120 changes: 120 additions & 0 deletions src/sage/matroids/linear_matroid.pyx
Expand Up @@ -4467,6 +4467,66 @@ cdef class TernaryMatroid(LinearMatroid):
"""
return True

# representability

cpdef ternary_matroid(self, randomized_tests=1, verify = True):
r"""
Return a ternary matroid representing ``self``.
INPUT:
- ``randomized_tests`` -- Ignored.
- ``verify`` -- Ignored
OUTPUT:
A binary matroid.
ALGORITHM:
``self`` is a ternary matroid, so just return ``self``.
.. SEEALSO::
:meth:`M.ternary_matroid()
<sage.matroids.matroid.Matroid.ternary_matroid>`
EXAMPLES::
sage: N = matroids.named_matroids.NonFano()
sage: N.ternary_matroid() is N
True
"""
return self

cpdef is_ternary(self, randomized_tests=1):
r"""
Decide if ``self`` is a binary matroid.
INPUT:
- ``randomized_tests`` -- Ignored.
OUTPUT:
A Boolean.
ALGORITHM:
``self`` is a ternary matroid, so just return ``True``.
.. SEEALSO::
:meth:`M.is_ternary() <sage.matroids.matroid.Matroid.is_ternary>`
EXAMPLES::
sage: N = matroids.named_matroids.NonFano()
sage: N.is_ternary()
True
"""
return True

def __copy__(self):
"""
Create a shallow copy.
Expand Down Expand Up @@ -6008,6 +6068,66 @@ cdef class RegularMatroid(LinearMatroid):
"""
return True

cpdef ternary_matroid(self, randomized_tests=1, verify = True):
r"""
Return a ternary matroid representing ``self``.
INPUT:
- ``randomized_tests`` -- Ignored.
- ``verify`` -- Ignored
OUTPUT:
A ternary matroid.
ALGORITHM:
``self`` is a regular matroid, so just cast ``self`` to a TernaryMatroid.
.. SEEALSO::
:meth:`M.ternary_matroid()
<sage.matroids.matroid.Matroid.ternary_matroid>`
EXAMPLES::
sage: N = matroids.named_matroids.R10()
sage: N.ternary_matroid()
Ternary matroid of rank 5 on 10 elements, type 4+
"""
A, E = self.representation(B = self.basis(), reduced = False, labels = True)
return TernaryMatroid(matrix = A, groundset = E)

cpdef is_ternary(self, randomized_tests=1):
r"""
Decide if ``self`` is a ternary matroid.
INPUT:
- ``randomized_tests`` -- Ignored.
OUTPUT:
A Boolean.
ALGORITHM:
``self`` is a regular matroid, so just return ``True``.
.. SEEALSO::
:meth:`M.is_ternary() <sage.matroids.matroid.Matroid.is_ternary>`
EXAMPLES::
sage: N = matroids.named_matroids.R10()
sage: N.is_ternary()
True
"""
return True

# Copying, loading, saving

def __copy__(self):
Expand Down
3 changes: 3 additions & 0 deletions src/sage/matroids/matroid.pxd
Expand Up @@ -146,6 +146,9 @@ cdef class Matroid(SageObject):
cpdef _local_binary_matroid(self, basis=*)
cpdef binary_matroid(self, randomized_tests=*, verify=*)
cpdef is_binary(self, randomized_tests=*)
cpdef _local_ternary_matroid(self, basis=*)
cpdef ternary_matroid(self, randomized_tests=*, verify=*)
cpdef is_ternary(self, randomized_tests=*)

# matroid k-closed
cpdef is_k_closed(self, int k)
Expand Down
193 changes: 190 additions & 3 deletions src/sage/matroids/matroid.pyx
Expand Up @@ -110,8 +110,10 @@ additional functionality (e.g. linear extensions).
- :meth:`connectivity() <sage.matroids.matroid.Matroid.connectivity>`
- Representation
- :meth:`local_binary_matroid() <sage.matroids.matroid.Matroid.local_binary_matroid>`
- :meth:`binary_matroid() <sage.matroids.matroid.Matroid.binary_matroid>`
- :meth:`is_binary() <sage.matroids.matroid.Matroid.is_binary>`
- :meth:`ternary_matroid() <sage.matroids.matroid.Matroid.ternary_matroid>`
- :meth:`is_ternary() <sage.matroids.matroid.Matroid.is_ternary>`
- Optimization
- :meth:`max_weight_independent() <sage.matroids.matroid.Matroid.max_weight_independent>`
Expand Down Expand Up @@ -325,7 +327,7 @@ from utilities import newlabel, sanitize_contractions_deletions
from sage.rings.all import ZZ
from sage.numerical.mip import MixedIntegerLinearProgram

from sage.matroids.lean_matrix cimport BinaryMatrix
from sage.matroids.lean_matrix cimport BinaryMatrix, TernaryMatrix
from sage.misc.prandom import shuffle


Expand Down Expand Up @@ -5035,7 +5037,7 @@ cdef class Matroid(SageObject):
.. SEEALSO::
:meth:`M.local_binary_matroid()
<sage.matroids.matroid.Matroid.local_binary_matroid>`
<sage.matroids.matroid.Matroid._local_binary_matroid>`
EXAMPLES::
Expand Down Expand Up @@ -5101,6 +5103,191 @@ cdef class Matroid(SageObject):
"""
return self.binary_matroid(randomized_tests=randomized_tests, verify=True) is not None

cpdef _local_ternary_matroid(self, basis=None):
r"""
Return a ternary matroid `M` so that if ``self`` is ternary, then `M` is field
isomorphic to ``self``.
INPUT:
- ``basis`` -- (optional) a set; the basis `B` as above
OUTPUT:
A :class:`TernaryMatroid <sage.matroids.linear_matroid.TernaryMatroid>`.
ALGORITHM:
Suppose `A` is a reduced `B\times E\setminus B` matrix representation of `M`
relative to the given basis `B`. Define the graph `G` with `V(G) = E(M)`, so
that `e, f` are adjacent if and only if `B\triangle \{e, f\}` is a basis
of `M`. Then `A_{ef}` is nonzero if and only `e,f` are adjacent in `G`.
Moreover, if `C` is an induced circuit of `G`, then with `S=E(M)\setminus V(C)\setminus B`
and `T=B\setminus V(C)` the minor `M\setminus S/T` is either
a wheel or a whirl, and over `\GF{3}` this determines `\prod_{ef\in E(C)} A_{ef}`.
Together these properties determine `A` up to scaling of rows and columns of `A`.
The reduced matrix representation `A` is now constructed by fixing a spanning
forest of `G` and setting the corresponding entries of `A` to one. Then one by
one the remaining entries of `A` are fixed using an induced circuit `C` consisting
of the next entry and entries which already have been fixed.
EXAMPLES::
sage: N = matroids.named_matroids.Fano()
sage: M = N._local_ternary_matroid()
sage: N.is_isomorphism(M, {e:e for e in N.groundset()})
False
sage: N = matroids.named_matroids.NonFano()
sage: M = N._local_ternary_matroid()
sage: N.is_isomorphism(M, {e:e for e in N.groundset()})
True
"""
if basis is None:
basis = self.basis()
basis = sorted(basis)
bdx = {basis[i]:i for i in range(len(basis))}
E = sorted(self.groundset())
idx = { E[i]:i for i in range(len(E)) }
A = TernaryMatrix(len(basis), len(E))
for e in basis:
A.set(bdx[e], idx[e], 1)
entries = [(e, f, (e,f)) for e in basis for f in self._fundamental_cocircuit(basis, e).difference([e])]
G = Graph(entries)
T = set()
for C in G.connected_components():
T.update(G.subgraph(C).min_spanning_tree())
for edge in T:
e,f = edge[2]
A.set(bdx[e],idx[f], 1)
W = list(set(G.edges()) - set(T))
H = G.subgraph(edges = T)
while W:
edge = W.pop(-1)
e,f = edge[2]
path = H.shortest_path(e, f)
for i in range(len(W)):
edge2 = W[i]
if edge2[0] in path and edge2[1] in path:
W[i] = edge
edge = edge2
e,f = edge[2]
while path[0]!= e and path[0] != f:
path.pop(0)
while path[-1]!= e and path[-1] != f:
path.pop(-1)
if path[0] == f:
path.reverse()
x = 1
for i in range(len(path)-1):
if i%2 == 0:
x = x * A.get(bdx[path[i]], idx[path[i+1]])
else:
x = x * A.get(bdx[path[i+1]], idx[path[i]])
if (len(path) % 4 == 0) == self.is_dependent(set(basis).symmetric_difference(path)):
A.set(bdx[e],idx[f],x)
else:
A.set(bdx[e],idx[f],-x)
H.add_edge(edge)
from sage.matroids.linear_matroid import TernaryMatroid
return TernaryMatroid(groundset=E, matrix=A, basis=basis, keep_initial_representation=False)

cpdef ternary_matroid(self, randomized_tests=1, verify = True):
r"""
Return a ternary matroid representing ``self``, if such a
representation exists.
INPUT:
- ``randomized_tests`` -- (default: 1) an integer; the number of
times a certain necessary condition for being ternary is tested,
using randomization
- ``verify`` -- (default: ``True``), a Boolean; if ``True``,
any output will be a ternary matroid representing ``self``; if
``False``, any output will represent ``self`` if and only if the
matroid is ternary
OUTPUT:
Either a :class:`TernaryMatroid <sage.matroids.linear_matroid.TernaryMatroid>`, or ``None``
ALGORITHM:
First, compare the ternary matroids local to two random bases.
If these matroids are not isomorphic, return ``None``. This
test is performed ``randomized_tests`` times. Next, if ``verify``
is ``True``, test if a ternary matroid local to some basis is
isomorphic to ``self``.
.. SEEALSO::
:meth:`M._local_ternary_matroid()
<sage.matroids.matroid.Matroid._local_ternary_matroid>`
EXAMPLES::
sage: M = matroids.named_matroids.Fano()
sage: M.ternary_matroid() is None
True
sage: N = matroids.named_matroids.NonFano()
sage: N.ternary_matroid()
NonFano: Ternary matroid of rank 3 on 7 elements, type 0-
"""
M = self._local_ternary_matroid()
m = {e:e for e in self.groundset()}
if randomized_tests > 0:
E = list(self.groundset())
for r in range(randomized_tests):
shuffle(E)
B = self.max_weight_independent(E)
N = self._local_ternary_matroid(B)
if not M.is_field_isomorphism(N, m):
return None
M = N
if self.is_isomorphism(M, m):
return M
else:
return None

cpdef is_ternary(self, randomized_tests=1):
r"""
Decide if ``self`` is a ternary matroid.
INPUT:
- ``randomized_tests`` -- (default: 1) an integer; the number of
times a certain necessary condition for being ternary is tested,
using randomization
OUTPUT:
A Boolean.
ALGORITHM:
First, compare the ternary matroids local to two random bases.
If these matroids are not isomorphic, return ``False``. This
test is performed ``randomized_tests`` times. Next, test if a
ternary matroid local to some basis is isomorphic to ``self``.
.. SEEALSO::
:meth:`M.ternary_matroid()
<sage.matroids.matroid.Matroid.ternary_matroid>`
EXAMPLES::
sage: N = matroids.named_matroids.Fano()
sage: N.is_ternary()
False
sage: N = matroids.named_matroids.NonFano()
sage: N.is_ternary()
True
"""
return self.ternary_matroid(randomized_tests=randomized_tests, verify=True) is not None

# matroid k-closed

cpdef is_k_closed(self, int k):
Expand Down

0 comments on commit 446a0a5

Please sign in to comment.