source: src/SubspaceFactorizer.cpp@ 435065

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

RandomNumberGeneratorFactory is now used instead of rand() throughout the code.

  • FillVoidWithMolecule(): this is not sensible for all distributions. Maybe so, for now this is just to test the dipole angular correlation implementation. Here, one should rather hard-code one.
  • Property mode set to 100644
File size: 16.1 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 * SubspaceFactorizer.cpp
10 *
11 * Created on: Nov 23, 2010
12 * Author: heber
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include <cmath>
21
22#include <gsl/gsl_eigen.h>
23#include <gsl/gsl_matrix.h>
24#include <gsl/gsl_vector.h>
25#include <boost/foreach.hpp>
26#include <boost/shared_ptr.hpp>
27#include <boost/timer.hpp>
28
29#include "CodePatterns/Assert.hpp"
30#include "Helpers/defs.hpp"
31#include "CodePatterns/Log.hpp"
32#include "CodePatterns/toString.hpp"
33#include "CodePatterns/Verbose.hpp"
34#include "LinearAlgebra/Eigenspace.hpp"
35#include "LinearAlgebra/MatrixContent.hpp"
36#include "LinearAlgebra/Subspace.hpp"
37#include "LinearAlgebra/VectorContent.hpp"
38
39#include "RandomNumbers/RandomNumberGeneratorFactory.hpp"
40#include "RandomNumbers/RandomNumberGenerator.hpp"
41
42typedef std::set<std::set<size_t> > SetofIndexSets;
43typedef std::set<size_t> IndexSet;
44typedef std::multimap< size_t, boost::shared_ptr<Subspace> > SubspaceMap;
45typedef std::multimap< size_t, boost::shared_ptr<IndexSet> > IndexMap;
46typedef std::list< boost::shared_ptr<VectorContent> > VectorList;
47typedef std::list< std::pair<boost::shared_ptr<VectorContent>, double> > VectorValueList;
48typedef std::vector< boost::shared_ptr<VectorContent> > VectorArray;
49typedef std::vector< double > ValueArray;
50
51
52/** Iterative function to generate all power sets of indices of size \a maxelements.
53 *
54 * @param SetofSets Container for all sets
55 * @param CurrentSet pointer to current set in this container
56 * @param Indices Source set of indices
57 * @param maxelements number of elements of each set in final SetofSets
58 * @return true - generation continued, false - current set already had
59 * \a maxelements elements
60 */
61bool generatePowerSet(
62 SetofIndexSets &SetofSets,
63 SetofIndexSets::iterator &CurrentSet,
64 IndexSet &Indices,
65 const size_t maxelements)
66{
67 if (CurrentSet->size() < maxelements) {
68 // allocate the needed sets
69 const size_t size = Indices.size() - CurrentSet->size();
70 std::vector<std::set<size_t> > SetExpanded;
71 SetExpanded.reserve(size);
72
73 // copy the current set into each
74 for (size_t i=0;i<size;++i)
75 SetExpanded.push_back(*CurrentSet);
76
77 // expand each set by one index
78 size_t localindex=0;
79 BOOST_FOREACH(size_t iter, Indices) {
80 if (CurrentSet->count(iter) == 0) {
81 SetExpanded[localindex].insert(iter);
82 ++localindex;
83 }
84 }
85
86 // insert set at position of CurrentSet
87 for (size_t i=0;i<size;++i) {
88 //DoLog(1) && (Log() << Verbose(1) << "Inserting set #" << i << ": " << SetExpanded[i] << std::endl);
89 SetofSets.insert(CurrentSet, SetExpanded[i]);
90 }
91 SetExpanded.clear();
92
93 // and remove the current set
94 //SetofSets.erase(CurrentSet);
95 //CurrentSet = SetofSets.begin();
96
97 // set iterator to a valid position again
98 ++CurrentSet;
99 return true;
100 } else {
101 return false;
102 }
103}
104
105
106
107/** Prints the scalar product of each possible pair that is not orthonormal.
108 * We use class logger for printing.
109 * @param AllIndices set of all possible indices of the eigenvectors
110 * @param CurrentEigenvectors array of eigenvectors
111 * @return true - all are orthonormal to each other,
112 * false - some are not orthogonal or not normalized.
113 */
114bool checkOrthogonality(const IndexSet &AllIndices, const VectorArray &CurrentEigenvectors)
115{
116 size_t nonnormalized = 0;
117 size_t nonorthogonal = 0;
118 // check orthogonality
119 BOOST_FOREACH( size_t firstindex, AllIndices) {
120 BOOST_FOREACH( size_t secondindex, AllIndices) {
121 const double scp = (*CurrentEigenvectors[firstindex])*(*CurrentEigenvectors[secondindex]);
122 if (firstindex == secondindex) {
123 if (fabs(scp - 1.) > MYEPSILON) {
124 nonnormalized++;
125 Log() << Verbose(2) << "Vector " << firstindex << " is not normalized, off by "
126 << fabs(1.-(*CurrentEigenvectors[firstindex])*(*CurrentEigenvectors[secondindex])) << std::endl;
127 }
128 } else {
129 if (fabs(scp) > MYEPSILON) {
130 nonorthogonal++;
131 Log() << Verbose(2) << "Scalar product between " << firstindex << " and " << secondindex
132 << " is " << (*CurrentEigenvectors[firstindex])*(*CurrentEigenvectors[secondindex]) << std::endl;
133 }
134 }
135 }
136 }
137
138 if ((nonnormalized == 0) && (nonorthogonal == 0)) {
139 DoLog(1) && (DoLog(1) && (Log() << Verbose(1) << "All vectors are orthonormal to each other." << std::endl));
140 return true;
141 }
142 if ((nonnormalized == 0) && (nonorthogonal != 0))
143 DoLog(1) && (DoLog(1) && (Log() << Verbose(1) << "All vectors are normalized." << std::endl));
144 if ((nonnormalized != 0) && (nonorthogonal == 0))
145 DoLog(1) && (DoLog(1) && (Log() << Verbose(1) << "All vectors are orthogonal to each other." << std::endl));
146 return false;
147}
148
149/** Calculate the sum of the scalar product of each possible pair.
150 * @param AllIndices set of all possible indices of the eigenvectors
151 * @param CurrentEigenvectors array of eigenvectors
152 * @return sum of scalar products between all possible pairs
153 */
154double calculateOrthogonalityThreshold(const IndexSet &AllIndices, const VectorArray &CurrentEigenvectors)
155{
156 double threshold = 0.;
157 // check orthogonality
158 BOOST_FOREACH( size_t firstindex, AllIndices) {
159 BOOST_FOREACH( size_t secondindex, AllIndices) {
160 const double scp = (*CurrentEigenvectors[firstindex])*(*CurrentEigenvectors[secondindex]);
161 if (firstindex == secondindex) {
162 threshold += fabs(scp - 1.);
163 } else {
164 threshold += fabs(scp);
165 }
166 }
167 }
168 return threshold;
169}
170
171
172/** Operator for output to std::ostream operator of an IndexSet.
173 * @param ost output stream
174 * @param indexset index set to output
175 * @return ost output stream
176 */
177std::ostream & operator<<(std::ostream &ost, const IndexSet &indexset)
178{
179 ost << "{ ";
180 for (IndexSet::const_iterator iter = indexset.begin();
181 iter != indexset.end();
182 ++iter)
183 ost << *iter << " ";
184 ost << "}";
185 return ost;
186}
187
188
189int main(int argc, char **argv)
190{
191 size_t matrixdimension = 8;
192 size_t subspacelimit = 4;
193
194 if (argc < 2) {
195 std::cerr << "Usage: " << argv[0] << " <matrixdim> <subspacelimit>" << std::endl;
196 return 255;
197 } else {
198 {
199 std::stringstream s(toString(argv[1]));;
200 s >> matrixdimension;
201 }
202 {
203 std::stringstream s(toString(argv[2]));;
204 s >> subspacelimit;
205 }
206 }
207
208// RandomNumberGenerator &random = RandomNumberGeneratorFactory::getInstance().makeRandomNumberGenerator();
209// const double rng_min = rng->min();
210// const double rng_max = rng->max();
211 MatrixContent *matrix = new MatrixContent(matrixdimension,matrixdimension);
212 matrix->setZero();
213 for (size_t i=0; i<matrixdimension ; i++) {
214 for (size_t j=0; j<= i; ++j) {
215 //const double value = 10. * random() / (rng_max-rng_min);
216 //const double value = i==j ? 2. : 1.;
217 if (i==j)
218 matrix->set(i,i, 2.);
219 else if (j+1 == i) {
220 matrix->set(i,j, 1.);
221 matrix->set(j,i, 1.);
222 } else {
223 matrix->set(i,j, 0.);
224 matrix->set(j,i, 0.);
225 }
226 }
227 }
228
229 Eigenspace::eigenvectorset CurrentEigenvectors;
230 Eigenspace::eigenvalueset CurrentEigenvalues;
231
232 setVerbosity(3);
233
234 boost::timer Time_generatingfullspace;
235 DoLog(0) && (Log() << Verbose(0) << std::endl << std::endl);
236 // create the total index set
237 IndexSet AllIndices;
238 for (size_t i=0;i<matrixdimension;++i)
239 AllIndices.insert(i);
240 Eigenspace FullSpace(AllIndices, *matrix);
241 DoLog(1) && (Log() << Verbose(1) << "Generated full space: " << FullSpace << std::endl);
242 DoLog(0) && (Log() << Verbose(0) << "Full space generation took " << Time_generatingfullspace.elapsed() << " seconds." << std::endl);
243
244 // generate first set of eigenvectors
245 // set to first guess, i.e. the unit vectors of R^matrixdimension
246 BOOST_FOREACH( size_t index, AllIndices) {
247 boost::shared_ptr<VectorContent> EV(new VectorContent(matrixdimension));
248 EV->setZero();
249 EV->at(index) = 1.;
250 CurrentEigenvectors.push_back(EV);
251 CurrentEigenvalues.push_back(0.);
252 }
253
254 boost::timer Time_generatingsubsets;
255 DoLog(0) && (Log() << Verbose(0) << "Generating sub sets ..." << std::endl);
256 SetofIndexSets SetofSets;
257 // note that starting off empty set is unstable
258 IndexSet singleset;
259 BOOST_FOREACH(size_t iter, AllIndices) {
260 singleset.insert(iter);
261 SetofSets.insert(singleset);
262 singleset.clear();
263 }
264 SetofIndexSets::iterator CurrentSet = SetofSets.begin();
265 while (CurrentSet != SetofSets.end()) {
266 //DoLog(2) && (Log() << Verbose(2) << "Current set is " << *CurrentSet << std::endl);
267 if (!generatePowerSet(SetofSets, CurrentSet, AllIndices, subspacelimit)) {
268 // go to next set
269 ++CurrentSet;
270 }
271 }
272 DoLog(0) && (Log() << Verbose(0) << "Sub set generation took " << Time_generatingsubsets.elapsed() << " seconds." << std::endl);
273
274 // create a subspace to each set and and to respective level
275 boost::timer Time_generatingsubspaces;
276 DoLog(0) && (Log() << Verbose(0) << "Generating sub spaces ..." << std::endl);
277 SubspaceMap Dimension_to_Indexset;
278 BOOST_FOREACH(std::set<size_t> iter, SetofSets) {
279 boost::shared_ptr<Subspace> subspace(new Subspace(iter, FullSpace));
280 DoLog(1) && (Log() << Verbose(1) << "Current subspace is " << *subspace << std::endl);
281 Dimension_to_Indexset.insert( make_pair(iter.size(), boost::shared_ptr<Subspace>(subspace)) );
282 }
283
284 for (size_t dim = 1; dim<=subspacelimit;++dim) {
285 BOOST_FOREACH( SubspaceMap::value_type subspace, Dimension_to_Indexset.equal_range(dim)) {
286 if (dim != 0) { // from level 1 and onward
287 BOOST_FOREACH( SubspaceMap::value_type entry, Dimension_to_Indexset.equal_range(dim-1)) {
288 if (subspace.second->contains(*entry.second)) {
289 // if contained then add ...
290 subspace.second->addSubset(entry.second);
291 // ... and also its containees as they are all automatically contained as well
292 BOOST_FOREACH(boost::shared_ptr<Subspace> iter, entry.second->getSubIndices()) {
293 subspace.second->addSubset(iter);
294 }
295 }
296 }
297 }
298 }
299 }
300 DoLog(0) && (Log() << Verbose(0) << "Sub space generation took " << Time_generatingsubspaces.elapsed() << " seconds." << std::endl);
301
302 // create a file handle for the eigenvalues
303 std::ofstream outputvalues("eigenvalues.dat", std::ios_base::trunc);
304 ASSERT(outputvalues.good(),
305 "SubspaceFactorizerUnittest::EigenvectorTest() - failed to open eigenvalue file!");
306 outputvalues << "# iteration ";
307 BOOST_FOREACH(size_t iter, AllIndices) {
308 outputvalues << "\teigenvalue" << iter;
309 }
310 outputvalues << std::endl;
311
312 DoLog(0) && (Log() << Verbose(0) << "Solving ..." << std::endl);
313 boost::timer Time_solving;
314 size_t run=1; // counting iterations
315 double threshold = 1.; // containing threshold value
316 while ((threshold > MYEPSILON) && (run < 20)) {
317 // for every dimension
318 for (size_t dim = 1; dim <= subspacelimit;++dim) {
319 // for every index set of this dimension
320 DoLog(1) && (Log() << Verbose(1) << std::endl << std::endl);
321 DoLog(1) && (Log() << Verbose(1) << "Current dimension is " << dim << std::endl);
322 std::pair<SubspaceMap::const_iterator,SubspaceMap::const_iterator> Bounds = Dimension_to_Indexset.equal_range(dim);
323 for (SubspaceMap::const_iterator IndexsetIter = Bounds.first;
324 IndexsetIter != Bounds.second;
325 ++IndexsetIter) {
326 Subspace& subspace = *(IndexsetIter->second);
327 // show the index set
328 DoLog(2) && (Log() << Verbose(2) << std::endl);
329 DoLog(2) && (Log() << Verbose(2) << "Current subspace is " << subspace << std::endl);
330
331 // solve
332 subspace.calculateEigenSubspace();
333
334 // note that assignment to global eigenvectors all remains within subspace
335 }
336 }
337
338 // print list of similar eigenvectors
339 DoLog(2) && (Log() << Verbose(2) << std::endl);
340 BOOST_FOREACH( size_t index, AllIndices) {
341 DoLog(2) && (Log() << Verbose(2) << "Similar to " << index << "th current eigenvector " << *(CurrentEigenvectors[index]) << " are:" << std::endl);
342 BOOST_FOREACH( SubspaceMap::value_type iter, Dimension_to_Indexset) {
343 const VectorContent & CurrentEV = (iter.second)->getEigenvectorParallelToFullOne(index);
344 if (!CurrentEV.IsZero())
345 Log() << Verbose(2)
346 << "dim" << iter.first
347 << ", subspace{" << (iter.second)->getIndices()
348 << "}: "<< CurrentEV << std::endl;
349 }
350 DoLog(2) && (Log() << Verbose(2) << std::endl);
351 }
352
353 // create new CurrentEigenvectors from averaging parallel ones.
354 BOOST_FOREACH(size_t index, AllIndices) {
355 CurrentEigenvectors[index]->setZero();
356 CurrentEigenvalues[index] = 0.;
357 size_t count = 0;
358 BOOST_FOREACH( SubspaceMap::value_type iter, Dimension_to_Indexset) {
359 const VectorContent CurrentEV = (iter.second)->getEigenvectorParallelToFullOne(index);
360 *CurrentEigenvectors[index] += CurrentEV; // * (iter.second)->getEigenvalueOfEigenvectorParallelToFullOne(index);
361 CurrentEigenvalues[index] += (iter.second)->getEigenvalueOfEigenvectorParallelToFullOne(index);
362 if (!CurrentEV.IsZero())
363 count++;
364 }
365 *CurrentEigenvectors[index] *= 1./CurrentEigenvalues[index];
366 //CurrentEigenvalues[index] /= (double)count;
367 }
368
369 // check orthonormality
370 threshold = calculateOrthogonalityThreshold(AllIndices, CurrentEigenvectors);
371 bool dontOrthonormalization = checkOrthogonality(AllIndices, CurrentEigenvectors);
372
373 // orthonormalize
374 if (!dontOrthonormalization) {
375 DoLog(1) && (Log() << Verbose(1) << "Orthonormalizing ... " << std::endl);
376 for (IndexSet::const_iterator firstindex = AllIndices.begin();
377 firstindex != AllIndices.end();
378 ++firstindex) {
379 for (IndexSet::const_iterator secondindex = firstindex;
380 secondindex != AllIndices.end();
381 ++secondindex) {
382 if (*firstindex == *secondindex) {
383 (*CurrentEigenvectors[*secondindex]) *= 1./(*CurrentEigenvectors[*secondindex]).Norm();
384 } else {
385 (*CurrentEigenvectors[*secondindex]) -=
386 ((*CurrentEigenvectors[*firstindex])*(*CurrentEigenvectors[*secondindex]))
387 *(*CurrentEigenvectors[*firstindex]);
388 }
389 }
390 }
391 }
392
393// // check orthonormality again
394// checkOrthogonality(AllIndices, CurrentEigenvectors);
395
396 // put obtained eigenvectors into full space
397 FullSpace.setEigenpairs(CurrentEigenvectors, CurrentEigenvalues);
398
399 // show new ones
400 DoLog(1) && (Log() << Verbose(1) << "Resulting new eigenvectors and -values, run " << run << " are:" << std::endl);
401 outputvalues << run;
402 BOOST_FOREACH( size_t index, AllIndices) {
403 DoLog(1) && (Log() << Verbose(1) << *CurrentEigenvectors[index] << " with " << CurrentEigenvalues[index] << std::endl);
404 outputvalues << "\t" << CurrentEigenvalues[index];
405 }
406 outputvalues << std::endl;
407
408 // and next iteration
409 DoLog(0) && (Log() << Verbose(0) << "\titeration #" << run << std::endl);
410 run++;
411 }
412 DoLog(0) && (Log() << Verbose(0) << "Solving took " << Time_solving.elapsed() << " seconds." << std::endl);
413 // show final ones
414 DoLog(0) && (Log() << Verbose(0) << "Resulting new eigenvectors and -values, run " << run << " are:" << std::endl);
415 outputvalues << run;
416 BOOST_FOREACH( size_t index, AllIndices) {
417 DoLog(0) && (Log() << Verbose(0) << *CurrentEigenvectors[index] << " with " << CurrentEigenvalues[index] << std::endl);
418 outputvalues << "\t" << CurrentEigenvalues[index];
419 }
420 outputvalues << std::endl;
421 outputvalues.close();
422
423 setVerbosity(2);
424
425 DoLog(0) && (Log() << Verbose(0) << "Solving full space ..." << std::endl);
426 boost::timer Time_comparison;
427 MatrixContent tempFullspaceMatrix = FullSpace.getEigenspaceMatrix();
428 gsl_vector *eigenvalues = tempFullspaceMatrix.transformToEigenbasis();
429 tempFullspaceMatrix.sortEigenbasis(eigenvalues);
430 DoLog(0) && (Log() << Verbose(0) << "full space solution took " << Time_comparison.elapsed() << " seconds." << std::endl);
431
432 delete matrix;
433
434 return 0;
435}
Note: See TracBrowser for help on using the repository browser.