source: src/Fragmentation/PowerSetGenerator.cpp@ d4d7a1

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

FIX: As we use GSL internally, we are as of now required to use GPL v2 license.

  • GNU Scientific Library is used at every place in the code, especially the sub-package LinearAlgebra is based on it which in turn is used really everywhere in the remainder of MoleCuilder. Hence, we have to use the GPL license for the whole of MoleCuilder. In effect, GPL's COPYING was present all along and stated the terms of the GPL v2 license.
  • Hence, I added the default GPL v2 disclaimer to every source file and removed the note about a (actually missing) LICENSE file.
  • also, I added a help-redistribute action which again gives the disclaimer of the GPL v2.
  • also, I changed in the disclaimer that is printed at every program start in builder_init.cpp.
  • TEST: Added check on GPL statement present in every module to test CodeChecks project-disclaimer.
  • Property mode set to 100644
File size: 14.3 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(class 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, int *&TouchedList, int SubOrder, int &TouchedIndex)
72{
73 LOG(1+verbosity, "Clearing touched list.");
74 for (TouchedIndex=SubOrder+1;TouchedIndex--;) // empty touched list
75 TouchedList[TouchedIndex] = -1;
76 TouchedIndex = 0;
77
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 *> &BondsSet, int *&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 *>::const_iterator SetFirst, std::list<bond *>::const_iterator SetLast, int *&TouchedList, int TouchedIndex)
125{
126 int SetDimension = 0;
127 for( std::list<bond *>::const_iterator Binder = SetFirst;
128 Binder != SetLast;
129 ++Binder) {
130 for (int k=TouchedIndex;k--;) {
131 if ((*Binder)->Contains(TouchedList[k])) // if we added this very endpiece
132 SetDimension++;
133 }
134 }
135 return SetDimension;
136};
137
138/** Fills a list of bonds from another
139 * \param *BondsList bonds array/vector to fill
140 * \param SetFirst begin iterator first bond
141 * \param SetLast end iterator
142 * \param *&TouchedList touched list
143 * \param TouchedIndex currently touched
144 * \return number of elements
145 */
146int PowerSetGenerator::FillBondsList(std::vector<bond *> &BondsList, std::list<bond *>::const_iterator SetFirst, std::list<bond *>::const_iterator SetLast, int *&TouchedList, int TouchedIndex)
147{
148 int SetDimension = 0;
149 for( std::list<bond *>::const_iterator Binder = SetFirst;
150 Binder != SetLast;
151 ++Binder) {
152 for (int k=0;k<TouchedIndex;k++) {
153 if ((*Binder)->leftatom->getNr() == TouchedList[k]) // leftatom is always the closer one
154 BondsList[SetDimension++] = (*Binder);
155 }
156 }
157 return SetDimension;
158};
159
160/** Remove all items that were added on this SP level.
161 * \param verbosity verbosity level
162 * \param *FragmentSet snake stack to remove from
163 * \param *&TouchedList touched list
164 * \param TouchedIndex currently touched
165 */
166void PowerSetGenerator::RemoveAllTouchedFromSnakeStack(int verbosity, KeySet *FragmentSet, int *&TouchedList, int &TouchedIndex)
167{
168 int Removal = 0;
169 for(int j=0;j<TouchedIndex;j++) {
170 Removal = TouchedList[j];
171 LOG(2+verbosity, "Removing item nr. " << Removal << " from snake stack.");
172 FragmentSet->erase(Removal);
173 TouchedList[j] = -1;
174 }
175 std::stringstream output;
176 output << "Remaining local nr.s on snake stack are: ";
177 for(KeySet::iterator runner = FragmentSet->begin(); runner != FragmentSet->end(); runner++)
178 output << (*runner) << " ";
179 LOG(2, output.str());
180 TouchedIndex = 0; // set Index to 0 for list of atoms added on this level
181};
182
183
184/** 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.
185 * -# initialises UniqueFragments structure
186 * -# fills edge list via BFS
187 * -# creates the fragment by calling recursive function SPFragmentGenerator with UniqueFragments structure, 0 as
188 root distance, the edge set, its dimension and the current suborder
189 * -# Free'ing structure
190 * 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
191 * with SP of 2, then those with SP of 3, then those with SP of 4 and so on.
192 * \param RestrictedKeySet Restricted vertex set to use in context of molecule
193 * \param saturation whether to treat hydrogen special or not
194 * \return number of inserted fragments
195 * \note ShortestPathList in FragmentSearch structure is probably due to NumberOfAtomsSPLevel and SP not needed anymore
196 */
197int PowerSetGenerator::operator()(KeySet &RestrictedKeySet, const enum HydrogenSaturation saturation)
198{
199 int Counter = FragmentSearch->FragmentCounter; // mark current value of counter
200
201 LOG(0, std::endl);
202 LOG(0, "Begin of PowerSetGenerator with order " << BondsPerSPList.getOrder() << " at Root " << *FragmentSearch->getRoot() << ".");
203
204 BondsPerSPList.SetSPList(FragmentSearch->getRoot());
205
206 // do a BFS search to fill the SP lists and label the found vertices
207 BondsPerSPList.FillSPListandLabelVertices(FragmentSearch->getRoot()->GetTrueFather()->getNr(), RestrictedKeySet, saturation);
208
209 // outputting all list for debugging
210 BondsPerSPList.OutputSPList();
211
212 // creating fragments with the found edge sets (may be done in reverse order, faster)
213 int SP = BondsPerSPList.CountNumbersInBondsList();
214 LOG(0, "Total number of edges is " << SP << ".");
215 if (SP >= (BondsPerSPList.getOrder()-1)) {
216 // start with root (push on fragment stack)
217 LOG(0, "Starting fragment generation with " << *FragmentSearch->getRoot() << ", local nr is " << FragmentSearch->getRoot()->getNr() << ".");
218 FragmentSearch->FragmentSet->clear();
219 LOG(0, "Preparing subset for this root and calling generator.");
220
221 // prepare the subset and call the generator
222 std::vector<bond*> BondsList;
223 BondsList.resize(BondsPerSPList.BondsPerSPCount[0]);
224 ASSERT(BondsPerSPList.BondsPerSPList[0].size() != 0,
225 "molecule::PowerSetGenerator() - BondsPerSPList.BondsPerSPList[0] contains no root bond.");
226 BondsList[0] = (*BondsPerSPList.BondsPerSPList[0].begin()); // on SP level 0 there's only the root bond
227
228 SPFragmentGenerator(0, BondsList, BondsPerSPList.BondsPerSPCount[0], BondsPerSPList.getOrder());
229 } else {
230 LOG(0, "Not enough total number of edges to build " << BondsPerSPList.getOrder() << "-body fragments.");
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 *> &BondsSet, int SetDimension, int SubOrder)
260{
261 Info info(__func__);
262 int verbosity = 0; //FragmentSearch->ANOVAOrder-SubOrder;
263 int NumCombinations;
264 int bits, TouchedIndex, SubSetDimension, SP, Added;
265 int SpaceLeft;
266 int *TouchedList = new int[SubOrder + 1];
267 KeySetTestPair TestKeySetInsert;
268
269 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 bits = 0;
285 for (int j=SetDimension;j--;)
286 bits += (i & (1 << j)) >> j;
287
288 LOG(1+verbosity, "Current set is " << Binary(i | (1 << SetDimension)) << ", number of bits is " << bits << ".");
289 if (bits <= SubOrder) { // if not greater than additional atoms allowed on stack, continue
290 // --1-- add this set of the power set of bond partners to the snake stack
291 Added = AddPowersetToSnakeStack(verbosity, i, SetDimension, FragmentSearch->FragmentSet, BondsSet, TouchedList, TouchedIndex);
292
293 SpaceLeft = SubOrder - Added ;// SubOrder - bits; // due to item's maybe being already present, this does not work anymore
294 if (SpaceLeft > 0) {
295 LOG(1+verbosity, "There's still some space left on stack: " << SpaceLeft << ".");
296 if (SubOrder > 1) { // Due to Added above we have to check extra whether we're not already reaching beyond the desired Order
297 // --2-- look at all added end pieces of this combination, construct bond subsets and sweep through a power set of these by recursion
298 SP = RootDistance+1; // this is the next level
299
300 // first count the members in the subset
301 SubSetDimension = CountSetMembers(BondsPerSPList.BondsPerSPList[SP].begin(), BondsPerSPList.BondsPerSPList[SP].end(), TouchedList, TouchedIndex);
302
303 // then allocate and fill the list
304 std::vector<bond *> BondsList;
305 BondsList.resize(SubSetDimension);
306 SubSetDimension = FillBondsList(BondsList, BondsPerSPList.BondsPerSPList[SP].begin(), BondsPerSPList.BondsPerSPList[SP].end(), TouchedList, TouchedIndex);
307
308 // then iterate
309 LOG(2+verbosity, "Calling subset generator " << SP << " away from root " << *FragmentSearch->getRoot() << " with sub set dimension " << SubSetDimension << ".");
310 SPFragmentGenerator(SP, BondsList, SubSetDimension, SubOrder-bits);
311 }
312 } else {
313 // --2-- otherwise store the complete fragment
314 LOG(1+verbosity, "Enough items on stack for a fragment!");
315 // store fragment as a KeySet
316 if (DoLog(2)) {
317 std::stringstream output;
318 output << "Found a new fragment[" << FragmentSearch->FragmentCounter << "], local nr.s are: ";
319 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
320 output << (*runner) << " ";
321 LOG(2, output.str());
322 }
323 FragmentSearch->InsertFragmentIntoGraph();
324 }
325
326 // --3-- remove all added items in this level from snake stack
327 LOG(1+verbosity, "Removing all items that were added on this SP level " << RootDistance << ".");
328 RemoveAllTouchedFromSnakeStack(verbosity, FragmentSearch->FragmentSet, TouchedList, TouchedIndex);
329 } else {
330 LOG(2+verbosity, "More atoms to add for this set (" << bits << ") than space left on stack " << SubOrder << ", skipping this set.");
331 }
332 }
333 delete[](TouchedList);
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.