11
$\begingroup$

I am doing a research on networks which consists of polygons with different number of sides. I am trying to find all simple cycles in a network which are chordless. As an example, consider the following graph:

graph = Graph[
  {
    1 <-> 2,   2 <-> 3,   3 <-> 4,  4 <-> 5,   5 <-> 6,   1 <-> 6,  
    3 <-> 7,   7 <-> 8,   8 <-> 9,  9 <-> 10, 10 <-> 11, 11 <-> 3,
    4 <-> 12, 12 <-> 13, 13 <-> 11
  }, 
    VertexLabels -> "Name"
]

enter image description here

{1,2,3,4,5,6}, {3,4,11,12,13},{3,7,8,9,10,11} are rings and we can extract them:

cycles = FindFundamentalCycles[graph];
rings = Sort @* VertexList @* Graph /@ cycles  

enter image description here

But the above solution doesn't always work as it might give non-chordless cycles. Consider the following example:

grapht = Graph[
{
  1 <-> 2, 1 <-> 3, 2 <-> 4, 4 <-> 5, 5 <-> 6, 4 <-> 6, 
  6 <-> 7, 3 <-> 5, 3 <-> 9, 5 <-> 8, 8 <-> 9
},
VertexLabels -> "Name"];

enter image description here

Rings (cycles) are:

