Over at the MatroidUnion, Irene has written a comprehensive series of posts on classes of matroids that arise from biased graphs, so head there for more details on how even cycle matroids fit into the grand scheme of things. In this post however, we’ll just think about even cycle matroids on their own. This is also the first post I’ve written in Markdown, rather than battling with the visual editor, and while it formats the code nicely, I can’t make it format the *output* nicely (without the line numbers etc).

It is often convenient to identify a binary matroid with the *row space* of any (and hence all) of its representing matrices. For example, we’ve already discussed *graphic matroids* which are the binary matroids that can be represented by the vertex-edge incidence matrix of a graph, and so we’ll just call a subspace *graphic* if it is the row space of such a matrix. An *even cycle* matroid is a binary matroid that can be represented by the vertex-edge incidence matrix of a graph with an extra row added or, equivalently, a binary vector space containing a *graphic subspace* of codimension one.

There is no fast algorithm known for checking if a binary matroid is an even cycle matroid and so we have to just check all of its subspaces of codimension one for being graphic. It is easy to see that all the subspaces of codimension one can be obtained from a matroid M by *extending* M by a binary element e not in M and then immediately *contracting* e and so we get the following function:

def is_evencycle(m):
if (m.rank() < 4):
return true
else:
return any([n.contract('X').is_graphic()
for n in m.linear_extensions('X')])

This uses the name ‘X’ to label the new element that is immediately contracted. If one of the elements of m is already called ‘X’, then the linear extensions method will fail. A more careful approach would be to first find a *definitely* new label.

Even-cycle matroids form a minor-closed class and so a very natural problem is the determination of the excluded minors for this class. We’ll certainly need to able to *check* that a matroid is an excluded minor – recall that this means that the matroid is not *itself* an even cycle matroid, but all of its single element deletions and contractions are even cycle matroids. We can easily modify the code that we used for graphic matroids to get:

def is_excludedminor_evencycle(m):
return (not is_evencycle(m)
and all([is_evencycle(m.contract(x)) for x in m.groundset()])
and all([is_evencycle(m.delete(x)) for x in m.groundset()]))

Let’s use this to find the excluded minors for even cycle matroids of rank at most 5 in the most naive fashion possible, in other words, simply applying the function to every one of the 1372 binary matroids of rank at most 5. Assume that an array called “rank5s” has been defined such that “rank5s[e]” contains all the e-element binary matroids of rank at most 5. (It is fairly easy to make such an array using Sage.)

exminors = []
for e in range(32):
for m in rank5s[e]:
if is_excludedminor_evencycle(m):
exminors.append(m)

What do we get at the end of this?

sage: len(exminors)
13
sage: [ [m.rank(),m.size()] for m in exminors]
[[5, 12],
[5, 12],
[5, 13],
[5, 13],
[5, 13],
[5, 13],
[4, 14],
[5, 14],
[5, 14],
[5, 14],
[5, 14],
[5, 15],
[5, 15]]

There is a unique excluded minor of size 14 and rank 4, which can only be , the

matroid obtained by deleting an arbitrary element from , but the 12 additional excluded minors of rank 5 do not bode well for an excluded minor characterisation of even cycle matroids.

In fact, we’ll see in a later post in this series that things are even worse than it seems, but let’s return to the main point of this post, which is to demonstrate the relative ease of building on the functions provided in sage-matroids.

One fundamentally unsatisfying aspect of this code for excluded minors is that we’ve written two almost identical functions for the “excluded minor” functionality, but changing the occurrences of

m.is_graphic()

to

is_evencycle(m)

and if we continue to work with more properties, then we’ll need a separate function for

each and every property.

There is, however, a better way — we can create a function so that the property to

be tested is one of the *parameters* of the function.

def is_excluded_minor(p,m):
return (
not p(m)
and all([p(n) for n in [m.contract(e) for e in m.groundset()]])
and all([p(n) for n in [m.delete(e) for e in m.groundset()]]))

Now we can simply test whether a matroid is an excluded minor for the class of even cycle

matroids with

is_excluded_minor(is_evencycle, m)

and if we subsequently write a function for testing some other property, say whether the

matroid is an *even cut* matroid, then we can just insert the new property name into the

same function.

is_excluded_minor(is_evencut, m)

The only minor wrinkle is to remember to use the right name for the built-in functions.

is_excluded_minor(BinaryMatroid.is_graphic, m)

Next time, we’ll look a little more closely at the excluded minors for the even cycle matroids

and try to work out just how bad things might get!