void Main() { { #region IAtomContainer benzene = TestMoleculeFactory.MakeBenzene(); IAtom c1 = benzene.Atoms[0]; IAtom c4 = benzene.Atoms[3]; // shortest paths from C1 ShortestPaths sp = new ShortestPaths(benzene, c1); // number of paths from C1 to C4 int nPaths = sp.GetNPathsTo(c4); // distance between C1 to C4 int distance = sp.GetDistanceTo(c4); // reconstruct a path to the C4 - determined by storage order int[] path = sp.GetPathTo(c4); // reconstruct all paths int[][] paths = sp.GetPathsTo(c4); int[] org = paths[0]; // paths[0] == path int[] alt = paths[1]; #endregion } { IAtomContainer benzene = TestMoleculeFactory.MakeBenzene(); IAtom c1 = benzene.Atoms[0]; #region GetPathTo_int ShortestPaths sp = new ShortestPaths(benzene, c1); // reconstruct first path int[] path = sp.GetPathTo(5); // check there is only one path if (sp.GetNPathsTo(5) == 1) { path = sp.GetPathTo(5); // reconstruct the path } #endregion } { IAtomContainer benzene = TestMoleculeFactory.MakeBenzene(); IAtom c1 = benzene.Atoms[0]; #region GetPathTo_IAtom ShortestPaths sp = new ShortestPaths(benzene, c1); IAtom end = benzene.Atoms[3]; // reconstruct first path int[] path = sp.GetPathTo(end); // check there is only one path if (sp.GetNPathsTo(end) == 1) { path = sp.GetPathTo(end); // reconstruct the path } #endregion } { IAtomContainer benzene = TestMoleculeFactory.MakeBenzene(); IAtom c1 = benzene.Atoms[0]; #region GetPathsTo_int int threshold = 20; ShortestPaths sp = new ShortestPaths(benzene, c1); // reconstruct shortest paths int[][] paths = sp.GetPathsTo(5); // only reconstruct shortest paths below a threshold if (sp.GetNPathsTo(5) < threshold) { int[][] path = sp.GetPathsTo(5); // reconstruct shortest paths } #endregion } { IAtomContainer benzene = TestMoleculeFactory.MakeBenzene(); IAtom c1 = benzene.Atoms[0]; #region GetPathsTo_IAtom int threshold = 20; ShortestPaths sp = new ShortestPaths(benzene, c1); IAtom end = benzene.Atoms[3]; // reconstruct all shortest paths int[][] paths = sp.GetPathsTo(end); // only reconstruct shortest paths below a threshold if (sp.GetNPathsTo(end) < threshold) { paths = sp.GetPathsTo(end); // reconstruct shortest paths } #endregion } { IAtomContainer benzene = TestMoleculeFactory.MakeBenzene(); IAtom c1 = benzene.Atoms[0]; #region GetAtomsTo_int ShortestPaths sp = new ShortestPaths(benzene, c1); // reconstruct a shortest path IAtom[] path = sp.GetAtomsTo(5); // ensure single shortest path if (sp.GetNPathsTo(5) == 1) { path = sp.GetAtomsTo(5); // reconstruct shortest path } #endregion } { IAtomContainer benzene = TestMoleculeFactory.MakeBenzene(); IAtom c1 = benzene.Atoms[0]; #region GetAtomsTo_IAtom ShortestPaths sp = new ShortestPaths(benzene, c1); IAtom end = benzene.Atoms[3]; // reconstruct a shortest path IAtom[] path = sp.GetAtomsTo(end); // ensure single shortest path if (sp.GetNPathsTo(end) == 1) { path = sp.GetAtomsTo(end); // reconstruct shortest path } #endregion } { IAtomContainer benzene = TestMoleculeFactory.MakeBenzene(); IAtom c1 = benzene.Atoms[0]; #region GetNPathsTo_int ShortestPaths sp = new ShortestPaths(benzene, c1); sp.GetNPathsTo(5); // number of paths sp.GetNPathsTo(-1); // returns 0 - there are no paths #endregion } { IAtomContainer benzene = TestMoleculeFactory.MakeBenzene(); IAtom c1 = benzene.Atoms[0]; #region GetNPathsTo_IAtom ShortestPaths sp = new ShortestPaths(benzene, c1); IAtom end = benzene.Atoms[3]; sp.GetNPathsTo(end); // number of paths sp.GetNPathsTo(null); // returns 0 - there are no paths sp.GetNPathsTo(new Atom("C")); // returns 0 - there are no paths #endregion } { #region GetDistanceTo_int_1 IAtomContainer container = TestMoleculeFactory.MakeBenzene(); IAtom c1 = container.Atoms[0]; ShortestPaths sp = new ShortestPaths(container, c1); // start = 0 int n = container.Atoms.Count; if (sp.GetDistanceTo(5) < n) { // these is a path from 0 to 5 } #endregion } { #region GetDistanceTo_int_2 IAtomContainer container = TestMoleculeFactory.MakeBenzene(); IAtom c1 = container.Atoms[0]; ShortestPaths sp = new ShortestPaths(container, c1); // start = 0 int[] path = sp.GetPathTo(5); int start = path[0]; int end = path[sp.GetDistanceTo(5)]; #endregion } { #region GetDistanceTo_IAtom_1 IAtomContainer container = TestMoleculeFactory.MakeBenzene(); IAtom c1 = container.Atoms[0]; ShortestPaths sp = new ShortestPaths(container, c1); // start atom IAtom end = container.Atoms[3]; int n = container.Atoms.Count; if (sp.GetDistanceTo(end) < n) { // these is a path from start to end } #endregion } { #region GetDistanceTo_IAtom_2 IAtomContainer container = TestMoleculeFactory.MakeBenzene(); IAtom c1 = container.Atoms[0]; ShortestPaths sp = new ShortestPaths(container, c1); // start atom IAtom end = container.Atoms[3]; IAtom[] atoms = sp.GetAtomsTo(end); Console.WriteLine(end == atoms[sp.GetDistanceTo(end)]); // true #endregion } }
/// <summary> /// Compute the initial cycles. The code corresponds to algorithm 1 from /// <token>cdk-cite-Vismara97</token>, where possible the variable names have been kept /// the same. /// </summary> private void Compute() { int n = graph.Length; // the set 'S' contains the pairs of vertices adjacent to 'y' int[] s = new int[n]; int sizeOfS; // order the vertices by degree int[] vertices = new int[n]; for (int v = 0; v < n; v++) { vertices[ordering[v]] = v; } // if the graph is known to be a biconnected component (prepossessing) // and there is at least one vertex with a degree > 2 we can skip all // vertices of degree 2. // // otherwise the smallest possible cycle is {0,1,2} (no parallel edges // or loops) we can therefore don't need to do the first two shortest // paths calculations int first = biconnected && nDeg2Vertices < n ? nDeg2Vertices : 2; for (int i = first; i < n; i++) { int r = vertices[i]; ShortestPaths pathsFromR = new ShortestPaths(graph, null, r, limit / 2, ordering); // we only check the vertices which belong to the set Vr. this // set is vertices reachable from 'r' by only travelling though // vertices smaller then r. In the ShortestPaths API this is // name 'IsPrecedingPathTo'. // // using Vr allows us to prune the number of vertices to check and // discover each cycle exactly once. This is possible as for each // simple cycle there is only one vertex with a maximum ordering. for (int j = 0; j < i; j++) { int y = vertices[j]; if (!pathsFromR.IsPrecedingPathTo(y)) { continue; } // start refilling set 's' by resetting it's size sizeOfS = 0; // z is adjacent to y and belong to Vr foreach (var z in graph[y]) { if (!pathsFromR.IsPrecedingPathTo(z)) { continue; } int distToZ = pathsFromR.GetDistanceTo(z); int distToY = pathsFromR.GetDistanceTo(y); // the distance of the path to z is one less then the // path to y. the vertices are adjacent, therefore z must // also belong to the shortest path from r to y. // // we queue up (in 's') all the vertices adjacent to y for // which this holds and then check these once we've processed // all adjacent vertices // // / ¯ ¯ z1 \ z1 and z2 are added to 's' and // r y - z3 checked later as p and q (see below) // \ _ _ z2 / // if (distToZ + 1 == distToY) { s[sizeOfS++] = z; } // if the distances are equal we could have an odd cycle // but we need to check the paths only intersect at 'r'. // // we check the intersect for cases like this, shortest // cycle here is {p .. y, z .. p} not {r .. y, z .. r} // // / ¯ ¯ y / ¯ ¯ \ / ¯ ¯ y // r - - - p | or r p | // \ _ _ z \ _ _ / \ _ _ z // // if it's the shortest cycle then the intersect is just {r} // // / ¯ ¯ y // r | // \ _ _ z // else if (distToZ == distToY && ordering[z] < ordering[y]) { int[] pathToY = pathsFromR.GetPathTo(y); int[] pathToZ = pathsFromR.GetPathTo(z); if (GetSingletonIntersect(pathToZ, pathToY)) { Cycle cycle = new Cycle.OddCycle(this, pathsFromR, pathToY, pathToZ); Add(cycle); } } } // check each pair vertices adjacent to 'y' for an // even cycle, as with the odd cycle we ensure the intersect // of the paths {r .. p} and {r .. q} is {r}. // // / ¯ ¯ p \ // r y // \ _ _ q / // for (int k = 0; k < sizeOfS; k++) { for (int l = k + 1; l < sizeOfS; l++) { int[] pathToP = pathsFromR.GetPathTo(s[k]); int[] pathToQ = pathsFromR.GetPathTo(s[l]); if (GetSingletonIntersect(pathToP, pathToQ)) { Cycle cycle = new Cycle.EvenCycle(this, pathsFromR, pathToP, y, pathToQ); Add(cycle); } } } } } }