source: src/Fragmentation/PowerSetGenerator.cpp@ 4464ef

Action_Thermostats Add_AtomRandomPerturbation Add_RotateAroundBondAction Add_SelectAtomByNameAction Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_StructOpt_integration_tests Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_ChronosMutex Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion GeometryObjects Gui_displays_atomic_force_velocity IndependentFragmentGrids_IntegrationTest JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks RotateToPrincipalAxisSystem_UndoRedo StoppableMakroAction Subpackage_levmar Subpackage_vmg ThirdParty_MPQC_rebuilt_buildsystem TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps Ubuntu_1604_changes stable
Last change on this file since 4464ef was e23fec, checked in by Frederik Heber <heber@…>, 10 years ago

Renamed Bond::Contains to Bond::ContainsNr() and added ::ContainsId().

  • I just stumbled over this, trying to recreate bonds from removed atoms and Contains looks for the Nr not the Id ...
  • Property mode set to 100644
File size: 14.6 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
5 * Copyright (C) 2013 Frederik Heber. All rights reserved.
6 *
7 *
8 * This file is part of MoleCuilder.
9 *
10 * MoleCuilder is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * MoleCuilder is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/*
25 * PowerSetGenerator.cpp
26 *
27 * Created on: Oct 18, 2011
28 * Author: heber
29 */
30
31// include config.h
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35
36#include "CodePatterns/MemDebug.hpp"
37
38#include "PowerSetGenerator.hpp"
39
40#include <sstream>
41
42#include "CodePatterns/Info.hpp"
43#include "CodePatterns/Log.hpp"
44
45#include "Atom/atom.hpp"
46#include "Bond/bond.hpp"
47#include "Fragmentation/KeySet.hpp"
48#include "Fragmentation/UniqueFragments.hpp"
49
50/** Constructor of class PowerSetGenerator.
51 *
52 */
53PowerSetGenerator::PowerSetGenerator(UniqueFragments *_FragmentSearch, int _Order) :
54 BondsPerSPList(_Order),
55 FragmentSearch(_FragmentSearch)
56{}
57
58/** Destructor of class PowerSetGenerator.
59 *
60 */
61PowerSetGenerator::~PowerSetGenerator()
62{
63 FragmentSearch = NULL;
64}
65
66/** Clears the touched list
67 * \param verbosity verbosity level
68 * \param &TouchedList touched list
69 * \param SubOrder current suborder
70 * \param TouchedIndex currently touched
71 */
72void PowerSetGenerator::ClearingTouched(int verbosity, TouchedList_t &TouchedList, int SubOrder, int &TouchedIndex)
73{
74 LOG(1+verbosity, "Clearing touched list.");
75 TouchedList.resize(SubOrder+1, -1);
76 for (TouchedIndex=SubOrder+1;TouchedIndex--;) // empty touched list
77 TouchedList[TouchedIndex] = -1;
78 TouchedIndex = 0;
79}
80
81/** Adds the current combination of the power set to the snake stack.
82 * \param verbosity verbosity level
83 * \param CurrentCombination
84 * \param SetDimension maximum number of bits in power set
85 * \param *FragmentSet snake stack to remove from
86 * \param &BondsSet set of bonds
87 * \param &TouchedList touched list
88 * \param TouchedIndex currently touched
89 * \return number of set bits
90 */
91int PowerSetGenerator::AddPowersetToSnakeStack(int verbosity, int CurrentCombination, int SetDimension, KeySet *FragmentSet, std::vector<bond::ptr > &BondsSet, TouchedList_t &TouchedList, int &TouchedIndex)
92{
93 atom *OtherWalker = NULL;
94 bool bit = false;
95 KeySetTestPair TestKeySetInsert;
96
97 int Added = 0;
98 for (int j=0;j<SetDimension;j++) { // pull out every bit by shifting
99 bit = ((CurrentCombination & (1 << j)) != 0); // mask the bit for the j-th bond
100 if (bit) { // if bit is set, we add this bond partner
101 OtherWalker = BondsSet[j]->rightatom; // rightatom is always the one more distant, i.e. the one to add
102 //LOG(1+verbosity, "Current Bond is " << BondsSet[j] << ", checking on " << *OtherWalker << ".");
103 LOG(2+verbosity, "Adding " << *OtherWalker << " with nr " << OtherWalker->getNr() << ".");
104 TestKeySetInsert = FragmentSet->insert(OtherWalker->getNr());
105 if (TestKeySetInsert.second) {
106 TouchedList[TouchedIndex++] = OtherWalker->getNr(); // note as added
107 Added++;
108 } else {
109 LOG(2+verbosity, "This was item was already present in the keyset.");
110 }
111 } else {
112 LOG(2+verbosity, "Not adding.");
113 }
114 }
115 return Added;
116};
117
118/** Counts the number of elements in a power set.
119 * \param SetFirst begin iterator first bond
120 * \param SetLast end iterator
121 * \param &TouchedList touched list
122 * \param TouchedIndex currently touched
123 * \return number of elements
124 */
125int PowerSetGenerator::CountSetMembers(std::list<bond::ptr >::const_iterator SetFirst, std::list<bond::ptr >::const_iterator SetLast, const TouchedList_t &TouchedList, int TouchedIndex)
126{
127 int SetDimension = 0;
128 for( std::list<bond::ptr >::const_iterator Binder = SetFirst;
129 Binder != SetLast;
130 ++Binder) {
131 for (TouchedList_t::const_iterator iter = TouchedList.begin();
132 iter != TouchedList.end(); ++iter) {
133 if ((*Binder)->ContainsNr(*iter)) // if we added this very endpiece
134 SetDimension++;
135 }
136 }
137 return SetDimension;
138};
139
140/** Fills a list of bonds from another
141 * \param *BondsList bonds array/vector to fill
142 * \param SetFirst begin iterator first bond
143 * \param SetLast end iterator
144 * \param &TouchedList touched list
145 * \param TouchedIndex currently touched
146 * \return number of elements
147 */
148int PowerSetGenerator::FillBondsList(std::vector<bond::ptr > &BondsList, std::list<bond::ptr >::const_iterator SetFirst, std::list<bond::ptr >::const_iterator SetLast, const TouchedList_t &TouchedList, int TouchedIndex)
149{
150 int SetDimension = 0;
151 for( std::list<bond::ptr >::const_iterator Binder = SetFirst;
152 Binder != SetLast;
153 ++Binder) {
154 for (TouchedList_t::const_iterator iter = TouchedList.begin();
155 iter != TouchedList.end(); ++iter) {
156 if ((*Binder)->leftatom->getNr() == *iter) // leftatom is always the closer one
157 BondsList[SetDimension++] = (*Binder);
158 }
159 }
160 return SetDimension;
161};
162
163/** Remove all items that were added on this SP level.
164 * \param verbosity verbosity level
165 * \param *FragmentSet snake stack to remove from
166 * \param &TouchedList touched list
167 * \param TouchedIndex currently touched
168 */
169void PowerSetGenerator::RemoveAllTouchedFromSnakeStack(int verbosity, KeySet *FragmentSet, TouchedList_t &TouchedList, int &TouchedIndex)
170{
171 for (TouchedList_t::iterator iter = TouchedList.begin();
172 iter != TouchedList.end();++iter) {
173 const int Removal = *iter;
174 LOG(2+verbosity, "Removing item nr. " << Removal << " from snake stack.");
175 FragmentSet->erase(Removal);
176 (*iter) = -1;
177 }
178 std::stringstream output;
179 output << "Remaining local nr.s on snake stack are: ";
180 for(KeySet::iterator runner = FragmentSet->begin(); runner != FragmentSet->end(); runner++)
181 output << (*runner) << " ";
182 LOG(2, output.str());
183 TouchedIndex = 0; // set Index to 0 for list of atoms added on this level
184};
185
186
187/** Creates a list of all unique fragments of certain vertex size from a given graph \a Fragment for a given root vertex in the context of \a this molecule.
188 * -# initialises UniqueFragments structure
189 * -# fills edge list via BFS
190 * -# creates the fragment by calling recursive function SPFragmentGenerator with UniqueFragments structure, 0 as
191 root distance, the edge set, its dimension and the current suborder
192 * -# Free'ing structure
193 * Note that we may use the fact that the atoms are SP-ordered on the atomstack. I.e. when popping always the last, we first get all
194 * with SP of 2, then those with SP of 3, then those with SP of 4 and so on.
195 * \param RestrictedKeySet Restricted vertex set to use in context of molecule
196 * \param treatment whether to treat hydrogen special or not
197 * \return number of inserted fragments
198 * \note ShortestPathList in FragmentSearch structure is probably due to NumberOfAtomsSPLevel and SP not needed anymore
199 */
200int PowerSetGenerator::operator()(KeySet &RestrictedKeySet, const enum HydrogenTreatment treatment)
201{
202 int Counter = FragmentSearch->FragmentCounter; // mark current value of counter
203
204 LOG(0, std::endl);
205 LOG(0, "Begin of PowerSetGenerator with order " << BondsPerSPList.getOrder() << " at Root " << *FragmentSearch->getRoot() << ".");
206
207 BondsPerSPList.SetSPList(FragmentSearch->getRoot());
208
209 // do a BFS search to fill the SP lists and label the found vertices
210 BondsPerSPList.FillSPListandLabelVertices(FragmentSearch->getRoot()->GetTrueFather()->getNr(), RestrictedKeySet, treatment);
211
212 // outputting all list for debugging
213 BondsPerSPList.OutputSPList();
214
215 // creating fragments with the found edge sets (may be done in reverse order, faster)
216 int SP = BondsPerSPList.CountNumbersInBondsList();
217 LOG(0, "INFO: Total number of edges is " << SP << ".");
218 {
219 // start with root (push on fragment stack)
220 LOG(0, "Starting fragment generation with " << *FragmentSearch->getRoot() << ", local nr is " << FragmentSearch->getRoot()->getNr() << ".");
221 FragmentSearch->FragmentSet->clear();
222 LOG(0, "Preparing subset for this root and calling generator.");
223
224 // prepare the subset and call the generator
225 std::vector<bond::ptr> BondsList;
226 BondsList.resize(BondsPerSPList.BondsPerSPCount[0]);
227 ASSERT(BondsPerSPList.BondsPerSPList[0].size() != 0,
228 "molecule::PowerSetGenerator() - BondsPerSPList.BondsPerSPList[0] contains no root bond.");
229 BondsList[0] = (*BondsPerSPList.BondsPerSPList[0].begin()); // on SP level 0 there's only the root bond
230
231 SPFragmentGenerator(0, BondsList, BondsPerSPList.BondsPerSPCount[0], BondsPerSPList.getOrder());
232 }
233
234 // as FragmentSearch structure is used only once, we don't have to clean it anymore
235 // remove root from stack
236 LOG(0, "Removing root again from stack.");
237 FragmentSearch->FragmentSet->erase(FragmentSearch->getRoot()->getNr());
238
239 // free'ing the bonds lists
240 BondsPerSPList.ResetSPList();
241
242 // return list
243 LOG(0, "End of PowerSetGenerator.");
244 return (FragmentSearch->FragmentCounter - Counter);
245};
246
247/** From a given set of Bond sorted by Shortest Path distance, create all possible fragments of size \a SetDimension.
248 * -# loops over every possible combination (2^dimension of edge set)
249 * -# inserts current set, if there's still space left
250 * -# yes: calls SPFragmentGenerator with structure, created new edge list and size respective to root dist
251ance+1
252 * -# no: stores fragment into keyset list by calling InsertFragmentIntoGraph
253 * -# removes all items added into the snake stack (in UniqueFragments structure) added during level (root
254distance) and current set
255 * \param RootDistance current shortest path level, whose set of edges is represented by **BondsSet
256 * \param BondsSet array of bonds to check
257 * \param SetDimension Number of possible bonds on this level (i.e. size of the array BondsSet[])
258 * \param SubOrder remaining number of allowed vertices to add
259 */
260void PowerSetGenerator::SPFragmentGenerator(int RootDistance, std::vector<bond::ptr > &BondsSet, int SetDimension, int SubOrder)
261{
262 Info info(__func__);
263 int verbosity = 0; //FragmentSearch->ANOVAOrder-SubOrder;
264 int TouchedIndex, SubSetDimension, Added;
265 int SpaceLeft;
266 TouchedList_t TouchedList(SubOrder + 1, -1);
267 KeySetTestPair TestKeySetInsert;
268
269 const int NumCombinations = 1 << SetDimension;
270
271 // here for all bonds of Walker all combinations of end pieces (from the bonds)
272 // have to be added and for the remaining ANOVA order GraphCrawler be called
273 // recursively for the next level
274
275 LOG(1+verbosity, "We are " << RootDistance << " away from Root, which is " << *FragmentSearch->getRoot() << ", SubOrder is " << SubOrder << ", SetDimension is " << SetDimension << " and this means " << NumCombinations-1 << " combination(s).");
276
277 // initialised touched list (stores added atoms on this level)
278 ClearingTouched(verbosity, TouchedList, SubOrder, TouchedIndex);
279
280 // create every possible combination of the endpieces
281 LOG(1+verbosity, "Going through all combinations of the power set.");
282 for (int i=1;i<NumCombinations;i++) { // sweep through all power set combinations (skip empty set!)
283 // count the set bit of i
284 const int bits = countBits(i, SetDimension);
285
286 LOG(1+verbosity, "Current set is " << Binary(i | (1 << SetDimension)) << ", number of bits is " << bits << ".");
287 if (bits <= SubOrder) { // if not greater than additional atoms allowed on stack, continue
288 // --1-- add this set of the power set of bond partners to the snake stack
289 Added = AddPowersetToSnakeStack(verbosity, i, SetDimension, FragmentSearch->FragmentSet, BondsSet, TouchedList, TouchedIndex);
290
291 // --2-- store the fragment
292 const int order = BondsPerSPList.getOrder() - SubOrder + Added - 1;
293 LOG(1+verbosity, "Storing fragment as order " << order << ".");
294 // store fragment as a KeySet
295 if (DoLog(2)) {
296 std::stringstream output;
297 output << "Found a new fragment[" << FragmentSearch->FragmentCounter << "], local nr.s are: ";
298 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
299 output << (*runner) << " ";
300 LOG(2, output.str());
301 }
302 FragmentSearch->InsertFragmentIntoGraph(order);
303
304 // --3-- if below SubOrder still, recurse
305 SpaceLeft = SubOrder - Added ;// SubOrder - bits; // due to item's maybe being already present, this does not work anymore
306 if ((SpaceLeft > 0) && (RootDistance < BondsPerSPList.getOrder())) {
307 LOG(1+verbosity, "There's still some space left on stack: " << SpaceLeft << ".");
308 if (SubOrder > 1) { // Due to Added above we have to check extra whether we're not already reaching beyond the desired Order
309 // --2-- look at all added end pieces of this combination, construct bond subsets and sweep through a power set of these by recursion
310 const int SP = RootDistance+1; // this is the next level
311
312 // first count the members in the subset
313 SubSetDimension = CountSetMembers(BondsPerSPList.BondsPerSPList[SP].begin(), BondsPerSPList.BondsPerSPList[SP].end(), TouchedList, TouchedIndex);
314
315 // then allocate and fill the list
316 std::vector<bond::ptr > BondsList;
317 BondsList.resize(SubSetDimension);
318 SubSetDimension = FillBondsList(BondsList, BondsPerSPList.BondsPerSPList[SP].begin(), BondsPerSPList.BondsPerSPList[SP].end(), TouchedList, TouchedIndex);
319
320 // then iterate
321 LOG(2+verbosity, "Calling subset generator " << SP << " away from root " << *FragmentSearch->getRoot() << " with sub set dimension " << SubSetDimension << ".");
322 SPFragmentGenerator(SP, BondsList, SubSetDimension, SubOrder-bits);
323 }
324 } else {
325 LOG(1+verbosity, "No more space or no shortest path levels, not recursing.");
326 }
327
328 // --3-- remove all added items in this level from snake stack
329 LOG(1+verbosity, "Removing all items that were added on this SP level " << RootDistance << ".");
330 RemoveAllTouchedFromSnakeStack(verbosity, FragmentSearch->FragmentSet, TouchedList, TouchedIndex);
331 } else {
332 LOG(2+verbosity, "More atoms to add for this set (" << bits << ") than space left on stack " << SubOrder << ", skipping this set.");
333 }
334 }
335 LOG(1+verbosity, "End of SPFragmentGenerator, " << RootDistance << " away from Root " << *FragmentSearch->getRoot() << " and SubOrder is " << SubOrder << ".");
336};
Note: See TracBrowser for help on using the repository browser.