Circle Graphs

To construct a circle graph we first choose $n$ pairs of points on a circle in the real plane and then join each pair of points by a straight line, a chord. These chords are the vertices of the circle graph and they are adjacent if and only if they cross.

In fact we can view our $2n$ points as the vertices on the cycle of length $2n$, and represent the chords by a perfect matching in the complete graph on the vertices of the cycle. We call this structure a chord diagram. This can be viewed as a cubic graph, with a parallel edge wherever the matching edge is also an edge in the cycle. Since a matching edge which is parallel to a cycle edge does not cross another matching edge, it forms an isolated vertex in the circle graph. For most purposes we can therefore assume that the matching has no edge in the cycle---it's a subgraph of $\comp{C_{2n}}$.

Chord diagrams arise in knot theory. Suppose we have a knot drawn in the plane; assume that there are $n$ crossings labelled 1 through $n$. The knot is an embedding of a circle and, on walking around this circle we see a sequence of $2n$ integers. The terms of the sequence are elements of $\{1,\ldots,n\}$, and each element occurs twice. Such a sequence is known as a double occurrence word. We could even encode the actual knot by assigning $i^+$ to the overpass and $i^-$ to the underpass, but we digress. Each double occurrence word determines a chord diagram with $n$ chords--- simply write the word on the vertices of $C_{2n}$ in the natural way, and then join vertices with the same label by an edge.

For the moment at least, we specify a circle graph on $n$ vertices by a perfect matching in $K_{2n}$, and thus by a set of $n$ edges. We need to decide if two edges of the matching cross:

def cross(e1,e2):
    if e1[1]<e1[0]: e1[0],e1[1] = e1[1],e1[0]
    if e2[1]<e2[0]: e2[0],e2[1] = e2[1],e2[0]
    return (e1[0]<e2[0] and e2[0]<e1[1]<e2[1]) or (e2[0]<e1[0]<e2[1] and e2[1]<e1[1])

With this in hand we can easily construct the circle graph corresponding to a given matching:

def circle_grf(pm):
    return Graph([range( len( pm)), lambda i,j: cross(pm[i],pm[j])])
def chord_dgrm(pm):
    dgrm = graphs.CycleGraph( 2*len(pm))
    dgrm.add_edges( pm)
    return dgrm
pm = [(0, 8), (1, 4), (2, 9), (3, 6), (5, 7)]
CD = chord_dgrm( pm)
show(CD)  # not tested

We can get the perfect matchings in the complement of $C_{10}$ as follows. (It's not pretty, but it works.)

C = graphs.CycleGraph(10)
CC = C.complement().line_graph().complement()
cliques = CC.cliques_maximum()

So there are 293 perfect matchings in the complement of $C_{10}$. It is easy to create the corresponding circle graphs and then find the number of different possibilities by examining canonical labelings.

grfs = [circle_grf( pm).canonical_label().graph6_string() for pm in cliques]
uniq = Set(grfs)
{'DBk', 'D]{', 'D`K', 'DK[', 'DBg', 'DB{', 
'D@s', 'D^{', 'D@{', 'D?{', 'Dbk', 'DF{', 
'DIk', 'D@O', 'DJ{', 'DLo', 'DK{', 'D~{', 
'D_K', 'DNw', 'DL{', 'DJk', 'DFw', 'DN{'}

With just 24 different circle graphs resulting from the 293 matchings, we see this is not a particularly efficient way to generate circle graphs.

We can make use of procedures to convert between perfect matchings and double occurrence words.