~ubuntu-branches/ubuntu/maverick/cdk/maverick

« back to all changes in this revision

Viewing changes to src/org/openscience/cdk/graph/PathTools.java

  • Committer: Bazaar Package Importer
  • Author(s): Paul Cager
  • Date: 2008-04-09 21:17:53 UTC
  • Revision ID: james.westby@ubuntu.com-20080409211753-46lmjw5z8mx5pd8d
Tags: upstream-1.0.2
ImportĀ upstreamĀ versionĀ 1.0.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $RCSfile$
 
2
 * $Author: egonw $    
 
3
 * $Date: 2007-10-23 16:20:20 +0200 (Tue, 23 Oct 2007) $    
 
4
 * $Revision: 9182 $
 
5
 *
 
6
 * Copyright (C) 2001-2007  The Chemistry Development Kit (CDK) project
 
7
 *
 
8
 * Contact: cdk-devel@lists.sourceforge.net
 
9
 *
 
10
 * This program is free software; you can redistribute it and/or
 
11
 * modify it under the terms of the GNU Lesser General Public License
 
12
 * as published by the Free Software Foundation; either version 2.1
 
13
 * of the License, or (at your option) any later version.
 
14
 * All we ask is that proper credit is given for our work, which includes
 
15
 * - but is not limited to - adding the above copyright notice to the beginning
 
16
 * of your source code files, and to any copyright notice that you may distribute
 
17
 * with programs based on this work.
 
18
 *
 
19
 * This program is distributed in the hope that it will be useful,
 
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
22
 * GNU Lesser General Public License for more details.
 
23
 *
 
24
 * You should have received a copy of the GNU Lesser General Public License
 
25
 * along with this program; if not, write to the Free Software
 
26
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 
27
 *
 
28
 */
 
29
package org.openscience.cdk.graph;
 
30
 
 
31
import org.openscience.cdk.CDKConstants;
 
32
import org.openscience.cdk.exception.NoSuchAtomException;
 
33
import org.openscience.cdk.graph.matrix.AdjacencyMatrix;
 
34
import org.openscience.cdk.interfaces.IAtom;
 
35
import org.openscience.cdk.interfaces.IAtomContainer;
 
36
import org.openscience.cdk.interfaces.IBond;
 
37
import org.openscience.cdk.interfaces.ILonePair;
 
38
import org.openscience.cdk.interfaces.IMolecule;
 
39
import org.openscience.cdk.interfaces.ISingleElectron;
 
40
 
 
41
import java.util.ArrayList;
 
42
import java.util.Iterator;
 
43
import java.util.List;
 
44
import java.util.Vector;
 
45
 
 
46
/**
 
47
 * Tools class with methods for handling molecular graphs.
 
48
 *
 
49
 * @author steinbeck
 
50
 * @cdk.module standard
 
51
 * @cdk.created 2001-06-17
 
52
 */
 
