public static int Dfs(Graph g, Matching m, BitArray s) { int nMatched = 0; BitArray unvisited = (BitArray)s.Clone(); // visit those with degree 1 first and expand out matching for (int v = BitArrays.NextSetBit(unvisited, 0); v >= 0; v = BitArrays.NextSetBit(unvisited, v + 1)) { if (!m.Matched(v)) { int cnt = 0; int d = g.Degree(v); while (--d >= 0) { int w = g.EdgeAt(v, d).Other(v); if (unvisited[w]) { ++cnt; } } if (cnt == 1) { nMatched += DfsVisit(g, v, m, unvisited, true); } } } // now those which aren't degree 1 for (int v = BitArrays.NextSetBit(unvisited, 0); v >= 0; v = BitArrays.NextSetBit(unvisited, v + 1)) { if (!m.Matched(v)) { nMatched += DfsVisit(g, v, m, unvisited, true); } } return(nMatched); }
public static int DfsVisit(Graph g, int v, Matching m, BitArray unvisited, bool match) { unvisited.Set(v, false); int nMatched = 0; int d = g.Degree(v); while (--d >= 0) { int w = g.EdgeAt(v, d).Other(v); if (unvisited[w]) { if (match) { m.Match(v, w); return(2 + DfsVisit(g, w, m, unvisited, false)); } else { nMatched += DfsVisit(g, w, m, unvisited, true); } } } return(nMatched); }
// invariant, m is a perfect matching private static Graph CopyAndAssign(Graph delocalised, BitArray subset, BitArray aromatic, Matching m) { Graph localised = new Graph(delocalised.Order); localised.SetFlags(delocalised.GetFlags() & ~Graph.HAS_AROM); for (int u = 0; u < delocalised.Order; u++) { localised.AddAtom(delocalised.GetAtom(u).AsAliphaticForm()); localised.AddTopology(delocalised.TopologyOf(u)); int d = delocalised.Degree(u); for (int j = 0; j < d; ++j) { Edge e = delocalised.EdgeAt(u, j); int v = e.Other(u); if (v < u) { var aa = e.Bond; if (aa == Bond.Single) { if (aromatic[u] && aromatic[v]) { localised.AddEdge(Bond.Single.CreateEdge(u, v)); } else { localised.AddEdge(Bond.Implicit.CreateEdge(u, v)); } } else if (aa == Bond.Aromatic) { if (subset[u] && m.Other(u) == v) { localised.AddEdge(Bond.DoubleAromatic.CreateEdge(u, v)); } else if (aromatic[u] && aromatic[v]) { localised.AddEdge(Bond.ImplicitAromatic.CreateEdge(u, v)); } else { localised.AddEdge(Bond.Implicit.CreateEdge(u, v)); } } else if (aa == Bond.Implicit) { if (subset[u] && m.Other(u) == v) { localised.AddEdge(Bond.DoubleAromatic.CreateEdge(u, v)); } else if (aromatic[u] && aromatic[v]) { localised.AddEdge(Bond.ImplicitAromatic.CreateEdge(u, v)); } else { localised.AddEdge(e); } } else { localised.AddEdge(e); } } } } return(localised); }
public static Graph Resonate(Graph g, BitArray cyclic, bool ordered) { BitArray subset = new BitArray(g.Order); for (int u = BitArrays.NextSetBit(cyclic, 0); u >= 0; u = BitArrays.NextSetBit(cyclic, u + 1)) { // candidates must have a bonded // valence of one more than their degree // and in a ring int uExtra = g.BondedValence(u) - g.Degree(u); if (uExtra > 0) { int other = -1; Edge target = null; int d = g.Degree(u); for (int j = 0; j < d; ++j) { Edge e = g.EdgeAt(u, j); int v = e.Other(u); // check for bond validity if (e.Bond.Order == 2) { int vExtra = g.BondedValence(v) - g.Degree(v); if (cyclic[v] && vExtra > 0) { if (HasAdjDirectionalLabels(g, e, cyclic) && !InSmallRing(g, e)) { other = -1; break; } if (vExtra > 1 && HasAdditionalCyclicDoubleBond(g, cyclic, u, v)) { other = -1; break; } if (other == -1) { other = v; // first one target = e; } else { other = -2; // found more than one } } // only one double bond don't check any more if (uExtra == 1) { break; } } } if (other >= 0) { subset.Set(u, true); subset.Set(other, true); target.SetBond(Bond.Implicit); } } } if (!ordered) { g = g.Sort(new Graph.CanOrderFirst()); } Matching m = Matching.CreateEmpty(g); int n = BitArrays.Cardinality(subset); int nMatched = ArbitraryMatching.Dfs(g, m, subset); if (nMatched < n) { if (n - nMatched == 2) { nMatched = ArbitraryMatching.AugmentOnce(g, m, nMatched, subset); } if (nMatched < n) { nMatched = MaximumMatching.Maximise(g, m, nMatched, IntSet.FromBitArray(subset)); } if (nMatched < n) { throw new ApplicationException("Could not Kekulise"); } } // assign new double bonds for (int v = BitArrays.NextSetBit(subset, 0); v >= 0; v = BitArrays.NextSetBit(subset, v + 1)) { int w = m.Other(v); subset.Set(w, false); g.CreateEdge(v, w).SetBond(Bond.Double); } return(g); }
[TestMethod()] public void IsEmptyTest() { Matching matching = Matching.CreateEmpty(Graph.FromSmiles("CCCCC")); Assert.AreEqual(0, matching.GetMatches().Count()); }
public static int FindPath(Graph g, int v, int end, BitArray unvisited, int[] path, int len, Matching m, bool matchNeeded) { unvisited.Set(v, false); path[len++] = v; int l; int d = g.Degree(v); for (int j = 0; j < d; ++j) { Edge e = g.EdgeAt(v, j); // explicit single bond can not be augmented along!! if (e.Bond == Bond.Single) { continue; } int w = e.Other(v); if (unvisited[w]) { if (w == end) { path[len] = w; len++; unvisited.Set(v, true); // odd length path no good return(((len & 0x1) == 1) ? 0 : len); } else if ((m.Other(w) == v) == matchNeeded) { if ((l = FindPath(g, w, end, unvisited, path, len, m, !matchNeeded)) > 0) { unvisited.Set(v, true); return(l); } } } } unvisited.Set(v, true); return(0); }
/// <summary> /// Utility to maximise an existing matching of the provided graph. /// </summary> /// <param name="g">a graph</param> /// <param name="m">matching on the graph</param> /// <param name="n"></param> /// <returns>the maximal matching on the graph</returns> public static int Maximise(Graph g, Matching m, int n) { return(Maximise(g, m, n, IntSet.Universe)); }
/// <summary> /// Utility to maximise an existing matching of the provided graph. /// </summary> /// <param name="g">a graph</param> /// <param name="m">matching on the graph, will me modified</param> /// <param name="n">current matching cardinality</param> /// <param name="s">subset of vertices to match</param> /// <returns>the maximal matching on the graph</returns> public static int Maximise(Graph g, Matching m, int n, IntSet s) { MaximumMatching mm = new MaximumMatching(g, m, n, s); return(mm.nMatched); }