cyclest = FindFundamentalCycles[grapht]; 
HighlightGraph[grapht, #] & /@ cyclest

enter image description here

But I need to get {4,5,6} as a ring not {1,2,3,4,5,6} since there is an edge in the latter. Is there any way to filter out only chordless cycles?


W Community crosspost

$\endgroup$
4
$\begingroup$

First, let us find all cycles in the graph. Then, we will filter out the ones that contain chords; this we can detect by checking if the $n$-vertex induced subgraph is isomorphic to a cycle of length $n$ or not.

Let us use your graph as an example:

g = Graph[{1 <-> 2, 1 <-> 3, 2 <-> 4, 4 <-> 5, 5 <-> 6, 4 <-> 6, 
   6 <-> 7, 3 <-> 5, 3 <-> 9, 5 <-> 8, 8 <-> 9}, 
  VertexLabels -> "Name"];

cy = VertexList[Graph[#]] & /@ FindCycle[g, Infinity, All];
Select[cy, IsomorphicGraphQ[CycleGraph[Length[#]], Subgraph[g, #]] &]
(* {{4, 5, 6}, {5, 8, 9, 3}, {1, 2, 4, 5, 3}} *)

HighlightGraph[g, %]

Of course, if you have additional constraints, you can simply modify the call to FindCycle with different parameters to only find cycles of length e.g. of size 5, 6, 7, or 8. To achieve this, just do FindCycle[g, {5, 8}, All] instead.

| improve this answer | |
$\endgroup$
  • $\begingroup$ This seems to work like a charm! A huge thank! $\endgroup$ – Mahdi Mar 22 '15 at 19:42
  • $\begingroup$ Although, I found that this doesn't work in Mathematica 9 mostly because of FindCycle. $\endgroup$ – Mahdi Apr 3 '15 at 5:59
7
$\begingroup$

Here's a weird way to find chordless cycles in V12+: convert the Graph into a Molecule and query for the set of smallest rings.

Your example:

grapht = Graph[
{
  1 <-> 2, 1 <-> 3, 2 <-> 4, 4 <-> 5, 5 <-> 6, 4 <-> 6, 
  6 <-> 7, 3 <-> 5, 3 <-> 9, 5 <-> 8, 8 <-> 9
},
VertexLabels -> "Name"];

rings = Molecule[grapht]["SmallestSetOfSmallestRings"]
{{1, 2, 4, 5, 3}, {6, 5, 4}, {8, 9, 3, 5}}
HighlightGraph[grapht, PathGraph[Append[#, First[#]]]] & /@ rings

enter image description here

Now it seems a graph with vertex degree greater than 4 can't become a molecule, but we can work around this with a hidden option. I've packed this into a function:

ChordlessRings[g_?GraphQ] :=
  Block[{mol, rings},
    mol = Quiet[Molecule[IndexGraph[g], "GraphValenceRules" -> {_ -> "C"}]];
    (
      rings = mol["SmallestSetOfSmallestRings"];

      rings /; ListQ[rings]

    ) /; MoleculeQ[mol]
  ]

ChordlessRings[___] = $Failed;

A larger example:

SeedRandom[4];
vm = VoronoiMesh[RandomReal[{-1, 1}, {100, 2}], {{-1, 1}, {-1, 1}}];
g = PlanarGraph[MeshCells[vm, 1][[All, 1]], VertexSize -> Large]

(rings = ChordlessRings[g]) // Length
100
HighlightGraph[g, PathGraph[Append[#, First[#]]]] & /@ rings[[1 ;; 5]]

enter image description here

Graphics @ GraphicsComplex[
  GraphEmbedding[g], 
  {EdgeForm[Black], {RandomColor[Hue[_]], Polygon[#]} & /@ rings}
]

Or we can ensure no 2 adjacent faces share the same color:

Block[{Print}, << IGraphM`]

imat = SparseArray[Join @@ MapIndexed[Thread[Thread[{First[#2], #1}] -> 1] &, rings]];
faceadj = Unitize[imat.Transpose[imat]];
faceconn = SimpleGraph@AdjacencyGraph[faceadj];

colors = IGMinimumVertexColoring[faceconn];

Graphics @ GraphicsComplex[
  GraphEmbedding[g], 
  {EdgeForm[Black], MapThread[{ColorData[112, #2], Polygon[#]} &, {rings, colors}]}
]

| improve this answer | |
$\endgroup$
  • $\begingroup$ What's amusing about this solution is that it very likely uses an external method in RDKit which will probably then call back into a graph-theory library. Interesting the way the library calls chain. $\endgroup$ – b3m2a1 Dec 17 '19 at 22:34
  • $\begingroup$ In the Voronoi example you show, the outer face is also a chordless cycle, isn't it? But it's not returned by ChordlessRings. $\endgroup$ – Szabolcs Dec 18 '19 at 13:42
  • 1
    $\begingroup$ I think I'll leave my answer though since I find the method amusingly absurd. $\endgroup$ – Chip Hurst Dec 18 '19 at 13:50
  • 1
    $\begingroup$ I am not sure what the exact definition of "SmallestSetOfSmallestRings" is, but I notice that the number of results it returns is the dimension of the cycle basis. So perhaps it finds a minimal cycle basis? $\endgroup$ – Szabolcs Dec 18 '19 at 14:05
  • 1
    $\begingroup$ @CATrevillian The coloring was just randomly chosen with RandomColor[Hue[_]]. I added an example showing a proper 4 coloring. See my latest edit. $\endgroup$ – Chip Hurst Dec 18 '19 at 17:17
3
$\begingroup$

IGraph/M may help with this.

IGLADFindSubisomorphisms can look for induced subgraphs, and you are looking for induced cycles.

We can construct a function like this:

Needs["IGraphM`"]
chordlessCycles[graph_?UndirectedGraphQ] := 
  Join @@ Table[
    DeleteDuplicatesBy[Sort]@Values@IGLADFindSubisomorphisms[CycleGraph[k], graph, "Induced" -> True], 
    {k, IGGirth[graph], VertexCount[graph]}
  ]

This function will look for cycles of all sizes starting with the girth up to the vertex count. For your graph, it returns

chordlessCycles[graph]
(* {{3, 4, 12, 13, 11}, {1, 6, 5, 4, 3, 2}, {3, 7, 8, 9, 10, 11}} *) 

Beware that in general there may be a very large number of induced cycles. Stealing Chip's graph generation code, here's an example:

SeedRandom[4];
vm = VoronoiMesh[RandomReal[{-1, 1}, {10, 2}], {{-1, 1}, {-1, 1}}];
g = PlanarGraph[MeshCells[vm, 1][[All, 1]], VertexSize -> Large]

enter image description here

cycle[vlist_] := PathGraph[Append[vlist, First[vlist]]]

HighlightGraph[g, cycle[#], GraphHighlightStyle -> "Thick", 
   ImageSize -> 60] & /@ chordlessCycles[g]

enter image description here

| improve this answer | |
$\endgroup$
  • 1
    $\begingroup$ I was going to use IGFaces but noticed it didn't find the 5 cycle in OP's problematic example, e.g. HighlightGraph[grapht, UndirectedEdge @@@ Partition[#, 2, 1, 1]] & /@ IGFaces[grapht]. Why is this? $\endgroup$ – Chip Hurst Dec 18 '19 at 12:53
  • $\begingroup$ @ChipHurst You're right, finding faces may not be a good method at all, perhaps unless the graph is planar and 3-vertex-connected, in which case its embedding is unique. This graph is not 3-connected, even after removing that dangling part. To get an idea of the embedding that IGraph/M is considering here, take a look at IGLayoutPlanar[grapht]. In that embedding, the 5 cycle is not a face. $\endgroup$ – Szabolcs Dec 18 '19 at 13:35
  • $\begingroup$ I removed the suggestion to use IGFaces. It was not a good one, for other reasons too: some chordless cycles cannot be faces in any embedding. $\endgroup$ – Szabolcs Dec 18 '19 at 13:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.