source: src/SubspaceFactorizer.cpp@ 456e78

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

SubspaceFactorizer is now hierarchical.

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