source: src/molecule_graph.cpp@ 273382

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 273382 was 273382, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Prepared interface of Vector Class for transition to VectorComposites

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