source: src/molecule_graph.cpp@ 8c5327

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 8c5327 was 776b64, checked in by Frederik Heber <heber@…>, 16 years ago

Huge refactoring to make const what is const (ticket #38), continued.

  • too many changes because of too many cross-references to be able to list them up here.
  • NOTE that "make check" runs fine and did catch several error.
  • note that we had to use const_iterator several times when the map, ... was declared const.
  • at times we changed an allocated LinkedCell LCList(...) into

const LinkedCell *LCList;
LCList = new LinkedCell(...);

  • also mutable (see ticket #5) was used, e.g. for molecule::InternalPointer (PointCloud changes are allowed, because they are just accounting).

Signed-off-by: Frederik Heber <heber@…>

  • Property mode set to 100644
File size: 58.9 KB
Line 
1/*
2 * molecule_graph.cpp
3 *
4 * Created on: Oct 5, 2009
5 * Author: heber
6 */
7
8#include "atom.hpp"
9#include "bond.hpp"
10#include "config.hpp"
11#include "element.hpp"
12#include "helpers.hpp"
13#include "linkedcell.hpp"
14#include "lists.hpp"
15#include "memoryallocator.hpp"
16#include "molecule.hpp"
17
18struct BFSAccounting
19{
20 atom **PredecessorList;
21 int *ShortestPathList;
22 enum Shading *ColorList;
23 class StackClass<atom *> *BFSStack;
24 class StackClass<atom *> *TouchedStack;
25 int AtomCount;
26 int BondOrder;
27 atom *Root;
28 bool BackStepping;
29 int CurrentGraphNr;
30 int ComponentNr;
31};
32
33/** Accounting data for Depth First Search.
34 */
35struct DFSAccounting
36{
37 class StackClass<atom *> *AtomStack;
38 class StackClass<bond *> *BackEdgeStack;
39 int CurrentGraphNr;
40 int ComponentNumber;
41 atom *Root;
42 bool BackStepping;
43};
44
45/************************************* Functions for class molecule *********************************/
46
47/** Creates an adjacency list of the molecule.
48 * We obtain an outside file with the indices of atoms which are bondmembers.
49 */
50void molecule::CreateAdjacencyListFromDbondFile(ofstream *out, ifstream *input)
51{
52
53 // 1 We will parse bonds out of the dbond file created by tremolo.
54 int atom1, atom2;
55 atom *Walker, *OtherWalker;
56
57 if (!input) {
58 cout << Verbose(1) << "Opening silica failed \n";
59 };
60
61 *input >> ws >> atom1;
62 *input >> ws >> atom2;
63 cout << Verbose(1) << "Scanning file\n";
64 while (!input->eof()) // Check whether we read everything already
65 {
66 *input >> ws >> atom1;
67 *input >> ws >> atom2;
68
69 if (atom2 < atom1) //Sort indices of atoms in order
70 flip(atom1, atom2);
71 Walker = FindAtom(atom1);
72 OtherWalker = FindAtom(atom2);
73 AddBond(Walker, OtherWalker); //Add the bond between the two atoms with respective indices.
74 }
75}
76;
77
78/** Creates an adjacency list of the molecule.
79 * Generally, we use the CSD approach to bond recognition, that is the the distance
80 * between two atoms A and B must be within [Rcov(A)+Rcov(B)-t,Rcov(A)+Rcov(B)+t] with
81 * a threshold t = 0.4 Angstroem.
82 * To make it O(N log N) the function uses the linked-cell technique as follows:
83 * The procedure is step-wise:
84 * -# Remove every bond in list
85 * -# Count the atoms in the molecule with CountAtoms()
86 * -# partition cell into smaller linked cells of size \a bonddistance
87 * -# put each atom into its corresponding cell
88 * -# go through every cell, check the atoms therein against all possible bond partners in the 27 adjacent cells, add bond if true
89 * -# correct the bond degree iteratively (single->double->triple bond)
90 * -# finally print the bond list to \a *out if desired
91 * \param *out out stream for printing the matrix, NULL if no output
92 * \param bonddistance length of linked cells (i.e. maximum minimal length checked)
93 * \param IsAngstroem whether coordinate system is gauged to Angstroem or Bohr radii
94 */
95void molecule::CreateAdjacencyList(ofstream *out, double bonddistance, bool IsAngstroem)
96{
97
98 atom *Walker = NULL;
99 atom *OtherWalker = NULL;
100 atom **AtomMap = NULL;
101 int n[NDIM];
102 double distance, MinDistance, MaxDistance;
103 LinkedCell *LC = NULL;
104
105 BondDistance = bonddistance; // * ((IsAngstroem) ? 1. : 1./AtomicLengthToAngstroem);
106 *out << Verbose(0) << "Begin of CreateAdjacencyList." << endl;
107 // remove every bond from the list
108 if ((first->next != last) && (last->previous != first)) { // there are bonds present
109 cleanup(first, last);
110 }
111
112 // count atoms in molecule = dimension of matrix (also give each unique name and continuous numbering)
113 CountAtoms(out);
114 *out << Verbose(1) << "AtomCount " << AtomCount << "." << endl;
115
116 if (AtomCount != 0) {
117 LC = new LinkedCell(this, bonddistance);
118
119 // create a list to map Tesselpoint::nr to atom *
120 AtomMap = Malloc<atom *> (AtomCount, "molecule::CreateAdjacencyList - **AtomCount");
121 Walker = start;
122 while (Walker->next != end) {
123 Walker = Walker->next;
124 AtomMap[Walker->nr] = Walker;
125 }
126
127 // 3a. go through every cell
128 for (LC->n[0] = 0; LC->n[0] < LC->N[0]; LC->n[0]++)
129 for (LC->n[1] = 0; LC->n[1] < LC->N[1]; LC->n[1]++)
130 for (LC->n[2] = 0; LC->n[2] < LC->N[2]; LC->n[2]++) {
131 const LinkedNodes *List = LC->GetCurrentCell();
132 //*out << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << " containing " << List->size() << " points." << endl;
133 if (List != NULL) {
134 for (LinkedNodes::const_iterator Runner = List->begin(); Runner != List->end(); Runner++) {
135 Walker = AtomMap[(*Runner)->nr];
136 //*out << Verbose(0) << "Current Atom is " << *Walker << "." << endl;
137 // 3c. check for possible bond between each atom in this and every one in the 27 cells
138 for (n[0] = -1; n[0] <= 1; n[0]++)
139 for (n[1] = -1; n[1] <= 1; n[1]++)
140 for (n[2] = -1; n[2] <= 1; n[2]++) {
141 const LinkedNodes *OtherList = LC->GetRelativeToCurrentCell(n);
142 //*out << Verbose(2) << "Current relative cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << " containing " << List->size() << " points." << endl;
143 if (OtherList != NULL) {
144 for (LinkedNodes::const_iterator OtherRunner = OtherList->begin(); OtherRunner != OtherList->end(); OtherRunner++) {
145 if ((*OtherRunner)->nr > Walker->nr) {
146 OtherWalker = AtomMap[(*OtherRunner)->nr];
147 //*out << Verbose(1) << "Checking distance " << OtherWalker->x.PeriodicDistanceSquared(&(Walker->x), cell_size) << " against typical bond length of " << bonddistance*bonddistance << "." << endl;
148 MinDistance = OtherWalker->type->CovalentRadius + Walker->type->CovalentRadius;
149 MinDistance *= (IsAngstroem) ? 1. : 1. / AtomicLengthToAngstroem;
150 MaxDistance = MinDistance + BONDTHRESHOLD;
151 MinDistance -= BONDTHRESHOLD;
152 distance = OtherWalker->x.PeriodicDistanceSquared(&(Walker->x), cell_size);
153 if ((OtherWalker->father->nr > Walker->father->nr) && (distance <= MaxDistance * MaxDistance) && (distance >= MinDistance * MinDistance)) { // create bond if distance is smaller
154 //*out << Verbose(1) << "Adding Bond between " << *Walker << " and " << *OtherWalker << " in distance " << sqrt(distance) << "." << endl;
155 AddBond(Walker->father, OtherWalker->father, 1); // also increases molecule::BondCount
156 } else {
157 //*out << Verbose(1) << "Not Adding: Wrong label order or distance too great." << endl;
158 }
159 }
160 }
161 }
162 }
163 }
164 }
165 }
166 Free(&AtomMap);
167 delete (LC);
168 *out << Verbose(1) << "I detected " << BondCount << " bonds in the molecule with distance " << BondDistance << "." << endl;
169
170 // correct bond degree by comparing valence and bond degree
171 CorrectBondDegree(out);
172
173 // output bonds for debugging (if bond chain list was correctly installed)
174 ActOnAllAtoms(&atom::OutputBondOfAtom, out);
175 } else
176 *out << Verbose(1) << "AtomCount is " << AtomCount << ", thus no bonds, no connections!." << endl;
177 *out << Verbose(0) << "End of CreateAdjacencyList." << endl;
178}
179;
180
181/** Prints a list of all bonds to \a *out.
182 * \param output stream
183 */
184void molecule::OutputBondsList(ofstream *out)
185{
186 *out << Verbose(1) << endl << "From contents of bond chain list:";
187 bond *Binder = first;
188 while (Binder->next != last) {
189 Binder = Binder->next;
190 *out << *Binder << "\t" << endl;
191 }
192 *out << endl;
193}
194;
195
196/** correct bond degree by comparing valence and bond degree.
197 * correct Bond degree of each bond by checking both bond partners for a mismatch between valence and current sum of bond degrees,
198 * iteratively increase the one first where the other bond partner has the fewest number of bonds (i.e. in general bonds oxygene
199 * preferred over carbon bonds). Beforehand, we had picked the first mismatching partner, which lead to oxygenes with single instead of
200 * double bonds as was expected.
201 * \param *out output stream for debugging
202 * \return number of bonds that could not be corrected
203 */
204int molecule::CorrectBondDegree(ofstream *out)
205{
206 int No = 0;
207
208 if (BondCount != 0) {
209 *out << Verbose(1) << "Correcting Bond degree of each bond ... " << endl;
210 do {
211 No = SumPerAtom(&atom::CorrectBondDegree, out);
212 } while (No);
213 *out << " done." << endl;
214 } else {
215 *out << Verbose(1) << "BondCount is " << BondCount << ", no bonds between any of the " << AtomCount << " atoms." << endl;
216 }
217 *out << No << " bonds could not be corrected." << endl;
218
219 return (No);
220}
221;
222
223/** Counts all cyclic bonds and returns their number.
224 * \note Hydrogen bonds can never by cyclic, thus no check for that
225 * \param *out output stream for debugging
226 * \return number opf cyclic bonds
227 */
228int molecule::CountCyclicBonds(ofstream *out)
229{
230 NoCyclicBonds = 0;
231 int *MinimumRingSize = NULL;
232 MoleculeLeafClass *Subgraphs = NULL;
233 class StackClass<bond *> *BackEdgeStack = NULL;
234 bond *Binder = first;
235 if ((Binder->next != last) && (Binder->next->Type == Undetermined)) {
236 *out << Verbose(0) << "No Depth-First-Search analysis performed so far, calling ..." << endl;
237 Subgraphs = DepthFirstSearchAnalysis(out, BackEdgeStack);
238 while (Subgraphs->next != NULL) {
239 Subgraphs = Subgraphs->next;
240 delete (Subgraphs->previous);
241 }
242 delete (Subgraphs);
243 delete[] (MinimumRingSize);
244 }
245 while (Binder->next != last) {
246 Binder = Binder->next;
247 if (Binder->Cyclic)
248 NoCyclicBonds++;
249 }
250 delete (BackEdgeStack);
251 return NoCyclicBonds;
252}
253;
254
255/** Returns Shading as a char string.
256 * \param color the Shading
257 * \return string of the flag
258 */
259string molecule::GetColor(enum Shading color)
260{
261 switch (color) {
262 case white:
263 return "white";
264 break;
265 case lightgray:
266 return "lightgray";
267 break;
268 case darkgray:
269 return "darkgray";
270 break;
271 case black:
272 return "black";
273 break;
274 default:
275 return "uncolored";
276 break;
277 };
278}
279;
280
281/** Sets atom::GraphNr and atom::LowpointNr to BFSAccounting::CurrentGraphNr.
282 * \param *out output stream for debugging
283 * \param *Walker current node
284 * \param &BFS structure with accounting data for BFS
285 */
286void DepthFirstSearchAnalysis_SetWalkersGraphNr(ofstream *out, atom *&Walker, struct DFSAccounting &DFS)
287{
288 if (!DFS.BackStepping) { // if we don't just return from (8)
289 Walker->GraphNr = DFS.CurrentGraphNr;
290 Walker->LowpointNr = DFS.CurrentGraphNr;
291 *out << Verbose(1) << "Setting Walker[" << Walker->Name << "]'s number to " << Walker->GraphNr << " with Lowpoint " << Walker->LowpointNr << "." << endl;
292 DFS.AtomStack->Push(Walker);
293 DFS.CurrentGraphNr++;
294 }
295}
296;
297
298/** During DFS goes along unvisited bond and touches other atom.
299 * Sets bond::type, if
300 * -# BackEdge: set atom::LowpointNr and push on \a BackEdgeStack
301 * -# TreeEgde: set atom::Ancestor and continue with Walker along this edge
302 * Continue until molecule::FindNextUnused() finds no more unused bonds.
303 * \param *out output stream for debugging
304 * \param *mol molecule with atoms and finding unused bonds
305 * \param *&Binder current edge
306 * \param &DFS DFS accounting data
307 */
308void DepthFirstSearchAnalysis_ProbeAlongUnusedBond(ofstream *out, molecule *mol, atom *&Walker, bond *&Binder, struct DFSAccounting &DFS)
309{
310 atom *OtherAtom = NULL;
311
312 do { // (3) if Walker has no unused egdes, go to (5)
313 DFS.BackStepping = false; // reset backstepping flag for (8)
314 if (Binder == NULL) // if we don't just return from (11), Binder is already set to next unused
315 Binder = mol->FindNextUnused(Walker);
316 if (Binder == NULL)
317 break;
318 *out << Verbose(2) << "Current Unused Bond is " << *Binder << "." << endl;
319 // (4) Mark Binder used, ...
320 Binder->MarkUsed(black);
321 OtherAtom = Binder->GetOtherAtom(Walker);
322 *out << Verbose(2) << "(4) OtherAtom is " << OtherAtom->Name << "." << endl;
323 if (OtherAtom->GraphNr != -1) {
324 // (4a) ... if "other" atom has been visited (GraphNr != 0), set lowpoint to minimum of both, go to (3)
325 Binder->Type = BackEdge;
326 DFS.BackEdgeStack->Push(Binder);
327 Walker->LowpointNr = (Walker->LowpointNr < OtherAtom->GraphNr) ? Walker->LowpointNr : OtherAtom->GraphNr;
328 *out << Verbose(3) << "(4a) Visited: Setting Lowpoint of Walker[" << Walker->Name << "] to " << Walker->LowpointNr << "." << endl;
329 } else {
330 // (4b) ... otherwise set OtherAtom as Ancestor of Walker and Walker as OtherAtom, go to (2)
331 Binder->Type = TreeEdge;
332 OtherAtom->Ancestor = Walker;
333 Walker = OtherAtom;
334 *out << Verbose(3) << "(4b) Not Visited: OtherAtom[" << OtherAtom->Name << "]'s Ancestor is now " << OtherAtom->Ancestor->Name << ", Walker is OtherAtom " << OtherAtom->Name << "." << endl;
335 break;
336 }
337 Binder = NULL;
338 } while (1); // (3)
339}
340;
341
342/** Checks whether we have a new component.
343 * if atom::LowpointNr of \a *&Walker is greater than atom::GraphNr of its atom::Ancestor, we have a new component.
344 * Meaning that if we touch upon a node who suddenly has a smaller atom::LowpointNr than its ancestor, then we
345 * have a found a new branch in the graph tree.
346 * \param *out output stream for debugging
347 * \param *mol molecule with atoms and finding unused bonds
348 * \param *&Walker current node
349 * \param &DFS DFS accounting data
350 */
351void DepthFirstSearchAnalysis_CheckForaNewComponent(ofstream *out, molecule *mol, atom *&Walker, struct DFSAccounting &DFS, MoleculeLeafClass *&LeafWalker)
352{
353 atom *OtherAtom = NULL;
354
355 // (5) if Ancestor of Walker is ...
356 *out << Verbose(1) << "(5) Number of Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "] is " << Walker->Ancestor->GraphNr << "." << endl;
357
358 if (Walker->Ancestor->GraphNr != DFS.Root->GraphNr) {
359 // (6) (Ancestor of Walker is not Root)
360 if (Walker->LowpointNr < Walker->Ancestor->GraphNr) {
361 // (6a) set Ancestor's Lowpoint number to minimum of of its Ancestor and itself, go to Step(8)
362 Walker->Ancestor->LowpointNr = (Walker->Ancestor->LowpointNr < Walker->LowpointNr) ? Walker->Ancestor->LowpointNr : Walker->LowpointNr;
363 *out << Verbose(2) << "(6) Setting Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s Lowpoint to " << Walker->Ancestor->LowpointNr << "." << endl;
364 } else {
365 // (7) (Ancestor of Walker is a separating vertex, remove all from stack till Walker (including), these and Ancestor form a component
366 Walker->Ancestor->SeparationVertex = true;
367 *out << Verbose(2) << "(7) Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s is a separating vertex, creating component." << endl;
368 mol->SetNextComponentNumber(Walker->Ancestor, DFS.ComponentNumber);
369 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Ancestor's Compont is " << DFS.ComponentNumber << "." << endl;
370 mol->SetNextComponentNumber(Walker, DFS.ComponentNumber);
371 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Compont is " << DFS.ComponentNumber << "." << endl;
372 do {
373 OtherAtom = DFS.AtomStack->PopLast();
374 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
375 mol->SetNextComponentNumber(OtherAtom, DFS.ComponentNumber);
376 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << DFS.ComponentNumber << "." << endl;
377 } while (OtherAtom != Walker);
378 DFS.ComponentNumber++;
379 }
380 // (8) Walker becomes its Ancestor, go to (3)
381 *out << Verbose(2) << "(8) Walker[" << Walker->Name << "] is now its Ancestor " << Walker->Ancestor->Name << ", backstepping. " << endl;
382 Walker = Walker->Ancestor;
383 DFS.BackStepping = true;
384 }
385}
386;
387
388/** Cleans the root stack when we have found a component.
389 * If we are not DFSAccounting::BackStepping, then we clear the root stack by putting everything into a
390 * component down till we meet DFSAccounting::Root.
391 * \param *out output stream for debugging
392 * \param *mol molecule with atoms and finding unused bonds
393 * \param *&Walker current node
394 * \param *&Binder current edge
395 * \param &DFS DFS accounting data
396 */
397void DepthFirstSearchAnalysis_CleanRootStackDownTillWalker(ofstream *out, molecule *mol, atom *&Walker, bond *&Binder, struct DFSAccounting &DFS, MoleculeLeafClass *&LeafWalker)
398{
399 atom *OtherAtom = NULL;
400
401 if (!DFS.BackStepping) { // coming from (8) want to go to (3)
402 // (9) remove all from stack till Walker (including), these and Root form a component
403 DFS.AtomStack->Output(out);
404 mol->SetNextComponentNumber(DFS.Root, DFS.ComponentNumber);
405 *out << Verbose(3) << "(9) Root[" << DFS.Root->Name << "]'s Component is " << DFS.ComponentNumber << "." << endl;
406 mol->SetNextComponentNumber(Walker, DFS.ComponentNumber);
407 *out << Verbose(3) << "(9) Walker[" << Walker->Name << "]'s Component is " << DFS.ComponentNumber << "." << endl;
408 do {
409 OtherAtom = DFS.AtomStack->PopLast();
410 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
411 mol->SetNextComponentNumber(OtherAtom, DFS.ComponentNumber);
412 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << DFS.ComponentNumber << "." << endl;
413 } while (OtherAtom != Walker);
414 DFS.ComponentNumber++;
415
416 // (11) Root is separation vertex, set Walker to Root and go to (4)
417 Walker = DFS.Root;
418 Binder = mol->FindNextUnused(Walker);
419 *out << Verbose(1) << "(10) Walker is Root[" << DFS.Root->Name << "], next Unused Bond is " << Binder << "." << endl;
420 if (Binder != NULL) { // Root is separation vertex
421 *out << Verbose(1) << "(11) Root is a separation vertex." << endl;
422 Walker->SeparationVertex = true;
423 }
424 }
425}
426;
427
428/** Initializes DFSAccounting structure.
429 * \param *out output stream for debugging
430 * \param &DFS accounting structure to allocate
431 * \param AtomCount number of nodes in graph
432 * \param BondCount number of edges in graph
433 */
434void DepthFirstSearchAnalysis_Init(ofstream *out, struct DFSAccounting &DFS, int AtomCount, int BondCount)
435{
436 DFS.AtomStack = new StackClass<atom *> (AtomCount);
437 DFS.CurrentGraphNr = 0;
438 DFS.ComponentNumber = 0;
439 DFS.BackStepping = false;
440}
441;
442
443/** Free's DFSAccounting structure.
444 * \param *out output stream for debugging
445 * \param &DFS accounting structure to free
446 */
447void DepthFirstSearchAnalysis_Finalize(ofstream *out, struct DFSAccounting &DFS)
448{
449 delete (DFS.AtomStack);
450}
451;
452
453/** Performs a Depth-First search on this molecule.
454 * Marks bonds in molecule as cyclic, bridge, ... and atoms as
455 * articulations points, ...
456 * We use the algorithm from [Even, Graph Algorithms, p.62].
457 * \param *out output stream for debugging
458 * \param *&BackEdgeStack NULL pointer to StackClass with all the found back edges, allocated and filled on return
459 * \return list of each disconnected subgraph as an individual molecule class structure
460 */
461MoleculeLeafClass * molecule::DepthFirstSearchAnalysis(ofstream *out, class StackClass<bond *> *&BackEdgeStack)
462{
463 struct DFSAccounting DFS;
464 BackEdgeStack = new StackClass<bond *> (BondCount);
465 DFS.BackEdgeStack = BackEdgeStack;
466 MoleculeLeafClass *SubGraphs = new MoleculeLeafClass(NULL);
467 MoleculeLeafClass *LeafWalker = SubGraphs;
468 int OldGraphNr = 0;
469 atom *Walker = NULL;
470 bond *Binder = NULL;
471
472 *out << Verbose(0) << "Begin of DepthFirstSearchAnalysis" << endl;
473 DepthFirstSearchAnalysis_Init(out, DFS, AtomCount, BondCount);
474 DFS.Root = start->next;
475
476 ResetAllBondsToUnused();
477 SetAtomValueToValue(-1, &atom::GraphNr);
478 ActOnAllAtoms(&atom::InitComponentNr);
479 DFS.BackEdgeStack->ClearStack();
480 while (DFS.Root != end) { // if there any atoms at all
481 // (1) mark all edges unused, empty stack, set atom->GraphNr = 0 for all
482 DFS.AtomStack->ClearStack();
483
484 // put into new subgraph molecule and add this to list of subgraphs
485 LeafWalker = new MoleculeLeafClass(LeafWalker);
486 LeafWalker->Leaf = new molecule(elemente);
487 LeafWalker->Leaf->AddCopyAtom(DFS.Root);
488
489 OldGraphNr = DFS.CurrentGraphNr;
490 Walker = DFS.Root;
491 do { // (10)
492 do { // (2) set number and Lowpoint of Atom to i, increase i, push current atom
493 DepthFirstSearchAnalysis_SetWalkersGraphNr(out, Walker, DFS);
494
495 DepthFirstSearchAnalysis_ProbeAlongUnusedBond(out, this, Walker, Binder, DFS);
496
497 if (Binder == NULL) {
498 *out << Verbose(2) << "No more Unused Bonds." << endl;
499 break;
500 } else
501 Binder = NULL;
502 } while (1); // (2)
503
504 // if we came from backstepping, yet there were no more unused bonds, we end up here with no Ancestor, because Walker is Root! Then we are finished!
505 if ((Walker == DFS.Root) && (Binder == NULL))
506 break;
507
508 DepthFirstSearchAnalysis_CheckForaNewComponent(out, this, Walker, DFS, LeafWalker);
509
510 DepthFirstSearchAnalysis_CleanRootStackDownTillWalker(out, this, Walker, Binder, DFS, LeafWalker);
511
512 } while ((DFS.BackStepping) || (Binder != NULL)); // (10) halt only if Root has no unused edges
513
514 // From OldGraphNr to CurrentGraphNr ranges an disconnected subgraph
515 *out << Verbose(0) << "Disconnected subgraph ranges from " << OldGraphNr << " to " << DFS.CurrentGraphNr << "." << endl;
516 LeafWalker->Leaf->Output(out);
517 *out << endl;
518
519 // step on to next root
520 while ((DFS.Root != end) && (DFS.Root->GraphNr != -1)) {
521 //*out << Verbose(1) << "Current next subgraph root candidate is " << Root->Name << "." << endl;
522 if (DFS.Root->GraphNr != -1) // if already discovered, step on
523 DFS.Root = DFS.Root->next;
524 }
525 }
526 // set cyclic bond criterium on "same LP" basis
527 CyclicBondAnalysis();
528
529 OutputGraphInfoPerAtom(out);
530
531 OutputGraphInfoPerBond(out);
532
533 // free all and exit
534 DepthFirstSearchAnalysis_Finalize(out, DFS);
535 *out << Verbose(0) << "End of DepthFirstSearchAnalysis" << endl;
536 return SubGraphs;
537}
538;
539
540/** Scans through all bonds and set bond::Cyclic to true where atom::LowpointNr of both ends is equal: LP criterion.
541 */
542void molecule::CyclicBondAnalysis()
543{
544 NoCyclicBonds = 0;
545 bond *Binder = first;
546 while (Binder->next != last) {
547 Binder = Binder->next;
548 if (Binder->rightatom->LowpointNr == Binder->leftatom->LowpointNr) { // cyclic ??
549 Binder->Cyclic = true;
550 NoCyclicBonds++;
551 }
552 }
553}
554;
555
556/** Output graph information per atom.
557 * \param *out output stream
558 */
559void molecule::OutputGraphInfoPerAtom(ofstream *out)
560{
561 *out << Verbose(1) << "Final graph info for each atom is:" << endl;
562 ActOnAllAtoms(&atom::OutputGraphInfo, out);
563}
564;
565
566/** Output graph information per bond.
567 * \param *out output stream
568 */
569void molecule::OutputGraphInfoPerBond(ofstream *out)
570{
571 *out << Verbose(1) << "Final graph info for each bond is:" << endl;
572 bond *Binder = first;
573 while (Binder->next != last) {
574 Binder = Binder->next;
575 *out << Verbose(2) << ((Binder->Type == TreeEdge) ? "TreeEdge " : "BackEdge ") << *Binder << ": <";
576 *out << ((Binder->leftatom->SeparationVertex) ? "SP," : "") << "L" << Binder->leftatom->LowpointNr << " G" << Binder->leftatom->GraphNr << " Comp.";
577 Binder->leftatom->OutputComponentNumber(out);
578 *out << " === ";
579 *out << ((Binder->rightatom->SeparationVertex) ? "SP," : "") << "L" << Binder->rightatom->LowpointNr << " G" << Binder->rightatom->GraphNr << " Comp.";
580 Binder->rightatom->OutputComponentNumber(out);
581 *out << ">." << endl;
582 if (Binder->Cyclic) // cyclic ??
583 *out << Verbose(3) << "Lowpoint at each side are equal: CYCLIC!" << endl;
584 }
585}
586;
587
588/** Initialise each vertex as white with no predecessor, empty queue, color Root lightgray.
589 * \param *out output stream for debugging
590 * \param &BFS accounting structure
591 * \param AtomCount number of entries in the array to allocate
592 */
593void InitializeBFSAccounting(ofstream *out, struct BFSAccounting &BFS, int AtomCount)
594{
595 BFS.AtomCount = AtomCount;
596 BFS.PredecessorList = Malloc<atom*> (AtomCount, "molecule::BreadthFirstSearchAdd_Init: **PredecessorList");
597 BFS.ShortestPathList = Malloc<int> (AtomCount, "molecule::BreadthFirstSearchAdd_Init: *ShortestPathList");
598 BFS.ColorList = Malloc<enum Shading> (AtomCount, "molecule::BreadthFirstSearchAdd_Init: *ColorList");
599 BFS.BFSStack = new StackClass<atom *> (AtomCount);
600
601 for (int i = AtomCount; i--;) {
602 BFS.PredecessorList[i] = NULL;
603 BFS.ShortestPathList[i] = -1;
604 BFS.ColorList[i] = white;
605 }
606};
607
608/** Free's accounting structure.
609 * \param *out output stream for debugging
610 * \param &BFS accounting structure
611 */
612void FinalizeBFSAccounting(ofstream *out, struct BFSAccounting &BFS)
613{
614 Free(&BFS.PredecessorList);
615 Free(&BFS.ShortestPathList);
616 Free(&BFS.ColorList);
617 delete (BFS.BFSStack);
618 BFS.AtomCount = 0;
619};
620
621/** Clean the accounting structure.
622 * \param *out output stream for debugging
623 * \param &BFS accounting structure
624 */
625void CleanBFSAccounting(ofstream *out, struct BFSAccounting &BFS)
626{
627 atom *Walker = NULL;
628 while (!BFS.TouchedStack->IsEmpty()) {
629 Walker = BFS.TouchedStack->PopFirst();
630 BFS.PredecessorList[Walker->nr] = NULL;
631 BFS.ShortestPathList[Walker->nr] = -1;
632 BFS.ColorList[Walker->nr] = white;
633 }
634};
635
636/** Resets shortest path list and BFSStack.
637 * \param *out output stream for debugging
638 * \param *&Walker current node, pushed onto BFSAccounting::BFSStack and BFSAccounting::TouchedStack
639 * \param &BFS accounting structure
640 */
641void ResetBFSAccounting(ofstream *out, atom *&Walker, struct BFSAccounting &BFS)
642{
643 BFS.ShortestPathList[Walker->nr] = 0;
644 BFS.BFSStack->ClearStack(); // start with empty BFS stack
645 BFS.BFSStack->Push(Walker);
646 BFS.TouchedStack->Push(Walker);
647};
648
649/** Performs a BFS from \a *Root, trying to find the same node and hence a cycle.
650 * \param *out output stream for debugging
651 * \param *&BackEdge the edge from root that we don't want to move along
652 * \param &BFS accounting structure
653 */
654void CyclicStructureAnalysis_CyclicBFSFromRootToRoot(ofstream *out, bond *&BackEdge, struct BFSAccounting &BFS)
655{
656 atom *Walker = NULL;
657 atom *OtherAtom = NULL;
658 do { // look for Root
659 Walker = BFS.BFSStack->PopFirst();
660 *out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *BFS.Root << "." << endl;
661 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
662 if ((*Runner) != BackEdge) { // only walk along DFS spanning tree (otherwise we always find SP of one being backedge Binder)
663 OtherAtom = (*Runner)->GetOtherAtom(Walker);
664#ifdef ADDHYDROGEN
665 if (OtherAtom->type->Z != 1) {
666#endif
667 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *(*Runner) << "." << endl;
668 if (BFS.ColorList[OtherAtom->nr] == white) {
669 BFS.TouchedStack->Push(OtherAtom);
670 BFS.ColorList[OtherAtom->nr] = lightgray;
671 BFS.PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
672 BFS.ShortestPathList[OtherAtom->nr] = BFS.ShortestPathList[Walker->nr] + 1;
673 *out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " lightgray, its predecessor is " << Walker->Name << " and its Shortest Path is " << BFS.ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl;
674 //if (BFS.ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr]) { // Check for maximum distance
675 *out << Verbose(3) << "Putting OtherAtom into queue." << endl;
676 BFS.BFSStack->Push(OtherAtom);
677 //}
678 } else {
679 *out << Verbose(3) << "Not Adding, has already been visited." << endl;
680 }
681 if (OtherAtom == BFS.Root)
682 break;
683#ifdef ADDHYDROGEN
684 } else {
685 *out << Verbose(2) << "Skipping hydrogen atom " << *OtherAtom << "." << endl;
686 BFS.ColorList[OtherAtom->nr] = black;
687 }
688#endif
689 } else {
690 *out << Verbose(2) << "Bond " << *(*Runner) << " not Visiting, is the back edge." << endl;
691 }
692 }
693 BFS.ColorList[Walker->nr] = black;
694 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
695 if (OtherAtom == BFS.Root) { // if we have found the root, check whether this cycle wasn't already found beforehand
696 // step through predecessor list
697 while (OtherAtom != BackEdge->rightatom) {
698 if (!OtherAtom->GetTrueFather()->IsCyclic) // if one bond in the loop is not marked as cyclic, we haven't found this cycle yet
699 break;
700 else
701 OtherAtom = BFS.PredecessorList[OtherAtom->nr];
702 }
703 if (OtherAtom == BackEdge->rightatom) { // if each atom in found cycle is cyclic, loop's been found before already
704 *out << Verbose(3) << "This cycle was already found before, skipping and removing seeker from search." << endl;
705 do {
706 OtherAtom = BFS.TouchedStack->PopLast();
707 if (BFS.PredecessorList[OtherAtom->nr] == Walker) {
708 *out << Verbose(4) << "Removing " << *OtherAtom << " from lists and stacks." << endl;
709 BFS.PredecessorList[OtherAtom->nr] = NULL;
710 BFS.ShortestPathList[OtherAtom->nr] = -1;
711 BFS.ColorList[OtherAtom->nr] = white;
712 BFS.BFSStack->RemoveItem(OtherAtom);
713 }
714 } while ((!BFS.TouchedStack->IsEmpty()) && (BFS.PredecessorList[OtherAtom->nr] == NULL));
715 BFS.TouchedStack->Push(OtherAtom); // last was wrongly popped
716 OtherAtom = BackEdge->rightatom; // set to not Root
717 } else
718 OtherAtom = BFS.Root;
719 }
720 } while ((!BFS.BFSStack->IsEmpty()) && (OtherAtom != BFS.Root) && (OtherAtom != NULL)); // || (ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr])));
721};
722
723/** Climb back the BFSAccounting::PredecessorList and find cycle members.
724 * \param *out output stream for debugging
725 * \param *&OtherAtom
726 * \param *&BackEdge denotes the edge we did not want to travel along when doing CyclicBFSFromRootToRoot()
727 * \param &BFS accounting structure
728 * \param *&MinimumRingSize minimum distance from this node possible without encountering oneself, set on return for each atom
729 * \param &MinRingSize global minimum distance from one node without encountering oneself, set on return
730 */
731void CyclicStructureAnalysis_RetrieveCycleMembers(ofstream *out, atom *&OtherAtom, bond *&BackEdge, struct BFSAccounting &BFS, int *&MinimumRingSize, int &MinRingSize)
732{
733 atom *Walker = NULL;
734 int NumCycles = 0;
735 int RingSize = -1;
736
737 if (OtherAtom == BFS.Root) {
738 // now climb back the predecessor list and thus find the cycle members
739 NumCycles++;
740 RingSize = 1;
741 BFS.Root->GetTrueFather()->IsCyclic = true;
742 *out << Verbose(1) << "Found ring contains: ";
743 Walker = BFS.Root;
744 while (Walker != BackEdge->rightatom) {
745 *out << Walker->Name << " <-> ";
746 Walker = BFS.PredecessorList[Walker->nr];
747 Walker->GetTrueFather()->IsCyclic = true;
748 RingSize++;
749 }
750 *out << Walker->Name << " with a length of " << RingSize << "." << endl << endl;
751 // walk through all and set MinimumRingSize
752 Walker = BFS.Root;
753 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize;
754 while (Walker != BackEdge->rightatom) {
755 Walker = BFS.PredecessorList[Walker->nr];
756 if (RingSize < MinimumRingSize[Walker->GetTrueFather()->nr])
757 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize;
758 }
759 if ((RingSize < MinRingSize) || (MinRingSize == -1))
760 MinRingSize = RingSize;
761 } else {
762 *out << Verbose(1) << "No ring containing " << *BFS.Root << " with length equal to or smaller than " << MinimumRingSize[Walker->GetTrueFather()->nr] << " found." << endl;
763 }
764};
765
766/** From a given node performs a BFS to touch the next cycle, for whose nodes \a *&MinimumRingSize is set and set it accordingly.
767 * \param *out output stream for debugging
768 * \param *&Root node to look for closest cycle from, i.e. \a *&MinimumRingSize is set for this node
769 * \param *&MinimumRingSize minimum distance from this node possible without encountering oneself, set on return for each atom
770 * \param AtomCount number of nodes in graph
771 */
772void CyclicStructureAnalysis_BFSToNextCycle(ofstream *out, atom *&Root, atom *&Walker, int *&MinimumRingSize, int AtomCount)
773{
774 struct BFSAccounting BFS;
775 atom *OtherAtom = Walker;
776
777 InitializeBFSAccounting(out, BFS, AtomCount);
778
779 ResetBFSAccounting(out, Walker, BFS);
780 while (OtherAtom != NULL) { // look for Root
781 Walker = BFS.BFSStack->PopFirst();
782 //*out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl;
783 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
784 // "removed (*Runner) != BackEdge) || " from next if, is u
785 if ((Walker->ListOfBonds.size() == 1)) { // only walk along DFS spanning tree (otherwise we always find SP of 1 being backedge Binder), but terminal hydrogens may be connected via backedge, hence extra check
786 OtherAtom = (*Runner)->GetOtherAtom(Walker);
787 //*out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
788 if (BFS.ColorList[OtherAtom->nr] == white) {
789 BFS.TouchedStack->Push(OtherAtom);
790 BFS.ColorList[OtherAtom->nr] = lightgray;
791 BFS.PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
792 BFS.ShortestPathList[OtherAtom->nr] = BFS.ShortestPathList[Walker->nr] + 1;
793 //*out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " lightgray, its predecessor is " << Walker->Name << " and its Shortest Path is " << ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl;
794 if (OtherAtom->GetTrueFather()->IsCyclic) { // if the other atom is connected to a ring
795 MinimumRingSize[Root->GetTrueFather()->nr] = BFS.ShortestPathList[OtherAtom->nr] + MinimumRingSize[OtherAtom->GetTrueFather()->nr];
796 OtherAtom = NULL; //break;
797 break;
798 } else
799 BFS.BFSStack->Push(OtherAtom);
800 } else {
801 //*out << Verbose(3) << "Not Adding, has already been visited." << endl;
802 }
803 } else {
804 //*out << Verbose(3) << "Not Visiting, is a back edge." << endl;
805 }
806 }
807 BFS.ColorList[Walker->nr] = black;
808 //*out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
809 }
810 //CleanAccountingLists(TouchedStack, PredecessorList, ShortestPathList, ColorList);
811
812 FinalizeBFSAccounting(out, BFS);
813}
814;
815
816/** All nodes that are not in cycles get assigned a \a *&MinimumRingSizeby BFS to next cycle.
817 * \param *out output stream for debugging
818 * \param *&MinimumRingSize array with minimum distance without encountering onself for each atom
819 * \param &MinRingSize global minium distance
820 * \param &NumCyles number of cycles in graph
821 * \param *mol molecule with atoms
822 */
823void CyclicStructureAnalysis_AssignRingSizetoNonCycleMembers(ofstream *out, int *&MinimumRingSize, int &MinRingSize, int &NumCycles, molecule *mol)
824{
825 atom *Root = NULL;
826 atom *Walker = NULL;
827 if (MinRingSize != -1) { // if rings are present
828 // go over all atoms
829 Root = mol->start;
830 while (Root->next != mol->end) {
831 Root = Root->next;
832
833 if (MinimumRingSize[Root->GetTrueFather()->nr] == mol->AtomCount) { // check whether MinimumRingSize is set, if not BFS to next where it is
834 Walker = Root;
835
836 //*out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
837 CyclicStructureAnalysis_BFSToNextCycle(out, Root, Walker, MinimumRingSize, mol->AtomCount);
838
839 }
840 *out << Verbose(1) << "Minimum ring size of " << *Root << " is " << MinimumRingSize[Root->GetTrueFather()->nr] << "." << endl;
841 }
842 *out << Verbose(1) << "Minimum ring size is " << MinRingSize << ", over " << NumCycles << " cycles total." << endl;
843 } else
844 *out << Verbose(1) << "No rings were detected in the molecular structure." << endl;
845}
846;
847
848/** Analyses the cycles found and returns minimum of all cycle lengths.
849 * We begin with a list of Back edges found during DepthFirstSearchAnalysis(). We go through this list - one end is the Root,
850 * the other our initial Walker - and do a Breadth First Search for the Root. We mark down each Predecessor and as soon as
851 * we have found the Root via BFS, we may climb back the closed cycle via the Predecessors. Thereby we mark atoms and bonds
852 * as cyclic and print out the cycles.
853 * \param *out output stream for debugging
854 * \param *BackEdgeStack stack with all back edges found during DFS scan. Beware: This stack contains the bonds from the total molecule, not from the subgraph!
855 * \param *&MinimumRingSize contains smallest ring size in molecular structure on return or -1 if no rings were found, if set is maximum search distance
856 * \todo BFS from the not-same-LP to find back to starting point of tributary cycle over more than one bond
857 */
858void molecule::CyclicStructureAnalysis(ofstream *out, class StackClass<bond *> * BackEdgeStack, int *&MinimumRingSize)
859{
860 struct BFSAccounting BFS;
861 atom *Walker = NULL;
862 atom *OtherAtom = NULL;
863 bond *BackEdge = NULL;
864 int NumCycles = 0;
865 int MinRingSize = -1;
866
867 InitializeBFSAccounting(out, BFS, AtomCount);
868
869 *out << Verbose(1) << "Back edge list - ";
870 BackEdgeStack->Output(out);
871
872 *out << Verbose(1) << "Analysing cycles ... " << endl;
873 NumCycles = 0;
874 while (!BackEdgeStack->IsEmpty()) {
875 BackEdge = BackEdgeStack->PopFirst();
876 // this is the target
877 BFS.Root = BackEdge->leftatom;
878 // this is the source point
879 Walker = BackEdge->rightatom;
880
881 ResetBFSAccounting(out, Walker, BFS);
882
883 *out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
884 OtherAtom = NULL;
885 CyclicStructureAnalysis_CyclicBFSFromRootToRoot(out, BackEdge, BFS);
886
887 CyclicStructureAnalysis_RetrieveCycleMembers(out, OtherAtom, BackEdge, BFS, MinimumRingSize, MinRingSize);
888
889 CleanBFSAccounting(out, BFS);
890 }
891 FinalizeBFSAccounting(out, BFS);
892
893 CyclicStructureAnalysis_AssignRingSizetoNonCycleMembers(out, MinimumRingSize, MinRingSize, NumCycles, this);
894
895}
896;
897
898/** Sets the next component number.
899 * This is O(N) as the number of bonds per atom is bound.
900 * \param *vertex atom whose next atom::*ComponentNr is to be set
901 * \param nr number to use
902 */
903void molecule::SetNextComponentNumber(atom *vertex, int nr)
904{
905 size_t i = 0;
906 if (vertex != NULL) {
907 for (; i < vertex->ListOfBonds.size(); i++) {
908 if (vertex->ComponentNr[i] == -1) { // check if not yet used
909 vertex->ComponentNr[i] = nr;
910 break;
911 } else if (vertex->ComponentNr[i] == nr) // if number is already present, don't add another time
912 break; // breaking here will not cause error!
913 }
914 if (i == vertex->ListOfBonds.size())
915 cerr << "Error: All Component entries are already occupied!" << endl;
916 } else
917 cerr << "Error: Given vertex is NULL!" << endl;
918}
919;
920
921/** Returns next unused bond for this atom \a *vertex or NULL of none exists.
922 * \param *vertex atom to regard
923 * \return bond class or NULL
924 */
925bond * molecule::FindNextUnused(atom *vertex)
926{
927 for (BondList::const_iterator Runner = vertex->ListOfBonds.begin(); Runner != vertex->ListOfBonds.end(); (++Runner))
928 if ((*Runner)->IsUsed() == white)
929 return ((*Runner));
930 return NULL;
931}
932;
933
934/** Resets bond::Used flag of all bonds in this molecule.
935 * \return true - success, false - -failure
936 */
937void molecule::ResetAllBondsToUnused()
938{
939 bond *Binder = first;
940 while (Binder->next != last) {
941 Binder = Binder->next;
942 Binder->ResetUsed();
943 }
944}
945;
946
947/** Output a list of flags, stating whether the bond was visited or not.
948 * \param *out output stream for debugging
949 * \param *list
950 */
951void OutputAlreadyVisited(ofstream *out, int *list)
952{
953 *out << Verbose(4) << "Already Visited Bonds:\t";
954 for (int i = 1; i <= list[0]; i++)
955 *out << Verbose(0) << list[i] << " ";
956 *out << endl;
957}
958;
959
960/** Storing the bond structure of a molecule to file.
961 * Simply stores Atom::nr and then the Atom::nr of all bond partners per line.
962 * \param *out output stream for debugging
963 * \param *path path to file
964 * \return true - file written successfully, false - writing failed
965 */
966bool molecule::StoreAdjacencyToFile(ofstream *out, char *path)
967{
968 ofstream AdjacencyFile;
969 stringstream line;
970 bool status = true;
971
972 line << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
973 AdjacencyFile.open(line.str().c_str(), ios::out);
974 *out << Verbose(1) << "Saving adjacency list ... ";
975 if (AdjacencyFile != NULL) {
976 ActOnAllAtoms(&atom::OutputAdjacency, &AdjacencyFile);
977 AdjacencyFile.close();
978 *out << Verbose(1) << "done." << endl;
979 } else {
980 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
981 status = false;
982 }
983
984 return status;
985}
986;
987
988bool CheckAdjacencyFileAgainstMolecule_Init(ofstream *out, char *path, ifstream &File, int *&CurrentBonds)
989{
990 stringstream filename;
991 filename << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
992 File.open(filename.str().c_str(), ios::out);
993 *out << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... ";
994 if (File == NULL)
995 return false;
996
997 // allocate storage structure
998 CurrentBonds = Malloc<int> (8, "molecule::CheckAdjacencyFileAgainstMolecule - CurrentBonds"); // contains parsed bonds of current atom
999 return true;
1000}
1001;
1002
1003void CheckAdjacencyFileAgainstMolecule_Finalize(ofstream *out, ifstream &File, int *&CurrentBonds)
1004{
1005 File.close();
1006 File.clear();
1007 Free(&CurrentBonds);
1008}
1009;
1010
1011void CheckAdjacencyFileAgainstMolecule_CompareBonds(ofstream *out, bool &status, int &NonMatchNumber, atom *&Walker, size_t &CurrentBondsOfAtom, int AtomNr, int *&CurrentBonds, atom **ListOfAtoms)
1012{
1013 size_t j = 0;
1014 int id = -1;
1015
1016 //*out << Verbose(2) << "Walker is " << *Walker << ", bond partners: ";
1017 if (CurrentBondsOfAtom == Walker->ListOfBonds.size()) {
1018 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
1019 id = (*Runner)->GetOtherAtom(Walker)->nr;
1020 j = 0;
1021 for (; (j < CurrentBondsOfAtom) && (CurrentBonds[j++] != id);)
1022 ; // check against all parsed bonds
1023 if (CurrentBonds[j - 1] != id) { // no match ? Then mark in ListOfAtoms
1024 ListOfAtoms[AtomNr] = NULL;
1025 NonMatchNumber++;
1026 status = false;
1027 //*out << "[" << id << "]\t";
1028 } else {
1029 //*out << id << "\t";
1030 }
1031 }
1032 //*out << endl;
1033 } else {
1034 *out << "Number of bonds for Atom " << *Walker << " does not match, parsed " << CurrentBondsOfAtom << " against " << Walker->ListOfBonds.size() << "." << endl;
1035 status = false;
1036 }
1037}
1038;
1039
1040/** Checks contents of adjacency file against bond structure in structure molecule.
1041 * \param *out output stream for debugging
1042 * \param *path path to file
1043 * \param **ListOfAtoms allocated (molecule::AtomCount) and filled lookup table for ids (Atom::nr) to *Atom
1044 * \return true - structure is equal, false - not equivalence
1045 */
1046bool molecule::CheckAdjacencyFileAgainstMolecule(ofstream *out, char *path, atom **ListOfAtoms)
1047{
1048 ifstream File;
1049 bool status = true;
1050 atom *Walker = NULL;
1051 char *buffer = NULL;
1052 int *CurrentBonds = NULL;
1053 int NonMatchNumber = 0; // will number of atoms with differing bond structure
1054 size_t CurrentBondsOfAtom = -1;
1055
1056 if (!CheckAdjacencyFileAgainstMolecule_Init(out, path, File, CurrentBonds)) {
1057 *out << Verbose(1) << "Adjacency file not found." << endl;
1058 return true;
1059 }
1060
1061 buffer = Malloc<char> (MAXSTRINGSIZE, "molecule::CheckAdjacencyFileAgainstMolecule: *buffer");
1062 // Parse the file line by line and count the bonds
1063 while (!File.eof()) {
1064 File.getline(buffer, MAXSTRINGSIZE);
1065 stringstream line;
1066 line.str(buffer);
1067 int AtomNr = -1;
1068 line >> AtomNr;
1069 CurrentBondsOfAtom = -1; // we count one too far due to line end
1070 // parse into structure
1071 if ((AtomNr >= 0) && (AtomNr < AtomCount)) {
1072 Walker = ListOfAtoms[AtomNr];
1073 while (!line.eof())
1074 line >> CurrentBonds[++CurrentBondsOfAtom];
1075 // compare against present bonds
1076 CheckAdjacencyFileAgainstMolecule_CompareBonds(out, status, NonMatchNumber, Walker, CurrentBondsOfAtom, AtomNr, CurrentBonds, ListOfAtoms);
1077 }
1078 }
1079 Free(&buffer);
1080 CheckAdjacencyFileAgainstMolecule_Finalize(out, File, CurrentBonds);
1081
1082 if (status) { // if equal we parse the KeySetFile
1083 *out << Verbose(1) << "done: Equal." << endl;
1084 } else
1085 *out << Verbose(1) << "done: Not equal by " << NonMatchNumber << " atoms." << endl;
1086 return status;
1087}
1088;
1089
1090/** Picks from a global stack with all back edges the ones in the fragment.
1091 * \param *out output stream for debugging
1092 * \param **ListOfLocalAtoms array of father atom::nr to local atom::nr (reverse of atom::father)
1093 * \param *ReferenceStack stack with all the back egdes
1094 * \param *LocalStack stack to be filled
1095 * \return true - everything ok, false - ReferenceStack was empty
1096 */
1097bool molecule::PickLocalBackEdges(ofstream *out, atom **ListOfLocalAtoms, class StackClass<bond *> *&ReferenceStack, class StackClass<bond *> *&LocalStack)
1098{
1099 bool status = true;
1100 if (ReferenceStack->IsEmpty()) {
1101 cerr << "ReferenceStack is empty!" << endl;
1102 return false;
1103 }
1104 bond *Binder = ReferenceStack->PopFirst();
1105 bond *FirstBond = Binder; // mark the first bond, so that we don't loop through the stack indefinitely
1106 atom *Walker = NULL, *OtherAtom = NULL;
1107 ReferenceStack->Push(Binder);
1108
1109 do { // go through all bonds and push local ones
1110 Walker = ListOfLocalAtoms[Binder->leftatom->nr]; // get one atom in the reference molecule
1111 if (Walker != NULL) // if this Walker exists in the subgraph ...
1112 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
1113 OtherAtom = (*Runner)->GetOtherAtom(Walker);
1114 if (OtherAtom == ListOfLocalAtoms[(*Runner)->rightatom->nr]) { // found the bond
1115 LocalStack->Push((*Runner));
1116 *out << Verbose(3) << "Found local edge " << *(*Runner) << "." << endl;
1117 break;
1118 }
1119 }
1120 Binder = ReferenceStack->PopFirst(); // loop the stack for next item
1121 *out << Verbose(3) << "Current candidate edge " << Binder << "." << endl;
1122 ReferenceStack->Push(Binder);
1123 } while (FirstBond != Binder);
1124
1125 return status;
1126}
1127;
1128
1129void BreadthFirstSearchAdd_Init(struct BFSAccounting &BFS, atom *&Root, int AtomCount, int BondOrder, atom **AddedAtomList = NULL)
1130{
1131 BFS.AtomCount = AtomCount;
1132 BFS.BondOrder = BondOrder;
1133 BFS.PredecessorList = Malloc<atom*> (AtomCount, "molecule::BreadthFirstSearchAdd_Init: **PredecessorList");
1134 BFS.ShortestPathList = Malloc<int> (AtomCount, "molecule::BreadthFirstSearchAdd_Init: *ShortestPathList");
1135 BFS.ColorList = Malloc<enum Shading> (AtomCount, "molecule::BreadthFirstSearchAdd_Init: *ColorList");
1136 BFS.BFSStack = new StackClass<atom *> (AtomCount);
1137
1138 BFS.Root = Root;
1139 BFS.BFSStack->ClearStack();
1140 BFS.BFSStack->Push(Root);
1141
1142 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray
1143 for (int i = AtomCount; i--;) {
1144 BFS.PredecessorList[i] = NULL;
1145 BFS.ShortestPathList[i] = -1;
1146 if ((AddedAtomList != NULL) && (AddedAtomList[i] != NULL)) // mark already present atoms (i.e. Root and maybe others) as visited
1147 BFS.ColorList[i] = lightgray;
1148 else
1149 BFS.ColorList[i] = white;
1150 }
1151 BFS.ShortestPathList[Root->nr] = 0;
1152}
1153;
1154
1155void BreadthFirstSearchAdd_Free(struct BFSAccounting &BFS)
1156{
1157 Free(&BFS.PredecessorList);
1158 Free(&BFS.ShortestPathList);
1159 Free(&BFS.ColorList);
1160 delete (BFS.BFSStack);
1161 BFS.AtomCount = 0;
1162}
1163;
1164
1165void BreadthFirstSearchAdd_UnvisitedNode(ofstream *out, molecule *Mol, struct BFSAccounting &BFS, atom *&Walker, atom *&OtherAtom, bond *&Binder, bond *&Bond, atom **&AddedAtomList, bond **&AddedBondList, bool IsAngstroem)
1166{
1167 if (Binder != Bond) // let other atom white if it's via Root bond. In case it's cyclic it has to be reached again (yet Root is from OtherAtom already black, thus no problem)
1168 BFS.ColorList[OtherAtom->nr] = lightgray;
1169 BFS.PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
1170 BFS.ShortestPathList[OtherAtom->nr] = BFS.ShortestPathList[Walker->nr] + 1;
1171 *out << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " " << ((BFS.ColorList[OtherAtom->nr] == white) ? "white" : "lightgray") << ", its predecessor is " << Walker->Name << " and its Shortest Path is " << BFS.ShortestPathList[OtherAtom->nr] << " egde(s) long." << endl;
1172 if ((((BFS.ShortestPathList[OtherAtom->nr] < BFS.BondOrder) && (Binder != Bond)))) { // Check for maximum distance
1173 *out << Verbose(3);
1174 if (AddedAtomList[OtherAtom->nr] == NULL) { // add if it's not been so far
1175 AddedAtomList[OtherAtom->nr] = Mol->AddCopyAtom(OtherAtom);
1176 *out << "Added OtherAtom " << OtherAtom->Name;
1177 AddedBondList[Binder->nr] = Mol->CopyBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder);
1178 *out << " and bond " << *(AddedBondList[Binder->nr]) << ", ";
1179 } else { // this code should actually never come into play (all white atoms are not yet present in BondMolecule, that's why they are white in the first place)
1180 *out << "Not adding OtherAtom " << OtherAtom->Name;
1181 if (AddedBondList[Binder->nr] == NULL) {
1182 AddedBondList[Binder->nr] = Mol->CopyBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder);
1183 *out << ", added Bond " << *(AddedBondList[Binder->nr]);
1184 } else
1185 *out << ", not added Bond ";
1186 }
1187 *out << ", putting OtherAtom into queue." << endl;
1188 BFS.BFSStack->Push(OtherAtom);
1189 } else { // out of bond order, then replace
1190 if ((AddedAtomList[OtherAtom->nr] == NULL) && (Binder->Cyclic))
1191 BFS.ColorList[OtherAtom->nr] = white; // unmark if it has not been queued/added, to make it available via its other bonds (cyclic)
1192 if (Binder == Bond)
1193 *out << Verbose(3) << "Not Queueing, is the Root bond";
1194 else if (BFS.ShortestPathList[OtherAtom->nr] >= BFS.BondOrder)
1195 *out << Verbose(3) << "Not Queueing, is out of Bond Count of " << BFS.BondOrder;
1196 if (!Binder->Cyclic)
1197 *out << ", is not part of a cyclic bond, saturating bond with Hydrogen." << endl;
1198 if (AddedBondList[Binder->nr] == NULL) {
1199 if ((AddedAtomList[OtherAtom->nr] != NULL)) { // .. whether we add or saturate
1200 AddedBondList[Binder->nr] = Mol->CopyBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder);
1201 } else {
1202#ifdef ADDHYDROGEN
1203 if (!Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, IsAngstroem))
1204 exit(1);
1205#endif
1206 }
1207 }
1208 }
1209}
1210;
1211
1212void BreadthFirstSearchAdd_VisitedNode(ofstream *out, molecule *Mol, struct BFSAccounting &BFS, atom *&Walker, atom *&OtherAtom, bond *&Binder, bond *&Bond, atom **&AddedAtomList, bond **&AddedBondList, bool IsAngstroem)
1213{
1214 *out << Verbose(3) << "Not Adding, has already been visited." << endl;
1215 // This has to be a cyclic bond, check whether it's present ...
1216 if (AddedBondList[Binder->nr] == NULL) {
1217 if ((Binder != Bond) && (Binder->Cyclic) && (((BFS.ShortestPathList[Walker->nr] + 1) < BFS.BondOrder))) {
1218 AddedBondList[Binder->nr] = Mol->CopyBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder);
1219 } else { // if it's root bond it has to broken (otherwise we would not create the fragments)
1220#ifdef ADDHYDROGEN
1221 if(!Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, IsAngstroem))
1222 exit(1);
1223#endif
1224 }
1225 }
1226}
1227;
1228
1229/** Adds atoms up to \a BondCount distance from \a *Root and notes them down in \a **AddedAtomList.
1230 * Gray vertices are always enqueued in an StackClass<atom *> FIFO queue, the rest is usual BFS with adding vertices found was
1231 * white and putting into queue.
1232 * \param *out output stream for debugging
1233 * \param *Mol Molecule class to add atoms to
1234 * \param **AddedAtomList list with added atom pointers, index is atom father's number
1235 * \param **AddedBondList list with added bond pointers, index is bond father's number
1236 * \param *Root root vertex for BFS
1237 * \param *Bond bond not to look beyond
1238 * \param BondOrder maximum distance for vertices to add
1239 * \param IsAngstroem lengths are in angstroem or bohrradii
1240 */
1241void molecule::BreadthFirstSearchAdd(ofstream *out, molecule *Mol, atom **&AddedAtomList, bond **&AddedBondList, atom *Root, bond *Bond, int BondOrder, bool IsAngstroem)
1242{
1243 struct BFSAccounting BFS;
1244 atom *Walker = NULL, *OtherAtom = NULL;
1245 bond *Binder = NULL;
1246
1247 // add Root if not done yet
1248 if (AddedAtomList[Root->nr] == NULL) // add Root if not yet present
1249 AddedAtomList[Root->nr] = Mol->AddCopyAtom(Root);
1250
1251 BreadthFirstSearchAdd_Init(BFS, Root, BondOrder, AtomCount, AddedAtomList);
1252
1253 // and go on ... Queue always contains all lightgray vertices
1254 while (!BFS.BFSStack->IsEmpty()) {
1255 // we have to pop the oldest atom from stack. This keeps the atoms on the stack always of the same ShortestPath distance.
1256 // e.g. if current atom is 2, push to end of stack are of length 3, but first all of length 2 would be popped. They again
1257 // append length of 3 (their neighbours). Thus on stack we have always atoms of a certain length n at bottom of stack and
1258 // followed by n+1 till top of stack.
1259 Walker = BFS.BFSStack->PopFirst(); // pop oldest added
1260 *out << Verbose(1) << "Current Walker is: " << Walker->Name << ", and has " << Walker->ListOfBonds.size() << " bonds." << endl;
1261 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
1262 if ((*Runner) != NULL) { // don't look at bond equal NULL
1263 Binder = (*Runner);
1264 OtherAtom = (*Runner)->GetOtherAtom(Walker);
1265 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *(*Runner) << "." << endl;
1266 if (BFS.ColorList[OtherAtom->nr] == white) {
1267 BreadthFirstSearchAdd_UnvisitedNode(out, Mol, BFS, Walker, OtherAtom, Binder, Bond, AddedAtomList, AddedBondList, IsAngstroem);
1268 } else {
1269 BreadthFirstSearchAdd_VisitedNode(out, Mol, BFS, Walker, OtherAtom, Binder, Bond, AddedAtomList, AddedBondList, IsAngstroem);
1270 }
1271 }
1272 }
1273 BFS.ColorList[Walker->nr] = black;
1274 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
1275 }
1276 BreadthFirstSearchAdd_Free(BFS);
1277}
1278;
1279
1280/** Adds a bond as a copy to a given one
1281 * \param *left leftatom of new bond
1282 * \param *right rightatom of new bond
1283 * \param *CopyBond rest of fields in bond are copied from this
1284 * \return pointer to new bond
1285 */
1286bond * molecule::CopyBond(atom *left, atom *right, bond *CopyBond)
1287{
1288 bond *Binder = AddBond(left, right, CopyBond->BondDegree);
1289 Binder->Cyclic = CopyBond->Cyclic;
1290 Binder->Type = CopyBond->Type;
1291 return Binder;
1292}
1293;
1294
1295void BuildInducedSubgraph_Init(ofstream *out, atom **&ParentList, int AtomCount)
1296{
1297 // reset parent list
1298 ParentList = Malloc<atom*> (AtomCount, "molecule::BuildInducedSubgraph_Init: **ParentList");
1299 *out << Verbose(3) << "Resetting ParentList." << endl;
1300 for (int i = AtomCount; i--;)
1301 ParentList[i] = NULL;
1302}
1303;
1304
1305void BuildInducedSubgraph_FillParentList(ofstream *out, const molecule *mol, const molecule *Father, atom **&ParentList)
1306{
1307 // fill parent list with sons
1308 *out << Verbose(3) << "Filling Parent List." << endl;
1309 atom *Walker = mol->start;
1310 while (Walker->next != mol->end) {
1311 Walker = Walker->next;
1312 ParentList[Walker->father->nr] = Walker;
1313 // Outputting List for debugging
1314 *out << Verbose(4) << "Son[" << Walker->father->nr << "] of " << Walker->father << " is " << ParentList[Walker->father->nr] << "." << endl;
1315 }
1316
1317}
1318;
1319
1320void BuildInducedSubgraph_Finalize(ofstream *out, atom **&ParentList)
1321{
1322 Free(&ParentList);
1323}
1324;
1325
1326bool BuildInducedSubgraph_CreateBondsFromParent(ofstream *out, molecule *mol, const molecule *Father, atom **&ParentList)
1327{
1328 bool status = true;
1329 atom *Walker = NULL;
1330 atom *OtherAtom = NULL;
1331 // check each entry of parent list and if ok (one-to-and-onto matching) create bonds
1332 *out << Verbose(3) << "Creating bonds." << endl;
1333 Walker = Father->start;
1334 while (Walker->next != Father->end) {
1335 Walker = Walker->next;
1336 if (ParentList[Walker->nr] != NULL) {
1337 if (ParentList[Walker->nr]->father != Walker) {
1338 status = false;
1339 } else {
1340 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
1341 OtherAtom = (*Runner)->GetOtherAtom(Walker);
1342 if (ParentList[OtherAtom->nr] != NULL) { // if otheratom is also a father of an atom on this molecule, create the bond
1343 *out << Verbose(4) << "Endpoints of Bond " << (*Runner) << " are both present: " << ParentList[Walker->nr]->Name << " and " << ParentList[OtherAtom->nr]->Name << "." << endl;
1344 mol->AddBond(ParentList[Walker->nr], ParentList[OtherAtom->nr], (*Runner)->BondDegree);
1345 }
1346 }
1347 }
1348 }
1349 }
1350 return status;
1351}
1352;
1353
1354/** Adds bond structure to this molecule from \a Father molecule.
1355 * This basically causes this molecule to become an induced subgraph of the \a Father, i.e. for every bond in Father
1356 * with end points present in this molecule, bond is created in this molecule.
1357 * Special care was taken to ensure that this is of complexity O(N), where N is the \a Father's molecule::AtomCount.
1358 * \param *out output stream for debugging
1359 * \param *Father father molecule
1360 * \return true - is induced subgraph, false - there are atoms with fathers not in \a Father
1361 * \todo not checked, not fully working probably
1362 */
1363bool molecule::BuildInducedSubgraph(ofstream *out, const molecule *Father)
1364{
1365 bool status = true;
1366 atom **ParentList = NULL;
1367
1368 *out << Verbose(2) << "Begin of BuildInducedSubgraph." << endl;
1369 BuildInducedSubgraph_Init(out, ParentList, Father->AtomCount);
1370 BuildInducedSubgraph_FillParentList(out, this, Father, ParentList);
1371 status = BuildInducedSubgraph_CreateBondsFromParent(out, this, Father, ParentList);
1372 BuildInducedSubgraph_Finalize(out, ParentList);
1373 *out << Verbose(2) << "End of BuildInducedSubgraph." << endl;
1374 return status;
1375}
1376;
1377
1378/** For a given keyset \a *Fragment, checks whether it is connected in the current molecule.
1379 * \param *out output stream for debugging
1380 * \param *Fragment Keyset of fragment's vertices
1381 * \return true - connected, false - disconnected
1382 * \note this is O(n^2) for it's just a bug checker not meant for permanent use!
1383 */
1384bool molecule::CheckForConnectedSubgraph(ofstream *out, KeySet *Fragment)
1385{
1386 atom *Walker = NULL, *Walker2 = NULL;
1387 bool BondStatus = false;
1388 int size;
1389
1390 *out << Verbose(1) << "Begin of CheckForConnectedSubgraph" << endl;
1391 *out << Verbose(2) << "Disconnected atom: ";
1392
1393 // count number of atoms in graph
1394 size = 0;
1395 for (KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++)
1396 size++;
1397 if (size > 1)
1398 for (KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++) {
1399 Walker = FindAtom(*runner);
1400 BondStatus = false;
1401 for (KeySet::iterator runners = Fragment->begin(); runners != Fragment->end(); runners++) {
1402 Walker2 = FindAtom(*runners);
1403 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
1404 if ((*Runner)->GetOtherAtom(Walker) == Walker2) {
1405 BondStatus = true;
1406 break;
1407 }
1408 if (BondStatus)
1409 break;
1410 }
1411 }
1412 if (!BondStatus) {
1413 *out << (*Walker) << endl;
1414 return false;
1415 }
1416 }
1417 else {
1418 *out << "none." << endl;
1419 return true;
1420 }
1421 *out << "none." << endl;
1422
1423 *out << Verbose(1) << "End of CheckForConnectedSubgraph" << endl;
1424
1425 return true;
1426}
Note: See TracBrowser for help on using the repository browser.