source: src/unittests/SubspaceFactorizerUnitTest.cpp@ 00b59d5

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 00b59d5 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: 32.0 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 * SubspaceFactorizerUnitTest.cpp
10 *
11 * Created on: Nov 13, 2010
12 * Author: heber
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include <cppunit/CompilerOutputter.h>
21#include <cppunit/extensions/TestFactoryRegistry.h>
22#include <cppunit/ui/text/TestRunner.h>
23
24#include <cmath>
25
26#include <gsl/gsl_vector.h>
27#include <boost/foreach.hpp>
28#include <boost/shared_ptr.hpp>
29#include <boost/timer.hpp>
30
31#include "CodePatterns/Assert.hpp"
32#include "Helpers/defs.hpp"
33#include "CodePatterns/Log.hpp"
34#include "CodePatterns/toString.hpp"
35#include "CodePatterns/Verbose.hpp"
36#include "LinearAlgebra/Eigenspace.hpp"
37#include "LinearAlgebra/MatrixContent.hpp"
38#include "LinearAlgebra/Subspace.hpp"
39#include "LinearAlgebra/VectorContent.hpp"
40
41#include "RandomNumbers/RandomNumberGeneratorFactory.hpp"
42#include "RandomNumbers/RandomNumberGenerator.hpp"
43
44#include "SubspaceFactorizerUnitTest.hpp"
45
46#ifdef HAVE_TESTRUNNER
47#include "UnitTestMain.hpp"
48#endif /*HAVE_TESTRUNNER*/
49
50// Registers the fixture into the 'registry'
51CPPUNIT_TEST_SUITE_REGISTRATION( SubspaceFactorizerUnittest );
52
53void SubspaceFactorizerUnittest::setUp(){
54// RandomNumberGenerator &random = RandomNumberGeneratorFactory::getInstance().makeRandomNumberGenerator();
55// const double rng_min = rng->min();
56// const double rng_max = rng->max();
57 matrix = new MatrixContent(matrixdimension,matrixdimension);
58 matrix->setZero();
59 for (size_t i=0; i<matrixdimension ; i++) {
60 for (size_t j=0; j<= i; ++j) {
61 //const double value = 10. * random() / (rng_max-rng_min);
62 //const double value = i==j ? 2. : 1.;
63 if (i==j)
64 matrix->set(i,i, 2.);
65 else if (j+1 == i) {
66 matrix->set(i,j, 1.);
67 matrix->set(j,i, 1.);
68 } else {
69 matrix->set(i,j, 0.);
70 matrix->set(j,i, 0.);
71 }
72 }
73 }
74}
75
76void SubspaceFactorizerUnittest::tearDown(){
77 // delete test matrix
78 delete matrix;
79}
80
81void SubspaceFactorizerUnittest::BlockTest()
82{
83 MatrixContent *transformation = new MatrixContent(matrixdimension,matrixdimension);
84 transformation->setZero();
85 for (size_t j=0; j<1; ++j)
86 transformation->set(j,j, 1.);
87
88 MatrixContent temp((*matrix)&(*transformation));
89 std::cout << "Our matrix is " << *matrix << "." << std::endl;
90
91 std::cout << "Hadamard product of " << *matrix << " with " << *transformation << " is: " << std::endl;
92 std::cout << temp << std::endl;
93
94 gsl_vector *eigenvalues = temp.transformToEigenbasis();
95 VectorContent *eigenvaluesView = new VectorViewContent(gsl_vector_subvector(eigenvalues, 0, eigenvalues->size));
96 std::cout << "The resulting eigenbasis is " << temp
97 << "\n\t with eigenvalues " << *eigenvaluesView << std::endl;
98 delete eigenvaluesView;
99 gsl_vector_free(eigenvalues);
100 delete (transformation);
101
102
103 CPPUNIT_ASSERT_EQUAL(0,0);
104}
105
106/** For given set of row and column indices, we extract the small block matrix.
107 * @param bigmatrix big matrix to extract from
108 * @param Eigenvectors eigenvectors of the subspaces to obtain matrix in
109 * @param columnindexset index set to pick out of all indices
110 * @return small matrix with dimension equal to the number of indices for row and column.
111 */
112MatrixContent * getSubspaceMatrix(
113 MatrixContent &bigmatrix,
114 VectorArray &Eigenvectors,
115 const IndexSet &indexset)
116{
117 // check whether subsystem is big enough for both index sets
118 ASSERT(indexset.size() <= bigmatrix.getRows(),
119 "embedSubspaceMatrix() - bigmatrix has less rows "+toString(bigmatrix.getRows())
120 +" than needed by index set "
121 +toString(indexset.size())+"!");
122 ASSERT(indexset.size() <= bigmatrix.getColumns(),
123 "embedSubspaceMatrix() - bigmatrix has less columns "+toString(bigmatrix.getColumns())
124 +" than needed by index set "
125 +toString(indexset.size())+"!");
126
127 // construct small matrix
128 MatrixContent *subsystem = new MatrixContent(indexset.size(), indexset.size());
129 size_t localrow = 0; // local row indices for the subsystem
130 size_t localcolumn = 0;
131 BOOST_FOREACH( size_t rowindex, indexset) {
132 localcolumn = 0;
133 BOOST_FOREACH( size_t columnindex, indexset) {
134 ASSERT((rowindex < bigmatrix.getRows()) && (columnindex < bigmatrix.getColumns()),
135 "current index pair ("
136 +toString(rowindex)+","+toString(columnindex)
137 +") is out of bounds of bigmatrix ("
138 +toString(bigmatrix.getRows())+","+toString(bigmatrix.getColumns())
139 +")");
140 subsystem->at(localrow,localcolumn) = (*Eigenvectors[rowindex]) * (bigmatrix * (*Eigenvectors[columnindex]));
141 localcolumn++;
142 }
143 localrow++;
144 }
145 return subsystem;
146}
147
148/** For a given set of row and columns indices, we embed a small block matrix into a bigger space.
149 *
150 * @param eigenvectors current eigenvectors
151 * @param rowindexset row index set
152 * @param columnindexset column index set
153 * @return bigmatrix with eigenvectors contained
154 */
155MatrixContent * embedSubspaceMatrix(
156 VectorArray &Eigenvectors,
157 MatrixContent &subsystem,
158 const IndexSet &columnindexset)
159{
160 // check whether bigmatrix is at least as big as subsystem
161 ASSERT(Eigenvectors.size() > 0,
162 "embedSubspaceMatrix() - no Eigenvectors given!");
163 ASSERT(subsystem.getRows() <= Eigenvectors[0]->getDimension(),
164 "embedSubspaceMatrix() - subsystem has more rows "
165 +toString(subsystem.getRows())+" than eigenvectors "
166 +toString(Eigenvectors[0]->getDimension())+"!");
167 ASSERT(subsystem.getColumns() <= Eigenvectors.size(),
168 "embedSubspaceMatrix() - subsystem has more columns "
169 +toString(subsystem.getColumns())+" than eigenvectors "
170 +toString(Eigenvectors.size())+"!");
171 // check whether subsystem is big enough for both index sets
172 ASSERT(subsystem.getColumns() == subsystem.getRows(),
173 "embedSubspaceMatrix() - subsystem is not square "
174 +toString(subsystem.getRows())+" than needed by index set "
175 +toString(subsystem.getColumns())+"!");
176 ASSERT(columnindexset.size() == subsystem.getColumns(),
177 "embedSubspaceMatrix() - subsystem has not the same number of columns "
178 +toString(subsystem.getColumns())+" compared to the index set "
179 +toString(columnindexset.size())+"!");
180
181 // construct intermediate matrix
182 MatrixContent *intermediatematrix = new MatrixContent(Eigenvectors[0]->getDimension(), columnindexset.size());
183 size_t localcolumn = 0;
184 BOOST_FOREACH(size_t columnindex, columnindexset) {
185 // create two vectors from each row and copy assign them
186 boost::shared_ptr<VectorContent> srceigenvector(Eigenvectors[columnindex]);
187 boost::shared_ptr<VectorContent> desteigenvector(intermediatematrix->getColumnVector(localcolumn));
188 *desteigenvector = *srceigenvector;
189 localcolumn++;
190 }
191 // matrix product with eigenbasis subsystem matrix
192 *intermediatematrix *= subsystem;
193
194 // and place at right columns into bigmatrix
195 MatrixContent *bigmatrix = new MatrixContent(Eigenvectors[0]->getDimension(), Eigenvectors.size());
196 bigmatrix->setZero();
197 localcolumn = 0;
198 BOOST_FOREACH(size_t columnindex, columnindexset) {
199 // create two vectors from each row and copy assign them
200 boost::shared_ptr<VectorContent> srceigenvector(intermediatematrix->getColumnVector(localcolumn));
201 boost::shared_ptr<VectorContent> desteigenvector(bigmatrix->getColumnVector(columnindex));
202 *desteigenvector = *srceigenvector;
203 localcolumn++;
204 }
205
206 return bigmatrix;
207}
208
209/** Prints the scalar product of each possible pair that is not orthonormal.
210 * We use class logger for printing.
211 * @param AllIndices set of all possible indices of the eigenvectors
212 * @param CurrentEigenvectors array of eigenvectors
213 * @return true - all are orthonormal to each other,
214 * false - some are not orthogonal or not normalized.
215 */
216bool checkOrthogonality(const IndexSet &AllIndices, const VectorArray &CurrentEigenvectors)
217{
218 size_t nonnormalized = 0;
219 size_t nonorthogonal = 0;
220 // check orthogonality
221 BOOST_FOREACH( size_t firstindex, AllIndices) {
222 BOOST_FOREACH( size_t secondindex, AllIndices) {
223 const double scp = (*CurrentEigenvectors[firstindex])*(*CurrentEigenvectors[secondindex]);
224 if (firstindex == secondindex) {
225 if (fabs(scp - 1.) > MYEPSILON) {
226 nonnormalized++;
227 Log() << Verbose(2) << "Vector " << firstindex << " is not normalized, off by "
228 << fabs(1.-(*CurrentEigenvectors[firstindex])*(*CurrentEigenvectors[secondindex])) << std::endl;
229 }
230 } else {
231 if (fabs(scp) > MYEPSILON) {
232 nonorthogonal++;
233 Log() << Verbose(2) << "Scalar product between " << firstindex << " and " << secondindex
234 << " is " << (*CurrentEigenvectors[firstindex])*(*CurrentEigenvectors[secondindex]) << std::endl;
235 }
236 }
237 }
238 }
239
240 if ((nonnormalized == 0) && (nonorthogonal == 0)) {
241 DoLog(1) && (DoLog(1) && (Log() << Verbose(1) << "All vectors are orthonormal to each other." << std::endl));
242 return true;
243 }
244 if ((nonnormalized == 0) && (nonorthogonal != 0))
245 DoLog(1) && (DoLog(1) && (Log() << Verbose(1) << "All vectors are normalized." << std::endl));
246 if ((nonnormalized != 0) && (nonorthogonal == 0))
247 DoLog(1) && (DoLog(1) && (Log() << Verbose(1) << "All vectors are orthogonal to each other." << std::endl));
248 return false;
249}
250
251/** Calculate the sum of the scalar product of each possible pair.
252 * @param AllIndices set of all possible indices of the eigenvectors
253 * @param CurrentEigenvectors array of eigenvectors
254 * @return sum of scalar products between all possible pairs
255 */
256double calculateOrthogonalityThreshold(const IndexSet &AllIndices, const VectorArray &CurrentEigenvectors)
257{
258 double threshold = 0.;
259 // check orthogonality
260 BOOST_FOREACH( size_t firstindex, AllIndices) {
261 BOOST_FOREACH( size_t secondindex, AllIndices) {
262 const double scp = (*CurrentEigenvectors[firstindex])*(*CurrentEigenvectors[secondindex]);
263 if (firstindex == secondindex) {
264 threshold += fabs(scp - 1.);
265 } else {
266 threshold += fabs(scp);
267 }
268 }
269 }
270 return threshold;
271}
272
273/** Operator for output to std::ostream operator of an IndexSet.
274 * @param ost output stream
275 * @param indexset index set to output
276 * @return ost output stream
277 */
278std::ostream & operator<<(std::ostream &ost, const IndexSet &indexset)
279{
280 ost << "{ ";
281 for (IndexSet::const_iterator iter = indexset.begin();
282 iter != indexset.end();
283 ++iter)
284 ost << *iter << " ";
285 ost << "}";
286 return ost;
287}
288
289/** Assign eigenvectors of subspace to full eigenvectors.
290 * We use parallelity as relation measure.
291 * @param eigenvalue eigenvalue to assign along with
292 * @param CurrentEigenvector eigenvector to assign, is taken over within
293 * boost::shared_ptr
294 * @param CurrentEigenvectors full eigenvectors
295 * @param CorrespondenceList list to make sure that each subspace eigenvector
296 * is assigned to a unique full eigenvector
297 * @param ParallelEigenvectorList list of "similar" subspace eigenvectors per
298 * full eigenvector, allocated
299 */
300void AssignSubspaceEigenvectors(
301 double eigenvalue,
302 VectorContent *CurrentEigenvector,
303 VectorArray &CurrentEigenvectors,
304 IndexSet &CorrespondenceList,
305 VectorValueList *&ParallelEigenvectorList)
306{
307 DoLog(1) && (DoLog(1) && (Log() << Verbose(1) << "Current Eigenvector is " << *CurrentEigenvector << std::endl));
308
309 // (for now settle with the one we are most parallel to)
310 size_t mostparallel_index = SubspaceFactorizerUnittest::matrixdimension;
311 double mostparallel_scalarproduct = 0.;
312 BOOST_FOREACH( size_t indexiter, CorrespondenceList) {
313 DoLog(2) && (DoLog(2) && (Log() << Verbose(2) << "Comparing to old " << indexiter << "th eigenvector " << *(CurrentEigenvectors[indexiter]) << std::endl));
314 const double scalarproduct = (*(CurrentEigenvectors[indexiter])) * (*CurrentEigenvector);
315 DoLog(2) && (DoLog(2) && (Log() << Verbose(2) << "SKP is " << scalarproduct << std::endl));
316 if (fabs(scalarproduct) > mostparallel_scalarproduct) {
317 mostparallel_scalarproduct = fabs(scalarproduct);
318 mostparallel_index = indexiter;
319 }
320 }
321 if (mostparallel_index != SubspaceFactorizerUnittest::matrixdimension) {
322 // put into std::list for later use
323 // invert if pointing in negative direction
324 if ((*(CurrentEigenvectors[mostparallel_index])) * (*CurrentEigenvector) < 0) {
325 *CurrentEigenvector *= -1.;
326 DoLog(1) && (Log() << Verbose(1) << "Pushing (inverted) " << *CurrentEigenvector << " into parallel list [" << mostparallel_index << "]" << std::endl);
327 } else {
328 DoLog(1) && (Log() << Verbose(1) << "Pushing " << *CurrentEigenvector << " into parallel list [" << mostparallel_index << "]" << std::endl);
329 }
330 ParallelEigenvectorList[mostparallel_index].push_back(make_pair(boost::shared_ptr<VectorContent>(CurrentEigenvector), eigenvalue));
331 CorrespondenceList.erase(mostparallel_index);
332 }
333}
334
335void SubspaceFactorizerUnittest::EigenvectorTest()
336{
337 VectorArray CurrentEigenvectors;
338 ValueArray CurrentEigenvalues;
339 VectorValueList *ParallelEigenvectorList = new VectorValueList[matrixdimension];
340 IndexSet AllIndices;
341
342 // create the total index set
343 for (size_t i=0;i<matrixdimension;++i)
344 AllIndices.insert(i);
345
346 // create all consecutive index subsets for dim 1 to 3
347 IndexMap Dimension_to_Indexset;
348 for (size_t dim = 0; dim<3;++dim) {
349 for (size_t i=0;i<matrixdimension;++i) {
350 IndexSet *indexset = new IndexSet;
351 for (size_t j=0;j<dim+1;++j) {
352 const int value = (i+j) % matrixdimension;
353 //std::cout << "Putting " << value << " into " << i << "th map " << dim << std::endl;
354 CPPUNIT_ASSERT_MESSAGE("index "+toString(value)+" already present in "+toString(dim)+"-dim "+toString(i)+"th indexset.", indexset->count(value) == 0);
355 indexset->insert(value);
356 }
357 Dimension_to_Indexset.insert( make_pair(dim, boost::shared_ptr<IndexSet>(indexset)) );
358 // no need to free indexset, is stored in shared_ptr and
359 // will get released when Dimension_to_Indexset is destroyed
360 }
361 }
362
363 // set to first guess, i.e. the unit vectors of R^matrixdimension
364 BOOST_FOREACH( size_t index, AllIndices) {
365 boost::shared_ptr<VectorContent> EV(new VectorContent(matrixdimension));
366 EV->setZero();
367 EV->at(index) = 1.;
368 CurrentEigenvectors.push_back(EV);
369 CurrentEigenvalues.push_back(0.);
370 }
371
372 size_t run=1; // counting iterations
373 double threshold = 1.; // containing threshold value
374 while ((threshold > 1e-10) && (run < 10)) {
375 // for every dimension
376 for (size_t dim = 0; dim<subspacelimit;++dim) {
377 // for every index set of this dimension
378 DoLog(0) && (Log() << Verbose(0) << std::endl << std::endl);
379 DoLog(0) && (Log() << Verbose(0) << "Current dimension is " << dim << std::endl);
380 std::pair<IndexMap::const_iterator,IndexMap::const_iterator> Bounds = Dimension_to_Indexset.equal_range(dim);
381 for (IndexMap::const_iterator IndexsetIter = Bounds.first;
382 IndexsetIter != Bounds.second;
383 ++IndexsetIter) {
384 // show the index set
385 DoLog(0) && (Log() << Verbose(0) << std::endl);
386 DoLog(1) && (Log() << Verbose(1) << "Current index set is " << *(IndexsetIter->second) << std::endl);
387
388 // create transformation matrices from these
389 MatrixContent *subsystem = getSubspaceMatrix(*matrix, CurrentEigenvectors, *(IndexsetIter->second));
390 DoLog(2) && (Log() << Verbose(2) << "Subsystem matrix is " << *subsystem << std::endl);
391
392 // solve _small_ systems for eigenvalues
393 VectorContent *Eigenvalues = new VectorContent(subsystem->transformToEigenbasis());
394 DoLog(2) && (Log() << Verbose(2) << "Eigenvector matrix is " << *subsystem << std::endl);
395 DoLog(2) && (Log() << Verbose(2) << "Eigenvalues are " << *Eigenvalues << std::endl);
396
397 // blow up eigenvectors to matrixdimensiondim column vector again
398 MatrixContent *Eigenvectors = embedSubspaceMatrix(CurrentEigenvectors, *subsystem, *(IndexsetIter->second));
399 DoLog(1) && (Log() << Verbose(1) << matrixdimension << "x" << matrixdimension << " Eigenvector matrix is " << *Eigenvectors << std::endl);
400
401 // we don't need the subsystem anymore
402 delete subsystem;
403
404 // go through all eigenvectors in this subspace
405 IndexSet CorrespondenceList((*IndexsetIter->second)); // assure one-to-one and onto assignment
406 size_t localindex = 0;
407 BOOST_FOREACH( size_t iter, (*IndexsetIter->second)) {
408 // recognize eigenvectors parallel to existing ones
409 AssignSubspaceEigenvectors(
410 Eigenvalues->at(localindex),
411 new VectorContent(Eigenvectors->getColumnVector(iter)),
412 CurrentEigenvectors,
413 CorrespondenceList,
414 ParallelEigenvectorList);
415 localindex++;
416 }
417
418 // free eigenvectors
419 delete Eigenvectors;
420 delete Eigenvalues;
421 }
422 }
423
424 // print list of similar eigenvectors
425 BOOST_FOREACH( size_t index, AllIndices) {
426 DoLog(2) && (Log() << Verbose(2) << "Similar to " << index << "th current eigenvector " << *(CurrentEigenvectors[index]) << " are:" << std::endl);
427 BOOST_FOREACH( VectorValueList::value_type &iter, ParallelEigenvectorList[index] ) {
428 DoLog(2) && (Log() << Verbose(2) << *(iter.first) << std::endl);
429 }
430 DoLog(2) && (Log() << Verbose(2) << std::endl);
431 }
432
433 // create new CurrentEigenvectors from averaging parallel ones.
434 BOOST_FOREACH(size_t index, AllIndices) {
435 CurrentEigenvectors[index]->setZero();
436 CurrentEigenvalues[index] = 0.;
437 BOOST_FOREACH( VectorValueList::value_type &iter, ParallelEigenvectorList[index] ) {
438 *CurrentEigenvectors[index] += (*iter.first) * (iter.second);
439 CurrentEigenvalues[index] += (iter.second);
440 }
441 *CurrentEigenvectors[index] *= 1./CurrentEigenvalues[index];
442 CurrentEigenvalues[index] /= (double)ParallelEigenvectorList[index].size();
443 ParallelEigenvectorList[index].clear();
444 }
445
446 // check orthonormality
447 threshold = calculateOrthogonalityThreshold(AllIndices, CurrentEigenvectors);
448 bool dontOrthonormalization = checkOrthogonality(AllIndices, CurrentEigenvectors);
449
450 // orthonormalize
451 if (!dontOrthonormalization) {
452 DoLog(0) && (Log() << Verbose(0) << "Orthonormalizing ... " << std::endl);
453 for (IndexSet::const_iterator firstindex = AllIndices.begin();
454 firstindex != AllIndices.end();
455 ++firstindex) {
456 for (IndexSet::const_iterator secondindex = firstindex;
457 secondindex != AllIndices.end();
458 ++secondindex) {
459 if (*firstindex == *secondindex) {
460 (*CurrentEigenvectors[*secondindex]) *= 1./(*CurrentEigenvectors[*secondindex]).Norm();
461 } else {
462 (*CurrentEigenvectors[*secondindex]) -=
463 ((*CurrentEigenvectors[*firstindex])*(*CurrentEigenvectors[*secondindex]))
464 *(*CurrentEigenvectors[*firstindex]);
465 }
466 }
467 }
468 }
469
470// // check orthonormality again
471// checkOrthogonality(AllIndices, CurrentEigenvectors);
472
473 // show new ones
474 DoLog(0) && (Log() << Verbose(0) << "Resulting new eigenvectors and -values, run " << run << " are:" << std::endl);
475 BOOST_FOREACH( size_t index, AllIndices) {
476 DoLog(0) && (Log() << Verbose(0) << *CurrentEigenvectors[index] << " with " << CurrentEigenvalues[index] << std::endl);
477 }
478 run++;
479 }
480
481 delete[] ParallelEigenvectorList;
482
483 CPPUNIT_ASSERT_EQUAL(0,0);
484}
485
486
487/** Iterative function to generate all power sets of indices of size \a maxelements.
488 *
489 * @param SetofSets Container for all sets
490 * @param CurrentSet pointer to current set in this container
491 * @param Indices Source set of indices
492 * @param maxelements number of elements of each set in final SetofSets
493 * @return true - generation continued, false - current set already had
494 * \a maxelements elements
495 */
496bool generatePowerSet(
497 SetofIndexSets &SetofSets,
498 SetofIndexSets::iterator &CurrentSet,
499 IndexSet &Indices,
500 const size_t maxelements)
501{
502 if (CurrentSet->size() < maxelements) {
503 // allocate the needed sets
504 const size_t size = Indices.size() - CurrentSet->size();
505 std::vector<std::set<size_t> > SetExpanded;
506 SetExpanded.reserve(size);
507
508 // copy the current set into each
509 for (size_t i=0;i<size;++i)
510 SetExpanded.push_back(*CurrentSet);
511
512 // expand each set by one index
513 size_t localindex=0;
514 BOOST_FOREACH(size_t iter, Indices) {
515 if (CurrentSet->count(iter) == 0) {
516 SetExpanded[localindex].insert(iter);
517 ++localindex;
518 }
519 }
520
521 // insert set at position of CurrentSet
522 for (size_t i=0;i<size;++i) {
523 //DoLog(1) && (Log() << Verbose(1) << "Inserting set #" << i << ": " << SetExpanded[i] << std::endl);
524 SetofSets.insert(CurrentSet, SetExpanded[i]);
525 }
526 SetExpanded.clear();
527
528 // and remove the current set
529 //SetofSets.erase(CurrentSet);
530 //CurrentSet = SetofSets.begin();
531
532 // set iterator to a valid position again
533 ++CurrentSet;
534 return true;
535 } else {
536 return false;
537 }
538}
539
540void SubspaceFactorizerUnittest::generatePowerSetTest()
541{
542 IndexSet AllIndices;
543 for (size_t i=0;i<4;++i)
544 AllIndices.insert(i);
545
546 SetofIndexSets SetofSets;
547 // note that starting off empty set is unstable
548 IndexSet singleset;
549 BOOST_FOREACH(size_t iter, AllIndices) {
550 singleset.insert(iter);
551 SetofSets.insert(singleset);
552 singleset.clear();
553 }
554 SetofIndexSets::iterator CurrentSet = SetofSets.begin();
555 while (CurrentSet != SetofSets.end()) {
556 //DoLog(0) && (Log() << Verbose(0) << "Current set is " << *CurrentSet << std::endl);
557 if (!generatePowerSet(SetofSets, CurrentSet, AllIndices, 2)) {
558 // go to next set
559 ++CurrentSet;
560 }
561 }
562
563 SetofIndexSets ComparisonSet;
564 // now follows a very stupid construction
565 // because we can't use const arrays of some type meaningfully ...
566 { IndexSet tempSet; tempSet.insert(0); ComparisonSet.insert(tempSet); }
567 { IndexSet tempSet; tempSet.insert(1); ComparisonSet.insert(tempSet); }
568 { IndexSet tempSet; tempSet.insert(2); ComparisonSet.insert(tempSet); }
569 { IndexSet tempSet; tempSet.insert(3); ComparisonSet.insert(tempSet); }
570
571 { IndexSet tempSet; tempSet.insert(0); tempSet.insert(1); ComparisonSet.insert(tempSet); }
572 { IndexSet tempSet; tempSet.insert(0); tempSet.insert(2); ComparisonSet.insert(tempSet); }
573 { IndexSet tempSet; tempSet.insert(0); tempSet.insert(3); ComparisonSet.insert(tempSet); }
574
575 { IndexSet tempSet; tempSet.insert(1); tempSet.insert(2); ComparisonSet.insert(tempSet); }
576 { IndexSet tempSet; tempSet.insert(1); tempSet.insert(3); ComparisonSet.insert(tempSet); }
577
578 { IndexSet tempSet; tempSet.insert(2); tempSet.insert(3); ComparisonSet.insert(tempSet); }
579
580 CPPUNIT_ASSERT_EQUAL(SetofSets, ComparisonSet);
581}
582
583bool cmd(double a, double b)
584{
585 return a > b;
586}
587
588void SubspaceFactorizerUnittest::SubspaceTest()
589{
590 Eigenspace::eigenvectorset CurrentEigenvectors;
591 Eigenspace::eigenvalueset CurrentEigenvalues;
592
593 setVerbosity(0);
594
595 boost::timer Time_generatingfullspace;
596 DoLog(0) && (Log() << Verbose(0) << std::endl << std::endl);
597 // create the total index set
598 IndexSet AllIndices;
599 for (size_t i=0;i<matrixdimension;++i)
600 AllIndices.insert(i);
601 Eigenspace FullSpace(AllIndices, *matrix);
602 DoLog(1) && (Log() << Verbose(1) << "Generated full space: " << FullSpace << std::endl);
603 DoLog(0) && (Log() << Verbose(0) << "Full space generation took " << Time_generatingfullspace.elapsed() << " seconds." << std::endl);
604
605 // generate first set of eigenvectors
606 // set to first guess, i.e. the unit vectors of R^matrixdimension
607 BOOST_FOREACH( size_t index, AllIndices) {
608 boost::shared_ptr<VectorContent> EV(new VectorContent(matrixdimension));
609 EV->setZero();
610 EV->at(index) = 1.;
611 CurrentEigenvectors.push_back(EV);
612 CurrentEigenvalues.push_back(0.);
613 }
614
615 boost::timer Time_generatingsubsets;
616 DoLog(0) && (Log() << Verbose(0) << "Generating sub sets ..." << std::endl);
617 SetofIndexSets SetofSets;
618 // note that starting off empty set is unstable
619 IndexSet singleset;
620 BOOST_FOREACH(size_t iter, AllIndices) {
621 singleset.insert(iter);
622 SetofSets.insert(singleset);
623 singleset.clear();
624 }
625 SetofIndexSets::iterator CurrentSet = SetofSets.begin();
626 while (CurrentSet != SetofSets.end()) {
627 //DoLog(2) && (Log() << Verbose(2) << "Current set is " << *CurrentSet << std::endl);
628 if (!generatePowerSet(SetofSets, CurrentSet, AllIndices, subspacelimit)) {
629 // go to next set
630 ++CurrentSet;
631 }
632 }
633 DoLog(0) && (Log() << Verbose(0) << "Sub set generation took " << Time_generatingsubsets.elapsed() << " seconds." << std::endl);
634
635 // create a subspace to each set and and to respective level
636 boost::timer Time_generatingsubspaces;
637 DoLog(0) && (Log() << Verbose(0) << "Generating sub spaces ..." << std::endl);
638 SubspaceMap Dimension_to_Indexset;
639 BOOST_FOREACH(std::set<size_t> iter, SetofSets) {
640 boost::shared_ptr<Subspace> subspace(new Subspace(iter, FullSpace));
641 DoLog(1) && (Log() << Verbose(1) << "Current subspace is " << *subspace << std::endl);
642 Dimension_to_Indexset.insert( make_pair(iter.size(), boost::shared_ptr<Subspace>(subspace)) );
643 }
644
645 for (size_t dim = 1; dim<=subspacelimit;++dim) {
646 BOOST_FOREACH( SubspaceMap::value_type subspace, Dimension_to_Indexset.equal_range(dim)) {
647 if (dim != 0) { // from level 1 and onward
648 BOOST_FOREACH( SubspaceMap::value_type entry, Dimension_to_Indexset.equal_range(dim-1)) {
649 if (subspace.second->contains(*entry.second)) {
650 // if contained then add ...
651 subspace.second->addSubset(entry.second);
652 // ... and also its containees as they are all automatically contained as well
653 BOOST_FOREACH(boost::shared_ptr<Subspace> iter, entry.second->SubIndices) {
654 subspace.second->addSubset(iter);
655 }
656 }
657 }
658 }
659 }
660 }
661 DoLog(0) && (Log() << Verbose(0) << "Sub space generation took " << Time_generatingsubspaces.elapsed() << " seconds." << std::endl);
662
663 // create a file handle for the eigenvalues
664 std::ofstream outputvalues("eigenvalues.dat", std::ios_base::trunc);
665 ASSERT(outputvalues.good(),
666 "SubspaceFactorizerUnittest::EigenvectorTest() - failed to open eigenvalue file!");
667 outputvalues << "# iteration ";
668 BOOST_FOREACH(size_t iter, AllIndices) {
669 outputvalues << "\teigenvalue" << iter;
670 }
671 outputvalues << std::endl;
672
673 DoLog(0) && (Log() << Verbose(0) << "Solving ..." << std::endl);
674 boost::timer Time_solving;
675 size_t run=1; // counting iterations
676 double threshold = 1.; // containing threshold value
677 while ((threshold > MYEPSILON) && (run < 20)) {
678 // for every dimension
679 for (size_t dim = 1; dim <= subspacelimit;++dim) {
680 // for every index set of this dimension
681 DoLog(1) && (Log() << Verbose(1) << std::endl << std::endl);
682 DoLog(1) && (Log() << Verbose(1) << "Current dimension is " << dim << std::endl);
683 std::pair<SubspaceMap::const_iterator,SubspaceMap::const_iterator> Bounds = Dimension_to_Indexset.equal_range(dim);
684 for (SubspaceMap::const_iterator IndexsetIter = Bounds.first;
685 IndexsetIter != Bounds.second;
686 ++IndexsetIter) {
687 Subspace& subspace = *(IndexsetIter->second);
688 // show the index set
689 DoLog(2) && (Log() << Verbose(2) << std::endl);
690 DoLog(2) && (Log() << Verbose(2) << "Current subspace is " << subspace << std::endl);
691
692 // solve
693 subspace.calculateEigenSubspace();
694
695 // note that assignment to global eigenvectors all remains within subspace
696 }
697 }
698
699 // print list of similar eigenvectors
700 DoLog(2) && (Log() << Verbose(2) << std::endl);
701 BOOST_FOREACH( size_t index, AllIndices) {
702 DoLog(2) && (Log() << Verbose(2) << "Similar to " << index << "th current eigenvector " << *(CurrentEigenvectors[index]) << " are:" << std::endl);
703 BOOST_FOREACH( SubspaceMap::value_type iter, Dimension_to_Indexset) {
704 const VectorContent & CurrentEV = (iter.second)->getEigenvectorParallelToFullOne(index);
705 if (!CurrentEV.IsZero())
706 Log() << Verbose(2)
707 << "dim" << iter.first
708 << ", subspace{" << (iter.second)->getIndices()
709 << "}: "<<CurrentEV << std::endl;
710 }
711 DoLog(2) && (Log() << Verbose(2) << std::endl);
712 }
713
714 // create new CurrentEigenvectors from averaging parallel ones.
715 BOOST_FOREACH(size_t index, AllIndices) {
716 CurrentEigenvectors[index]->setZero();
717 CurrentEigenvalues[index] = 0.;
718 size_t count = 0;
719 BOOST_FOREACH( SubspaceMap::value_type iter, Dimension_to_Indexset) {
720 const VectorContent CurrentEV = (iter.second)->getEigenvectorParallelToFullOne(index);
721 *CurrentEigenvectors[index] += CurrentEV; // * (iter.second)->getEigenvalueOfEigenvectorParallelToFullOne(index);
722 CurrentEigenvalues[index] += (iter.second)->getEigenvalueOfEigenvectorParallelToFullOne(index);
723 if (!CurrentEV.IsZero())
724 count++;
725 }
726 *CurrentEigenvectors[index] *= 1./CurrentEigenvalues[index];
727 //CurrentEigenvalues[index] /= (double)count;
728 }
729
730 // check orthonormality
731 threshold = calculateOrthogonalityThreshold(AllIndices, CurrentEigenvectors);
732 bool dontOrthonormalization = checkOrthogonality(AllIndices, CurrentEigenvectors);
733
734 // orthonormalize
735 if (!dontOrthonormalization) {
736 DoLog(1) && (Log() << Verbose(1) << "Orthonormalizing ... " << std::endl);
737 for (IndexSet::const_iterator firstindex = AllIndices.begin();
738 firstindex != AllIndices.end();
739 ++firstindex) {
740 for (IndexSet::const_iterator secondindex = firstindex;
741 secondindex != AllIndices.end();
742 ++secondindex) {
743 if (*firstindex == *secondindex) {
744 (*CurrentEigenvectors[*secondindex]) *= 1./(*CurrentEigenvectors[*secondindex]).Norm();
745 } else {
746 (*CurrentEigenvectors[*secondindex]) -=
747 ((*CurrentEigenvectors[*firstindex])*(*CurrentEigenvectors[*secondindex]))
748 *(*CurrentEigenvectors[*firstindex]);
749 }
750 }
751 }
752 }
753
754// // check orthonormality again
755// checkOrthogonality(AllIndices, CurrentEigenvectors);
756
757 // put obtained eigenvectors into full space
758 FullSpace.setEigenpairs(CurrentEigenvectors, CurrentEigenvalues);
759
760 // show new ones
761 DoLog(1) && (Log() << Verbose(1) << "Resulting new eigenvectors and -values, run " << run << " are:" << std::endl);
762 outputvalues << run;
763 BOOST_FOREACH( size_t index, AllIndices) {
764 DoLog(1) && (Log() << Verbose(1) << *CurrentEigenvectors[index] << " with " << CurrentEigenvalues[index] << std::endl);
765 outputvalues << "\t" << CurrentEigenvalues[index];
766 }
767 outputvalues << std::endl;
768
769 // and next iteration
770 DoLog(0) && (Log() << Verbose(0) << "\titeration #" << run << std::endl);
771 run++;
772 }
773 DoLog(0) && (Log() << Verbose(0) << "Solving took " << Time_solving.elapsed() << " seconds." << std::endl);
774 // show final ones
775 DoLog(0) && (Log() << Verbose(0) << "Resulting new eigenvectors and -values, run " << run << " are:" << std::endl);
776 outputvalues << run;
777 BOOST_FOREACH( size_t index, AllIndices) {
778 DoLog(0) && (Log() << Verbose(0) << *CurrentEigenvectors[index] << " with " << CurrentEigenvalues[index] << std::endl);
779 outputvalues << "\t" << CurrentEigenvalues[index];
780 }
781 outputvalues << std::endl;
782 outputvalues.close();
783
784 setVerbosity(2);
785
786 DoLog(0) && (Log() << Verbose(0) << "Solving full space ..." << std::endl);
787 boost::timer Time_comparison;
788 MatrixContent tempFullspaceMatrix = FullSpace.getEigenspaceMatrix();
789 gsl_vector *eigenvalues = tempFullspaceMatrix.transformToEigenbasis();
790 tempFullspaceMatrix.sortEigenbasis(eigenvalues);
791 DoLog(0) && (Log() << Verbose(0) << "full space solution took " << Time_comparison.elapsed() << " seconds." << std::endl);
792
793 // compare all
794 sort(CurrentEigenvalues.begin(),CurrentEigenvalues.end()); //, cmd);
795 for (size_t i=0;i<eigenvalues->size; ++i) {
796 CPPUNIT_ASSERT_MESSAGE(toString(i)+"ths eigenvalue differs:"
797 +toString(CurrentEigenvalues[i])+" != "+toString(gsl_vector_get(eigenvalues,i)),
798 fabs((CurrentEigenvalues[i] - gsl_vector_get(eigenvalues,i))/CurrentEigenvalues[i]) < 1e-3);
799 }
800
801 CPPUNIT_ASSERT_EQUAL(0,0);
802}
Note: See TracBrowser for help on using the repository browser.