53
public class PathTools {
 
54
 
 
55
    public final static boolean debug = false;
 
56
 
 
57
    /**
 
58
     * Sums up the columns in a 2D int matrix
 
59
     *
 
60
     * @param apsp The 2D int matrix
 
61
     * @return A 1D matrix containing the column sum of the 2D matrix
 
62
     */
 
63
    public static int[] getInt2DColumnSum(int[][] apsp) {
 
64
        int[] colSum = new int[apsp.length];
 
65
        int sum;
 
66
        for (int i = 0; i < apsp.length; i++) {
 
67
            sum = 0;
 
68
            for (int j = 0; j < apsp.length; j++) {
 
69
                sum += apsp[i][j];
 
70
            }
 
71
            colSum[i] = sum;
 
72
        }
 
73
        return colSum;
 
74
    }
 
75
 
 
76
 
 
77
    /**
 
78
     * All-Pairs-Shortest-Path computation based on Floyds algorithm Takes an nxn
 
79
     * matrix C of edge costs and produces an nxn matrix A of lengths of shortest
 
80
     * paths.
 
81
     */
 
82
    public static int[][] computeFloydAPSP(int C[][]) {
 
83
        int i;
 
84
        int j;
 
85
        int k;
 
86
        int n = C.length;
 
87
        int[][] A = new int[n][n];
 
88
        //logger.debug("Matrix size: " + n);
 
89
        for (i = 0; i < n; i++) {
 
90
            for (j = 0; j < n; j++) {
 
91
                if (C[i][j] == 0) {
 
92
                    A[i][j] = 999999999;
 
93
                } else {
 
94
                    A[i][j] = 1;
 
95
                }
 
96
            }
 
97
        }
 
98
        for (i = 0; i < n; i++) {
 
99
            A[i][i] = 0;
 
100
            // no self cycle
 
101
        }
 
102
        for (k = 0; k < n; k++) {
 
103
            for (i = 0; i < n; i++) {
 
104
                for (j = 0; j < n; j++) {
 
105
                    if (A[i][k] + A[k][j] < A[i][j]) {
 
106
                        A[i][j] = A[i][k] + A[k][j];
 
107
                        //P[i][j] = k;        // k is included in the shortest path
 
108
                    }
 
109
                }
 
110
            }
 
111
        }
 
112
        return A;
 
113
    }
 
114
 
 
115
    /**
 
116
     * All-Pairs-Shortest-Path computation based on Floyds algorithm Takes an nxn
 
117
     * matrix C of edge costs and produces an nxn matrix A of lengths of shortest
 
118
     * paths.
 
119
     */
 
120
    public static int[][] computeFloydAPSP(double C[][]) {
 
121
        int i;
 
122
        int j;
 
123
        int n = C.length;
 
124
        int[][] A = new int[n][n];
 
125
        //logger.debug("Matrix size: " + n);
 
126
        for (i = 0; i < n; i++) {
 
127
            for (j = 0; j < n; j++) {
 
128
                if (C[i][j] == 0) {
 
129
                    A[i][j] = 0;
 
130
                } else {
 
131
                    A[i][j] = 1;
 
132
                }
 
133
            }
 
134
        }
 
135
        return computeFloydAPSP(A);
 
136
    }
 
137
 
 
138
 
 
139
    /**
 
140
     * Recursivly perfoms a depth first search in a molecular graphs contained in
 
141
     * the AtomContainer molecule, starting at the root atom and returning when it
 
142
     * hits the target atom.
 
143
     * CAUTION: This recursive method sets the VISITED flag of each atom
 
144
     * does not reset it after finishing the search. If you want to do the
 
145
     * operation on the same collection of atoms more than once, you have
 
146
     * to set all the VISITED flags to false before each operation
 
147
     * by looping of the atoms and doing a
 
148
     * "atom.setFlag((CDKConstants.VISITED, false));"
 
149
     *
 
150
     * @param molecule The
 
151
     *                 AtomContainer to be searched
 
152
     * @param root     The root atom
 
153
     *                 to start the search at
 
154
     * @param target   The target
 
155
     * @param path     An
 
156
     *                 AtomContainer to be filled with the path
 
157
     * @return true if the
 
158
     *         target atom was found during this function call
 
159
     */
 
160
    public static boolean depthFirstTargetSearch(IAtomContainer molecule, IAtom root, IAtom target, IAtomContainer path) throws NoSuchAtomException {
 
161
        java.util.List bonds = molecule.getConnectedBondsList(root);
 
162
        IAtom nextAtom;
 
163
        root.setFlag(CDKConstants.VISITED, true);
 
164
        for (int f = 0; f < bonds.size(); f++) {
 
165
                IBond bond = (IBond)bonds.get(f);
 
166
            nextAtom = bond.getConnectedAtom(root);
 
167
            if (!nextAtom.getFlag(CDKConstants.VISITED)) {
 
168
                path.addAtom(nextAtom);
 
169
                path.addBond(bond);
 
170
                if (nextAtom == target) {
 
171
                    return true;
 
172
                } else {
 
173
                    if (!depthFirstTargetSearch(molecule, nextAtom, target, path)) {
 
174
                        // we did not find the target
 
175
                        path.removeAtom(nextAtom);
 
176
                        path.removeBond(bond);
 
177
                    } else {
 
178
                        return true;
 
179
                    }
 
180
                }
 
181
            }
 
182
        }
 
183
        return false;
 
184
    }
 
185
 
 
186
 
 
187
    /**
 
188
     * Performs a breadthFirstSearch in an AtomContainer starting with a
 
189
     * particular sphere, which usually consists of one start atom. While
 
190
     * searching the graph, the method marks each visited atom. It then puts all
 
191
     * the atoms connected to the atoms in the given sphere into a new vector
 
192
     * which forms the sphere to search for the next recursive method call. All
 
193
     * atoms that have been visited are put into a molecule container. This
 
194
     * breadthFirstSearch does thus find the connected graph for a given start
 
195
     * atom.
 
196
     *
 
197
     * @param ac       The AtomContainer to be searched
 
198
     * @param sphere   A sphere of atoms to start the search with
 
199
     * @param molecule A molecule into which all the atoms and bonds are stored
 
200
     *                 that are found during search
 
201
     */
 
202
    public static void breadthFirstSearch(IAtomContainer ac, Vector sphere, IMolecule molecule) {
 
203
        // logger.debug("Staring partitioning with this ac: " + ac);
 
204
        breadthFirstSearch(ac, sphere, molecule, -1);
 
205
    }
 
206
 
 
207
 
 
208
    /**
 
209
     * Returns the atoms which are closest to an atom in an AtomContainer by bonds.
 
210
     * If number of atoms in or below sphere x&lt;max andnumber of atoms in or below sphere x+1&gt;max then atoms in or below sphere x+1 are returned.
 
211
     *
 
212
     * @param ac  The AtomContainer to examine
 
213
     * @param a   the atom to start from
 
214
     * @param max the number of neighbours to return
 
215
     * @return the average bond length
 
216
     */
 
217
    public static IAtom[] findClosestByBond(IAtomContainer ac, IAtom a, int max) {
 
218
        IMolecule mol = ac.getBuilder().newMolecule();
 
219
        Vector v = new Vector();
 
220
        v.add(a);
 
221
        breadthFirstSearch(ac, v, mol, max);
 
222
        IAtom[] returnValue = new IAtom[mol.getAtomCount() - 1];
 
223
        int k = 0;
 
224
        for (int i = 0; i < mol.getAtomCount(); i++) {
 
225
            if (mol.getAtom(i) != a) {
 
226
                returnValue[k] = mol.getAtom(i);
 
227
                k++;
 
228
            }
 
229
        }
 
230
        return (returnValue);
 
231
    }
 
232
 
 
233
 
 
234
    /**
 
235
     * Performs a breadthFirstSearch in an AtomContainer starting with a
 
236
     * particular sphere, which usually consists of one start atom. While
 
237
     * searching the graph, the method marks each visited atom. It then puts all
 
238
     * the atoms connected to the atoms in the given sphere into a new vector
 
239
     * which forms the sphere to search for the next recursive method call. All
 
240
     * atoms that have been visited are put into a molecule container. This
 
241
     * breadthFirstSearch does thus find the connected graph for a given start
 
242
     * atom.
 
243
     *
 
244
     * @param ac       The AtomContainer to be searched
 
245
     * @param sphere   A sphere of atoms to start the search with
 
246
     * @param molecule A molecule into which all the atoms and bonds are stored
 
247
     *                 that are found during search
 
248
     */
 
249
    public static void breadthFirstSearch(IAtomContainer ac, Vector sphere, IMolecule molecule, int max) {
 
250
        IAtom atom;
 
251
        IAtom nextAtom;
 
252
        Vector newSphere = new Vector();
 
253
        for (int f = 0; f < sphere.size(); f++) {
 
254
            atom = (IAtom) sphere.elementAt(f);
 
255
            //logger.debug("atoms  "+ atom + f);
 
256
            //logger.debug("sphere size  "+ sphere.size());
 
257
            molecule.addAtom(atom);
 
258
            // first copy LonePair's and SingleElectron's of this Atom as they need
 
259
            // to be copied too
 
260
            java.util.List lonePairs = ac.getConnectedLonePairsList(atom);
 
261
            //logger.debug("found #ec's: " + lonePairs.length);
 
262
            for (int i = 0; i < lonePairs.size(); i++) molecule.addLonePair((ILonePair)lonePairs.get(i));
 
263
            java.util.List singleElectrons = ac.getConnectedSingleElectronsList(atom);
 
264
            for (int i = 0; i < singleElectrons.size(); i++) molecule.addSingleElectron((ISingleElectron)singleElectrons.get(i));
 
265
            // now look at bonds
 
266
            java.util.List bonds = ac.getConnectedBondsList(atom);
 
267
            for (int g = 0; g < bonds.size(); g++) {
 
268
                IBond bond = (IBond)bonds.get(g);
 
269
                if (!bond.getFlag(CDKConstants.VISITED)) {
 
270
                    molecule.addBond(bond);
 
271
                    bond.setFlag(CDKConstants.VISITED, true);
 
272
                }
 
273
                nextAtom = bond.getConnectedAtom(atom);
 
274
                if (!nextAtom.getFlag(CDKConstants.VISITED)) {
 
275
//                                      logger.debug("wie oft???");
 
276
                    newSphere.addElement(nextAtom);
 
277
                    nextAtom.setFlag(CDKConstants.VISITED, true);
 
278
                }
 
279
            }
 
280
            if (max > -1 && molecule.getAtomCount() > max)
 
281
                return;
 
282
        }
 
283
        if (newSphere.size() > 0) {
 
284
            breadthFirstSearch(ac, newSphere, molecule, max);
 
285
        }
 
286
    }
 
287
 
 
288
 
 
289
    /**
 
290
     * Performs a breadthFirstTargetSearch in an AtomContainer starting with a
 
291
     * particular sphere, which usually consists of one start atom. While
 
292
     * searching the graph, the method marks each visited atom. It then puts all
 
293
     * the atoms connected to the atoms in the given sphere into a new vector
 
294
     * which forms the sphere to search for the next recursive method call.
 
295
     * The method keeps track of the sphere count and returns it as soon
 
296
     * as the target atom is encountered.
 
297
     *
 
298
     * @param ac         The AtomContainer in which the path search is to be performed.
 
299
     * @param sphere     The sphere of atoms to start with. Usually just the starting atom
 
300
     * @param target     The target atom to be searched
 
301
     * @param pathLength The current path length, incremented and passed in recursive calls. Call this method with "zero".
 
302
     * @param cutOff     Stop the path search when this cutOff sphere count has been reached
 
303
     * @return The shortest path between the starting sphere and the target atom
 
304
     */
 
305
    public static int breadthFirstTargetSearch(IAtomContainer ac, Vector sphere, IAtom target, int pathLength, int cutOff) {
 
306
        if (pathLength == 0) resetFlags(ac);
 
307
        pathLength++;
 
308
        if (pathLength > cutOff) {
 
309
            return -1;
 
310
        }
 
311
        IAtom atom;
 
312
 
 
313
        IAtom nextAtom;
 
314
        Vector newSphere = new Vector();
 
315
        for (int f = 0; f < sphere.size(); f++) {
 
316
            atom = (IAtom) sphere.elementAt(f);
 
317
            java.util.List bonds = ac.getConnectedBondsList(atom);
 
318
            for (int g = 0; g < bonds.size(); g++) {
 
319
                IBond bond = (IBond)bonds.get(g);
 
320
                if (!bond.getFlag(CDKConstants.VISITED)) {
 
321
                    bond.setFlag(CDKConstants.VISITED, true);
 
322
                }
 
323
                nextAtom = bond.getConnectedAtom(atom);
 
324
                if (!nextAtom.getFlag(CDKConstants.VISITED)) {
 
325
                    if (nextAtom == target) {
 
326
                        return pathLength;
 
327
                    }
 
328
                    newSphere.addElement(nextAtom);
 
329
                    nextAtom.setFlag(CDKConstants.VISITED, true);
 
330
                }
 
331
            }
 
332
        }
 
333
        if (newSphere.size() > 0) {
 
334
            return breadthFirstTargetSearch(ac, newSphere, target, pathLength, cutOff);
 
335
        }
 
336
        return -1;
 
337
    }
 
338
 
 
339
    public static void resetFlags(IAtomContainer ac) {
 
340
        for (int f = 0; f < ac.getAtomCount(); f++) {
 
341
            ac.getAtom(f).setFlag(CDKConstants.VISITED, false);
 
342
        }
 
343
        for (int f = 0; f < ac.getBondCount(); f++) {
 
344
            ac.getBond(f).setFlag(CDKConstants.VISITED, false);
 
345
        }
 
346
 
 
347
    }
 
348
 
 
349
    /**
 
350
     * Returns the radius of the molecular graph.
 
351
     *
 
352
     * @param atomContainer The molecule to consider
 
353
     * @return The topological radius
 
354
     */
 
355
    public static int getMolecularGraphRadius(IAtomContainer atomContainer) {
 
356
        int natom = atomContainer.getAtomCount();
 
357
 
 
358
        int[][] admat = AdjacencyMatrix.getMatrix(atomContainer);
 
359
        int[][] distanceMatrix = computeFloydAPSP(admat);
 
360
 
 
361
        int[] eta = new int[natom];
 
362
        for (int i = 0; i < natom; i++) {
 
363
            int max = -99999;
 
364
            for (int j = 0; j < natom; j++) {
 
365
                if (distanceMatrix[i][j] > max) max = distanceMatrix[i][j];
 
366
            }
 
367
            eta[i] = max;
 
368
        }
 
369
        int min = 999999;
 
370
        for (int i = 0; i < eta.length; i++) {
 
371
            if (eta[i] < min) min = eta[i];
 
372
        }
 
373
        return min;
 
374
    }
 
375
 
 
376
    /**
 
377
     * Returns the diameter of the molecular graph.
 
378
     *
 
379
     * @param atomContainer The molecule to consider
 
380
     * @return The topological diameter
 
381
     */
 
382
    public static int getMolecularGraphDiameter(IAtomContainer atomContainer) {
 
383
        int natom = atomContainer.getAtomCount();
 
384
 
 
385
        int[][] admat = AdjacencyMatrix.getMatrix(atomContainer);
 
386
        int[][] distanceMatrix = computeFloydAPSP(admat);
 
387
 
 
388
        int[] eta = new int[natom];
 
389
        for (int i = 0; i < natom; i++) {
 
390
            int max = -99999;
 
391
            for (int j = 0; j < natom; j++) {
 
392
                if (distanceMatrix[i][j] > max) max = distanceMatrix[i][j];
 
393
            }
 
394
            eta[i] = max;
 
395
        }
 
396
        int max = -999999;
 
397
        for (int i = 0; i < eta.length; i++) {
 
398
            if (eta[i] > max) max = eta[i];
 
399
        }
 
400
        return max;
 
401
    }
 
402
 
 
403
    /**
 
404
     * Returns the number of vertices that are a distance 'd' apart.
 
405
     * <p/>
 
406
     * In this method, d is the topological distance (ie edge count).
 
407
     *
 
408
     * @param atomContainer The molecule to consider
 
409
     * @param distance      The distance to consider
 
410
     * @return The number of vertices
 
411
     */
 
412
    public static int getVertexCountAtDistance(IAtomContainer atomContainer, int distance) {
 
413
        int natom = atomContainer.getAtomCount();
 
414
 
 
415
        int[][] admat = AdjacencyMatrix.getMatrix(atomContainer);
 
416
        int[][] distanceMatrix = computeFloydAPSP(admat);
 
417
 
 
418
        int n = 0;
 
419
 
 
420
        for (int i = 0; i < natom; i++) {
 
421
            for (int j = 0; j < natom; j++) {
 
422
                if (distanceMatrix[i][j] == distance) n++;
 
423
            }
 
424
        }
 
425
        return n / 2;
 
426
    }
 
427
 
 
428
    /**
 
429
     * Returns a list of atoms in the shortest path between two atoms.
 
430
     *
 
431
     * This method uses the Djikstra algorithm to find all the atoms in the shortest
 
432
     * path between the two specified atoms. The start and end atoms are also included
 
433
     * in the path returned
 
434
     *
 
435
     * @param atomContainer The molecule to search in
 
436
     * @param start The starting atom
 
437
     * @param end The ending atom
 
438
     * @return A <code>List</code> containing the atoms in the shortest path between <code>start</code> and
 
439
     * <code>end</code> inclusive
 
440
     */
 
441
    public static List getShortestPath(IAtomContainer atomContainer, IAtom start, IAtom end) {
 
442
        int natom = atomContainer.getAtomCount();
 
443
        int endNumber = atomContainer.getAtomNumber(end);
 
444
        int startNumber = atomContainer.getAtomNumber(start);
 
445
        int[] dist = new int[natom];
 
446
        int[] previous = new int[natom];
 
447
        for (int i = 0; i < natom; i++) {
 
448
            dist[i] = 99999999;
 
449
            previous[i] = -1;
 
450
        }
 
451
        dist[atomContainer.getAtomNumber(start)] = 0;
 
452
 
 
453
        ArrayList S = new ArrayList();
 
454
        ArrayList Q = new ArrayList();
 
455
        for (int i = 0; i < natom; i++) Q.add(new Integer(i));
 
456
 
 
457
        while (true) {
 
458
            if (Q.size() == 0) break;
 
459
 
 
460
            // extract min
 
461
            int u = 999999;
 
462
            int index = 0;
 
463
            for (int i = 0; i < Q.size(); i++) {
 
464
                int tmp = ((Integer)Q.get(i)).intValue();
 
465
                if (dist[tmp] < u) {
 
466
                    u = dist[tmp];
 
467
                    index = tmp;
 
468
                }
 
469
            }
 
470
            Q.remove(Q.indexOf(new Integer(index)));
 
471
            S.add(atomContainer.getAtom(index));
 
472
            if (index == endNumber) break;
 
473
 
 
474
            // relaxation
 
475
            java.util.List connected = atomContainer.getConnectedAtomsList( atomContainer.getAtom(index) );
 
476
            for (int i = 0; i < connected.size(); i++) {
 
477
                int anum = atomContainer.getAtomNumber((IAtom)connected.get(i));
 
478
                if (dist[anum] > dist[index] + 1) { // all edges have equals weights
 
479
                    dist[anum] = dist[index] + 1;
 
480
                    previous[anum] = index;
 
481
                }
 
482
            }
 
483
        }
 
484
 
 
485
        ArrayList tmp = new ArrayList();
 
486
        int u = endNumber;
 
487
        while (true) {
 
488
            tmp.add(0, atomContainer.getAtom(u));
 
489
            u = previous[u];
 
490
            if (u == startNumber){
 
491
                tmp.add(0, atomContainer.getAtom(u));
 
492
                break;
 
493
            }
 
494
        }
 
495
        return tmp;
 
496
    }
 
497
 
 
498
    private static List allPaths;
 
499
 
 
500
    /**
 
501
     * Get a list of all the paths between two atoms.
 
502
     * <p/>
 
503
     * If the two atoms are the same an empty list is returned. Note that this problem
 
504
     * is NP-hard and so can take a long time for large graphs.
 
505
     *
 
506
     * @param atomContainer The molecule to consider
 
507
     * @param start         The starting Atom of the path
 
508
     * @param end           The ending Atom of the path
 
509
     * @return A <code>List</code> containing all the paths between the specified atoms
 
510
     */
 
511
    public static List getAllPaths(IAtomContainer atomContainer, IAtom start, IAtom end) {
 
512
        allPaths = new ArrayList();
 
513
        if (start.equals(end)) return allPaths;
 
514
        findPathBetween(atomContainer, start, end, new ArrayList());
 
515
        return allPaths;
 
516
    }
 
517
 
 
518
    private static void findPathBetween(IAtomContainer atomContainer, IAtom start, IAtom end, List path) {
 
519
        if (start == end) {
 
520
            path.add(start);
 
521
            allPaths.add(new ArrayList(path));
 
522
            path.remove(path.size() - 1);
 
523
            return;
 
524
        }
 
525
        if (path.contains(start))
 
526
            return;
 
527
        path.add(start);
 
528
        List nbrs = atomContainer.getConnectedAtomsList(start);
 
529
        for (Iterator i = nbrs.iterator(); i.hasNext();)
 
530
            findPathBetween(atomContainer, (IAtom) i.next(), end, path);
 
531
        path.remove(path.size() - 1);
 
532
    }
 
533
 
 
534
    /**
 
535
     * Get the paths starting from an atom of specified length.
 
536
     * <p/>
 
537
     * This method returns a set of paths. Each path is a <code>List</code> of atoms that
 
538
     * make up the path (ie they are sequentially connected).
 
539
     *
 
540
     * @param atomContainer The molecule to consider
 
541
     * @param start         The starting atom
 
542
     * @param length        The length of paths to look for
 
543
     * @return A  <code>List</code> containing the paths found
 
544
     */
 
545
    public static List getPathsOfLength(IAtomContainer atomContainer, IAtom start, int length) {
 
546
        ArrayList curPath = new ArrayList();
 
547
        ArrayList paths = new ArrayList();
 
548
        curPath.add(start);
 
549
        paths.add(curPath);
 
550
        for (int i = 0; i < length; i++) {
 
551
            ArrayList tmpList = new ArrayList();
 
552
            for (int j = 0; j < paths.size(); j++) {
 
553
                curPath = (ArrayList) paths.get(j);
 
554
                IAtom lastVertex = (IAtom) curPath.get(curPath.size() - 1);
 
555
                List neighbors = atomContainer.getConnectedAtomsList(lastVertex);
 
556
                for (int k = 0; k < neighbors.size(); k++) {
 
557
                    ArrayList newPath = new ArrayList(curPath);
 
558
                    if (newPath.contains(neighbors.get(k))) continue;
 
559
                    newPath.add(neighbors.get(k));
 
560
                    tmpList.add(newPath);
 
561
                }
 
562
            }
 
563
            paths.clear();
 
564
            paths.addAll(tmpList);
 
565
        }
 
566
        return (paths);
 
567
    }
 
568
 
 
569
 
 
570
}
 
571