source: src/unittests/SubspaceFactorizerUnittest.cpp@ 4c1230

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