/// <summary> /// Check if all the edges of the <paramref name="cycle"/> are present in the current /// <see cref="basis"/>. /// </summary> /// <param name="cycle">an initial cycle</param> /// <returns>any edges of the basis are present</returns> public bool IsSubsetOfBasis(Cycle cycle) { BitArray edgeVector = cycle.EdgeVector; int intersect = BitArrays.Cardinality(And(edgesOfBasis, edgeVector)); return(intersect == cycle.Length); }
public void TestBug931608() { var builder = CDK.Builder; var filename = "NCDK.Data.MDL.bug931608-1.mol"; var ins = ResourceLoader.GetAsStream(filename); var reader = new MDLV2000Reader(ins, ChemObjectReaderMode.Strict); IAtomContainer structure1 = (IAtomContainer)reader.Read(builder.NewAtomContainer()); filename = "NCDK.Data.MDL.bug931608-2.mol"; ins = ResourceLoader.GetAsStream(filename); reader = new MDLV2000Reader(ins, ChemObjectReaderMode.Strict); IAtomContainer structure2 = (IAtomContainer)reader.Read(builder.NewAtomContainer()); AtomContainerManipulator.PercieveAtomTypesAndConfigureAtoms(structure1); AtomContainerManipulator.PercieveAtomTypesAndConfigureAtoms(structure2); IFingerprinter fingerprinter = GetBitFingerprinter(); BitArray bs1 = fingerprinter.GetBitFingerprint(structure1).AsBitSet(); BitArray bs2 = fingerprinter.GetBitFingerprint(structure2).AsBitSet(); // now we do the bool XOR on the two bitsets, leading // to a bitset that has all the bits set to "true" which differ // between the two original bitsets bs1.Xor(bs2); // cardinality gives us the number of "true" bits in the // result of the XOR operation. int cardinality = BitArrays.Cardinality(bs1); Assert.AreEqual(0, cardinality); }
/// <summary> /// Attempt to augment the matching such that it is perfect over the subset /// of vertices in the provided graph. /// </summary> /// <param name="graph">adjacency list representation of graph</param> /// <param name="subset">subset of vertices</param> /// <returns>the matching was perfect</returns> /// <exception cref="ArgumentException">the graph was a different size to the matching capacity</exception> public bool Perfect(int[][] graph, BitArray subset) { if (graph.Length != match.Length || BitArrays.Cardinality(subset) > graph.Length) { throw new ArgumentException("graph and matching had different capacity"); } // and odd set can never provide a perfect matching if ((BitArrays.Cardinality(subset) & 0x1) == 0x1) { return(false); } // arbitrary matching was perfect if (ArbitaryMatching(graph, subset)) { return(true); } EdmondsMaximumMatching.Maxamise(this, graph, subset); // the matching is imperfect if any vertex was for (int v = BitArrays.NextSetBit(subset, 0); v >= 0; v = BitArrays.NextSetBit(subset, v + 1)) { if (Unmatched(v)) { return(false); } } return(true); }
public static Graph GenerateKekuleForm(Graph g, BitArray subset, BitArray aromatic, bool inplace) { // make initial (empty) matching - then improve it, first // by matching the first edges we find, most of time this // gives us a perfect matching if not we maximise it // with Edmonds' algorithm Matching m = Matching.CreateEmpty(g); int n = BitArrays.Cardinality(subset); int nMatched = ArbitraryMatching.Initial(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 InvalidSmilesException("Could not Kekulise"); } } return(inplace ? Assign(g, subset, aromatic, m) : CopyAndAssign(g, subset, aromatic, m)); }
private void Reduce(int x, int lim) { IList <PathEdge> es = pathGraph[x]; int deg = es.Count; for (int i = 0; i < deg; i++) { PathEdge e1 = es[i]; for (int j = i + 1; j < deg; j++) { PathEdge e2 = es[j]; if (!e1.Intersects(e2)) { PathEdge reduced = Reduce(e1, e2, x); if (BitArrays.Cardinality(reduced.xs) >= lim) { continue; } if (reduced.Loop()) { if (reduced.CheckPiElectrons(ps)) { reduced.Flag(aromatic); } } else { Add(reduced); } } } } pathGraph[x].Clear(); }
public void Benzylbenzene() { Graph g = Graph.FromSmiles("c1ccccc1Cc1ccccc1"); BiconnectedComponents bc = new BiconnectedComponents(g, false); Assert.AreEqual(12, BitArrays.Cardinality(bc.Cyclic)); }
/// <summary> /// Find the next index that the <i>cycle</i> intersects with by at least two /// vertices. If the intersect of a vertex set with another contains more /// then two vertices it cannot be edge disjoint. /// </summary> /// <param name="start">start searching from here</param> /// <param name="cycle">test whether any current cycles are fused with this one</param> /// <returns>the index of the first fused after 'start', -1 if none</returns> private int IndexOfFused(int start, BitArray cycle) { for (int i = start; i < cycles.Count(); i++) { if (BitArrays.Cardinality(And(cycles[i], cycle)) > 1) { return(i); } } return(-1); }
public void TestGenerateFingerprintNaphthalene() { var smiles = "C1=CC2=CC=CC=C2C=C1"; var smilesParser = CDK.SmilesParser; var molecule = smilesParser.ParseSmiles(smiles); AtomContainerManipulator.PercieveAtomTypesAndConfigureAtoms(molecule); Aromaticity.CDKLegacy.Apply(molecule); ShortestPathFingerprinter fingerprint = new ShortestPathFingerprinter(1024); BitArray fingerprint1; fingerprint1 = fingerprint.GetBitFingerprint(molecule).AsBitSet(); Assert.AreEqual(8, BitArrays.Cardinality(fingerprint1)); }
public void TestGenerateFingerprintMultiphtalene() { var smiles = "C1=CC2=CC=C3C4=CC5=CC6=CC=CC=C6C=C5C=C4C=CC3=C2C=C1"; var smilesParser = CDK.SmilesParser; var molecule = smilesParser.ParseSmiles(smiles); AtomContainerManipulator.PercieveAtomTypesAndConfigureAtoms(molecule); AtomContainerManipulator.PercieveAtomTypesAndConfigureAtoms(molecule); ShortestPathFingerprinter fingerprint = new ShortestPathFingerprinter(1024); BitArray fingerprint1; fingerprint1 = fingerprint.GetBitFingerprint(molecule).AsBitSet(); Assert.AreEqual(15, BitArrays.Cardinality(fingerprint1)); }
/// <summary> /// Add the cycle vertices to our discovered cycles. The cycle is first /// checked to see if it is isolated (shares at most one vertex) or /// <i>potentially</i> fused. /// </summary> /// <param name="cycle">newly discovered cyclic vertex set</param> private void Add(BitArray cycle) { BitArray intersect = And(cycle, cyclic); if (BitArrays.Cardinality(intersect) > 1) { AddFused(cycle); } else { AddIsolated(cycle); } cyclic.Or(cycle); }
/// <summary> /// Convert the set bits of a BitArray to an int[]. /// </summary> /// <param name="set">input with 0 or more set bits</param> /// <returns>the bits which are set in the input</returns> public static int[] ToArray(BitArray set) { int[] vertices = new int[BitArrays.Cardinality(set)]; int i = 0; // fill the cyclic vertices with the bits that have been set for (int v = 0; i < vertices.Length; v++) { if (set[v]) { vertices[i++] = v; } } return(vertices); }
/// <summary> /// Evaluates Tanimoto coefficient for two bit sets. /// </summary> /// <param name="bitset1">A bitset (such as a fingerprint) for the first molecule</param> /// <param name="bitset2">A bitset (such as a fingerprint) for the second molecule</param> /// <returns>The Tanimoto coefficient</returns> /// <exception cref="CDKException"> if bitsets are not of the same length</exception> public static double Calculate(BitArray bitset1, BitArray bitset2) { double _bitset1_cardinality = BitArrays.Cardinality(bitset1); double _bitset2_cardinality = BitArrays.Cardinality(bitset2); if (bitset1.Count != bitset2.Count) { throw new CDKException($"{nameof(bitset1)} and {nameof(bitset2)} must have the same bit length"); } BitArray one_and_two = (BitArray)bitset1.Clone(); one_and_two.And(bitset2); double _common_bit_count = BitArrays.Cardinality(one_and_two); return(_common_bit_count / (_bitset1_cardinality + _bitset2_cardinality - _common_bit_count)); }
/// <summary> /// Create a new cyclic vertex search for the provided graph. /// </summary> /// <param name="graph">adjacency list representation of a graph</param> public JumboCyclicVertexSearch(IReadOnlyList <IReadOnlyList <int> > graph) { this.g = graph; int n = graph.Count; cyclic = new BitArray(n); if (n == 0) { return; } state = new BitArray[n]; visited = new BitArray(n); BitArray empty = new BitArray(n); // start from vertex 0 Search(0, Copy(empty), Copy(empty)); // if g is a fragment we will not have visited everything int v = 0; while (BitArrays.Cardinality(visited) != n) { v++; // each search expands to the whole fragment, as we // may have fragments we need to visit 0 and then // check every other vertex if (!visited[v]) { Search(v, Copy(empty), Copy(empty)); } } // allow the states to be collected state = null; visited = null; }
private void StoreWithComp(Edge e) { List <Edge> component = new List <Edge>(6); Edge f; BitArray tmp = new BitArray(g.Order); // count the number of unique vertices and edges int numEdges = 0; bool spiro = false; do { f = stack[--nstack]; int v = f.Either(); int w = f.Other(v); if (cyclic[v] || cyclic[w]) { spiro = true; } tmp.Set(v, true); tmp.Set(w, true); component.Add(f); numEdges++; } while (f != e); cyclic.Or(tmp); if (!spiro && BitArrays.Cardinality(tmp) == numEdges) { simple.Or(tmp); } components.Add(component); }
private static bool HasOddCardinality(BitArray s) { return((BitArrays.Cardinality(s) & 0x1) == 1); }
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> /// Assign an arbitrary matching that covers the subset of vertices. /// </summary> /// <param name="graph">adjacency list representation of graph</param> /// <param name="subset">subset of vertices in the graph</param> /// <returns>the matching was perfect</returns> internal bool ArbitaryMatching(int[][] graph, BitArray subset) { BitArray unmatched = new BitArray(subset.Length); // indicates the deg of each vertex in unmatched subset int[] deg = new int[graph.Length]; // queue/stack of vertices with deg1 vertices int[] deg1 = new int[graph.Length]; int nd1 = 0, nMatched = 0; for (int v = BitArrays.NextSetBit(subset, 0); v >= 0; v = BitArrays.NextSetBit(subset, v + 1)) { if (Matched(v)) { Trace.Assert(subset[Other(v)]); nMatched++; continue; } unmatched.Set(v, true); foreach (var w in graph[v]) { if (subset[w] && Unmatched(w)) { deg[v]++; } } if (deg[v] == 1) { deg1[nd1++] = v; } } while (!BitArrays.IsEmpty(unmatched)) { int v = -1; // attempt to select a vertex with degree = 1 (in matched set) while (nd1 > 0) { v = deg1[--nd1]; if (unmatched[v]) { break; } } // no unmatched degree 1 vertex, select the first unmatched if (v < 0 || unmatched[v]) { v = BitArrays.NextSetBit(unmatched, 0); } unmatched.Set(v, false); // find a unmatched edge and match it, adjacent degrees are updated foreach (var w in graph[v]) { if (unmatched[w]) { Match(v, w); nMatched += 2; unmatched.Set(w, false); // update neighbors of w and v (if needed) foreach (var u in graph[w]) { if (--deg[u] == 1 && unmatched[u]) { deg1[nd1++] = u; } } // if deg == 1, w is the only neighbor if (deg[v] > 1) { foreach (var u in graph[v]) { if (--deg[u] == 1 && unmatched[u]) { deg1[nd1++] = u; } } } break; } } } return(nMatched == BitArrays.Cardinality(subset)); }