// invariant, m is a perfect matching private static Graph Assign(Graph g, BitArray subset, BitArray aromatic, Matching m) { g.SetFlags(g.GetFlags() & ~Graph.HAS_AROM); for (int u = BitArrays.NextSetBit(aromatic, 0); u >= 0; u = BitArrays.NextSetBit(aromatic, u + 1)) { g.SetAtom(u, g.GetAtom(u).AsAliphaticForm()); int deg = g.Degree(u); for (int j = 0; j < deg; ++j) { Edge e = g.EdgeAt(u, j); int v = e.Other(u); if (v < u) { var aa = e.Bond; if (aa == Bond.Single) { if (aromatic[u] && aromatic[v]) { e.SetBond(Bond.Single); } else { e.SetBond(Bond.Implicit); } } else if (aa == Bond.Aromatic) { if (subset[u] && m.Other(u) == v) { e.SetBond(Bond.DoubleAromatic); g.UpdateBondedValence(u, +1); g.UpdateBondedValence(v, +1); } else if (aromatic[v]) { e.SetBond(Bond.ImplicitAromatic); } else { e.SetBond(Bond.Implicit); } } else if (aa == Bond.Implicit) { if (subset[u] && m.Other(u) == v) { e.SetBond(Bond.DoubleAromatic); g.UpdateBondedValence(u, +1); g.UpdateBondedValence(v, +1); } else if (aromatic[u] && aromatic[v]) { e.SetBond(Bond.ImplicitAromatic); } } } } } return(g); }
[TestMethod()] public void Adjusted_other() { Matching matching = Matching.CreateEmpty(Graph.FromSmiles("CCCCC")); matching.Match(0, 1); matching.Match(2, 3); matching.Match(1, 2); // 0-1 and 2-3 should not be Assert.AreEqual(matching.Other(1), 2); Assert.AreEqual(matching.Other(2), 1); }
public void Adjusted_other_invalid() { Matching matching = Matching.CreateEmpty(Graph.FromSmiles("CCCCC")); matching.Match(0, 1); matching.Match(2, 3); matching.Match(1, 2); // 0-1 and 2-3 should not be matching.Other(0); }
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); }
// 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); }
/// <summary> /// Find an augmenting path an alternate it's matching. If an augmenting path /// was found then the search must be restarted. If a blossom was detected /// the blossom is contracted and the search continues. /// </summary> /// <returns>an augmenting path was found</returns> private bool Augment() { // reset data structures Arrays.Fill(even, nil); Arrays.Fill(odd, nil); uf.Clear(); bridges.Clear(); queue.Clear(); // queue every unmatched vertex and place in the // even level (level = 0) for (int v = 0; v < graph.Order; v++) { if (subset.Contains(v) && matching.Unmatched(v)) { even[v] = v; queue.Enqueue(v); } } // for each 'free' vertex, start a bfs search while (!queue.IsEmpty()) { int v = queue.Poll(); int d = graph.Degree(v); for (int j = 0; j < d; ++j) { Edge e = graph.EdgeAt(v, j); if (e.Bond == Bond.Single) { continue; } int w = e.Other(v); if (!subset.Contains(w)) { continue; } // the endpoints of the edge are both at even levels in the // forest - this means it is either an augmenting path or // a blossom if (even[uf.Find(w)] != nil) { if (Check(v, w)) { return(true); } } // add the edge to the forest if is not already and extend // the tree with this matched edge else if (odd[w] == nil) { odd[w] = v; int u = matching.Other(w); // add the matched edge (potential though a blossom) if it // isn't in the forest already if (even[uf.Find(u)] == nil) { even[u] = w; queue.Enqueue(u); } } } } // no augmenting paths, matching is maximum return(false); }