source: src/molecule_graph.cpp@ 3738f0

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 Candidate_v1.7.0 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 3738f0 was 3738f0, checked in by Frederik Heber <heber@…>, 15 years ago

Moved molecule::CreateAdjacencyList over to class BondGraph.

to make this possible we had to:

other changes:

TESTFIXES:

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