source: src/molecule_graph.cpp@ 1363de

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 1363de was 129204, checked in by Frederik Heber <heber@…>, 14 years ago

Moved bond.* to Bond/, new class GraphEdge which contains graph parts of bond.

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