source: src/Fragmentation/PowerSetGenerator.cpp@ bae7bc

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 bae7bc was a1d035, checked in by Frederik Heber <heber@…>, 12 years ago

Converted TouchedList from int* to std::vector<int> in PowerSetGenerator.

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