source: src/SubspaceFactorizer.cpp@ 3f9eba

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 3f9eba was 56f73b, checked in by Frederik Heber <heber@…>, 14 years ago

Added config.h also to all header files, code check test ascertain this in the future.

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