source: src/LinearAlgebra/Subspace.cpp@ 286af5f

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

SubspaceFactorizerUnittest::SubspaceTest() - fully working compared to EigenvectorTest().

  • we also have an iteration and the results are exactly the same for a 3x3 matrix at run 2 and 9.
  • classes Eigenspace and Subspace are thus for now fully working.
  • Property mode set to 100644
File size: 14.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 * Subspace.cpp
10 *
11 * Created on: Nov 22, 2010
12 * Author: heber
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include "Helpers/MemDebug.hpp"
21
22#include <boost/shared_ptr.hpp>
23#include <boost/foreach.hpp>
24
25#include "Helpers/Assert.hpp"
26#include "Helpers/Log.hpp"
27#include "Helpers/toString.hpp"
28#include "Helpers/Verbose.hpp"
29
30#include "Eigenspace.hpp"
31#include "Subspace.hpp"
32
33
34/** Constructor for class Subspace.
35 *
36 * @param _s indices that make up this subspace
37 * @param _FullSpace reference to the full eigenspace
38 */
39Subspace::Subspace(indexset & _s, Eigenspace &_FullSpace) :
40 Eigenspace(_s),
41 ProjectToSubspace(_FullSpace.getIndices().size(), _s.size()),
42 ProjectFromSubspace(_s.size(), _FullSpace.getIndices().size()),
43 FullSpace(_FullSpace),
44 ZeroVector(_FullSpace.getIndices().size())
45{
46 // TODO: away with both of this when calculateEigenSubspace() works
47 // create projection matrices
48 createProjectionMatrices();
49
50 // create eigenspace matrices
51 projectFullSpaceMatrixToSubspace();
52}
53
54
55/** Destructor for class Subspace.
56 *
57 */
58Subspace::~Subspace()
59{}
60
61
62/** Diagonalizes the subspace matrix.
63 *
64 * @param fullmatrix full matrix to project into subspace and solve
65 */
66void Subspace::calculateEigenSubspace()
67{
68 // project down
69 createProjectionMatrices();
70 // remove subsubspace directions
71 correctEigenvectorsFromSubIndices();
72 // solve
73 projectFullSpaceMatrixToSubspace();
74 EigenvectorMatrix = EigenspaceMatrix;
75 VectorContent *EigenvalueVector = new VectorContent(EigenvectorMatrix.transformToEigenbasis());
76 Eigenvalues.clear();
77 for(size_t i = 0; i< EigenvalueVector->getDimension(); ++i) {
78 Eigenvalues.push_back( EigenvalueVector->at(i) );
79 }
80 delete EigenvalueVector;
81 Log() << Verbose(2) << "Eigenvector matrix is " << EigenvectorMatrix << std::endl;
82 Log() << Verbose(2) << "Eigenvalues are " << Eigenvalues << std::endl;
83 // create mapping
84 createLocalMapping();
85}
86
87
88/** Projects a given full matrix down into the subspace of this class.
89 *
90 * @param bigmatrix full matrix to project into subspace
91 */
92void Subspace::getSubspacematrixFromBigmatrix(const MatrixContent & bigmatrix)
93{
94 // check whether subsystem is big enough for both index sets
95 ASSERT(Indices.size() <= bigmatrix.getRows(),
96 "embedEigenspaceMatrix() - bigmatrix has less rows "+toString(bigmatrix.getRows())
97 +" than needed by index set "
98 +toString(Indices.size())+"!");
99 ASSERT(Indices.size() <= bigmatrix.getColumns(),
100 "embedEigenspaceMatrix() - bigmatrix has less columns "+toString(bigmatrix.getColumns())
101 +" than needed by index set "
102 +toString(Indices.size())+"!");
103
104 // construct small matrix
105 MatrixContent *subsystem = new MatrixContent(Indices.size(), Indices.size());
106 size_t localrow = 0; // local row indices for the subsystem
107 size_t localcolumn = 0;
108 BOOST_FOREACH( size_t rowindex, Indices) {
109 localcolumn = 0;
110 BOOST_FOREACH( size_t columnindex, Indices) {
111 ASSERT((rowindex < bigmatrix.getRows()) && (columnindex < bigmatrix.getColumns()),
112 "current index pair ("
113 +toString(rowindex)+","+toString(columnindex)
114 +") is out of bounds of bigmatrix ("
115 +toString(bigmatrix.getRows())+","+toString(bigmatrix.getColumns())
116 +")");
117 subsystem->at(localrow,localcolumn) = (*Eigenvectors[rowindex]) * (bigmatrix * (*Eigenvectors[columnindex]));
118 localcolumn++;
119 }
120 localrow++;
121 }
122}
123
124
125void Subspace::correctEigenvectorsFromSubIndices()
126{
127}
128
129
130/** Creates the inverse of LocalToGlobal.
131 * Mapping is one-to-one and onto, hence it's simply turning around the map.
132 */
133void Subspace::invertLocalToGlobalMapping()
134{
135 GlobalToLocal.clear();
136 for (mapping::const_iterator iter = LocalToGlobal.begin();
137 iter != LocalToGlobal.end();
138 ++iter) {
139 GlobalToLocal.insert( make_pair(iter->second, iter->first) );
140 }
141}
142
143
144/** Project calculated Eigenvectors into full space.
145 *
146 * @return set of projected eigenvectors.
147 */
148const Eigenspace::eigenvectorset & Subspace::getEigenvectorsInFullSpace()
149{
150 // check whether bigmatrix is at least as big as EigenspaceMatrix
151 ASSERT(Eigenvectors.size() > 0,
152 "embedEigenspaceMatrix() - no Eigenvectors given!");
153 ASSERT(EigenspaceMatrix.getRows() <= Eigenvectors[0]->getDimension(),
154 "embedEigenspaceMatrix() - EigenspaceMatrix has more rows "
155 +toString(EigenspaceMatrix.getRows())+" than eigenvectors "
156 +toString(Eigenvectors[0]->getDimension())+"!");
157 ASSERT(EigenspaceMatrix.getColumns() <= Eigenvectors.size(),
158 "embedEigenspaceMatrix() - EigenspaceMatrix has more columns "
159 +toString(EigenspaceMatrix.getColumns())+" than eigenvectors "
160 +toString(Eigenvectors.size())+"!");
161 // check whether EigenspaceMatrix is big enough for both index sets
162 ASSERT(EigenspaceMatrix.getColumns() == EigenspaceMatrix.getRows(),
163 "embedEigenspaceMatrix() - EigenspaceMatrix is not square "
164 +toString(EigenspaceMatrix.getRows())+" than needed by index set "
165 +toString(EigenspaceMatrix.getColumns())+"!");
166 ASSERT(Indices.size() == EigenspaceMatrix.getColumns(),
167 "embedEigenspaceMatrix() - EigenspaceMatrix has not the same number of columns "
168 +toString(EigenspaceMatrix.getColumns())+" compared to the index set "
169 +toString(Indices.size())+"!");
170
171 // construct intermediate matrix
172 MatrixContent *intermediatematrix = new MatrixContent(Eigenvectors[0]->getDimension(), Indices.size());
173 size_t localcolumn = 0;
174 BOOST_FOREACH(size_t columnindex, Indices) {
175 // create two vectors from each row and copy assign them
176 boost::shared_ptr<VectorContent> srceigenvector(Eigenvectors[columnindex]);
177 boost::shared_ptr<VectorContent> desteigenvector(intermediatematrix->getColumnVector(localcolumn));
178 *desteigenvector = *srceigenvector;
179 localcolumn++;
180 }
181 // matrix product with eigenbasis EigenspaceMatrix matrix
182 *intermediatematrix *= EigenspaceMatrix;
183
184 // and place at right columns into bigmatrix
185 MatrixContent *bigmatrix = new MatrixContent(Eigenvectors[0]->getDimension(), Eigenvectors.size());
186 bigmatrix->setZero();
187 localcolumn = 0;
188 BOOST_FOREACH(size_t columnindex, Indices) {
189 // create two vectors from each row and copy assign them
190 boost::shared_ptr<VectorContent> srceigenvector(intermediatematrix->getColumnVector(localcolumn));
191 boost::shared_ptr<VectorContent> desteigenvector(bigmatrix->getColumnVector(columnindex));
192 *desteigenvector = *srceigenvector;
193 localcolumn++;
194 }
195
196 return Eigenvectors;
197}
198
199
200/** Remove a subset of indices from the SubIndices.
201 *
202 * @param _s subset to remove
203 * @return true - removed, false - not found
204 */
205bool Subspace::removeSubset(boost::shared_ptr<Subspace> &_s)
206{
207 if (SubIndices.count(_s) != 0) {
208 SubIndices.erase(_s);
209 return true;
210 } else {
211 return false;
212 }
213}
214
215/** Add a subspace set to SubIndices.
216 *
217 * @param _s subset to add
218 * @return true - not present before, false - has already been present
219 */
220bool Subspace::addSubset(boost::shared_ptr<Subspace> & _s)
221{
222 if (SubIndices.count(_s) != 0)
223 return false;
224 else {
225 SubIndices.insert(_s);
226 return true;
227 }
228}
229
230
231/** Simply a getter for Eigenvectors, as they are stored as subspace eigenvectors.
232 *
233 * @return set of eigenvectors in subspace
234 */
235const MatrixContent & Subspace::getEigenvectorMatrixInFullSpace()
236{
237 // check whether bigmatrix is at least as big as EigenspaceMatrix
238 ASSERT(EigenspaceMatrix.getRows() <= Eigenvectors[0]->getDimension(),
239 "embedEigenspaceMatrix() - EigenspaceMatrix has more rows "
240 +toString(EigenspaceMatrix.getRows())+" than eigenvectors "
241 +toString(Eigenvectors[0]->getDimension())+"!");
242 ASSERT(EigenspaceMatrix.getColumns() <= Eigenvectors.size(),
243 "embedEigenspaceMatrix() - EigenspaceMatrix has more columns "
244 +toString(EigenspaceMatrix.getColumns())+" than eigenvectors "
245 +toString(Eigenvectors.size())+"!");
246 // check whether EigenspaceMatrix is big enough for both index sets
247 ASSERT(EigenspaceMatrix.getColumns() == EigenspaceMatrix.getRows(),
248 "embedEigenspaceMatrix() - EigenspaceMatrix is not square "
249 +toString(EigenspaceMatrix.getRows())+" than needed by index set "
250 +toString(EigenspaceMatrix.getColumns())+"!");
251 ASSERT(Indices.size() == EigenspaceMatrix.getColumns(),
252 "embedEigenspaceMatrix() - EigenspaceMatrix has not the same number of columns "
253 +toString(EigenspaceMatrix.getColumns())+" compared to the index set "
254 +toString(Indices.size())+"!");
255
256 // construct intermediate matrix
257 MatrixContent *intermediatematrix = new MatrixContent(Eigenvectors[0]->getDimension(), Indices.size());
258 size_t localcolumn = 0;
259 BOOST_FOREACH(size_t columnindex, Indices) {
260 // create two vectors from each row and copy assign them
261 boost::shared_ptr<VectorContent> srceigenvector(Eigenvectors[columnindex]);
262 boost::shared_ptr<VectorContent> desteigenvector(intermediatematrix->getColumnVector(localcolumn));
263 *desteigenvector = *srceigenvector;
264 localcolumn++;
265 }
266 // matrix product with eigenbasis EigenspaceMatrix matrix
267 *intermediatematrix *= EigenspaceMatrix;
268
269 // and place at right columns into bigmatrix
270 MatrixContent *bigmatrix = new MatrixContent(Eigenvectors[0]->getDimension(), Eigenvectors.size());
271 bigmatrix->setZero();
272 localcolumn = 0;
273 BOOST_FOREACH(size_t columnindex, Indices) {
274 // create two vectors from each row and copy assign them
275 boost::shared_ptr<VectorContent> srceigenvector(intermediatematrix->getColumnVector(localcolumn));
276 boost::shared_ptr<VectorContent> desteigenvector(bigmatrix->getColumnVector(columnindex));
277 *desteigenvector = *srceigenvector;
278 localcolumn++;
279 }
280
281 return *bigmatrix;
282}
283
284
285/** Creates the projection matrix from Subspace::FullSpace::EigenvectorMatrix.
286 * We simply copy the respective eigenvectors from Subspace::FullSpace into
287 * Subspace::Eigenvectors.
288 */
289void Subspace::createProjectionMatrices()
290{
291 // first ProjectToSubspace
292
293 // generate column vectors
294 std::vector< boost::shared_ptr<VectorContent> > ColumnVectors;
295 for (size_t i = 0; i < Indices.size(); ++i) {
296 boost::shared_ptr<VectorContent> p(ProjectToSubspace.getColumnVector(i));
297 ColumnVectors.push_back( p );
298 }
299
300 // then copy from real eigenvectors
301 size_t localindex = 0;
302 BOOST_FOREACH(size_t iter, Indices) {
303 *ColumnVectors[localindex] = FullSpace.getEigenvector(iter);
304 localindex++;
305 }
306 Log() << Verbose(2) << "ProjectionToSubspace matrix is " << ProjectToSubspace << std::endl;
307
308 // then ProjectFromSubspace is just transposed
309 ProjectFromSubspace = ((const MatrixContent)ProjectToSubspace).transpose();
310 Log() << Verbose(2) << "ProjectFromSubspace matrix is " << ProjectFromSubspace << std::endl;
311}
312
313
314/** Creates the subspace matrix by projecting down the FullSpace::EigenspaceMatrix.
315 * We just perform \f$M = P^t \cdot A \cdot P\f$, when P are the projection matrix,
316 * A the full matrix and M the subspace matrix.
317 */
318void Subspace::projectFullSpaceMatrixToSubspace()
319{
320 // construct small matrix
321 EigenspaceMatrix = ProjectFromSubspace * FullSpace.getEigenspaceMatrix() * ProjectToSubspace;
322 Log() << Verbose(2) << "EigenspaceMatrix matrix is " << EigenspaceMatrix << std::endl;
323}
324
325
326/** We associate local Eigenvectors with ones from FullSpace by a paralellity
327 * criterion.
328 */
329void Subspace::createLocalMapping()
330{
331 // first LocalToGlobal
332 LocalToGlobal.clear();
333 IndexSet CorrespondenceList(Indices); // is to ensure one-to-one mapping
334
335 for (size_t localindex = 0; localindex< Indices.size(); ++localindex) {
336 boost::shared_ptr<VectorContent> &CurrentEigenvector = Eigenvectors[localindex];
337 Log() << Verbose(1) << "Current Eigenvector is " << *CurrentEigenvector << std::endl;
338
339 // (for now settle with the one we are most parallel to)
340 size_t mostparallel_index = FullSpace.getIndices().size();
341 double mostparallel_scalarproduct = 0.;
342 BOOST_FOREACH( size_t indexiter, CorrespondenceList) {
343 Log() << Verbose(2) << "Comparing to old " << indexiter << "th eigenvector " << FullSpace.getEigenvector(indexiter) << std::endl;
344 const double scalarproduct = (FullSpace.getEigenvector(indexiter)) * ( ProjectToSubspace * (*CurrentEigenvector));
345 Log() << Verbose(2) << "SKP is " << scalarproduct << std::endl;
346 if (fabs(scalarproduct) > fabs(mostparallel_scalarproduct)) {
347 mostparallel_scalarproduct = scalarproduct;
348 mostparallel_index = indexiter;
349 }
350 }
351 // and make the assignment if we found one
352 if (mostparallel_index != FullSpace.getIndices().size()) {
353 // put into std::list for later use
354 // invert if pointing in negative direction
355 if (mostparallel_scalarproduct < 0) {
356 *CurrentEigenvector *= -1.;
357 Log() << Verbose(1) << "Associating (inverted) " << *CurrentEigenvector << " with " << mostparallel_index << "th's fullspace eigenvector." << std::endl;
358 } else {
359 Log() << Verbose(1) << "Associating " << *CurrentEigenvector << " with " << mostparallel_index << "th's fullspace eigenvector." << std::endl;
360 }
361 ASSERT( LocalToGlobal.count(localindex) == 0,
362 "Subspace::createLocalMapping() - localindex "+toString(localindex)+" already assigned to "
363 +toString(LocalToGlobal[localindex])+" !=? "+toString(mostparallel_index)+".");
364 LocalToGlobal.insert( make_pair(localindex, mostparallel_index) );
365 CorrespondenceList.erase(mostparallel_index);
366 }
367 }
368
369 // then invert mapping
370 GlobalToLocal.clear();
371 BOOST_FOREACH(mapping::value_type iter, LocalToGlobal) {
372 ASSERT(GlobalToLocal.count(iter.second) == 0,
373 "Subspace::createLocalMapping() - LocalToGlobal is not bijective, key "
374 +toString(iter.second)+" present more than once!");
375 GlobalToLocal.insert( make_pair(iter.second, iter.first) );
376 }
377}
378
379
380/** Get the local eigenvector that is most parallel to the \a i'th full one.
381 * We just the internal mapping Subspace::GlobalToLocal.
382 * @param i index of global eigenvector
383 * @return local eigenvector, most parallel
384 */
385const VectorContent Subspace::getEigenvectorParallelToFullOne(size_t i)
386{
387 if (GlobalToLocal.count(i) == 0) {
388 return ZeroVector;
389 } else {
390 return ProjectToSubspace*(*Eigenvectors[GlobalToLocal[i]]);
391 }
392}
393
394
395/** Get the local eigenvalue of the eigenvector that is most parallel to the
396 * \a i'th full one.
397 * We just the internal mapping Subspace::GlobalToLocal.
398 * @param i index of global eigenvector
399 * @return eigenvalue of local eigenvector, most parallel
400 */
401const double Subspace::getEigenvalueOfEigenvectorParallelToFullOne(size_t i)
402{
403 if (GlobalToLocal.count(i) == 0) {
404 return 0.;
405 } else {
406 return Eigenvalues[GlobalToLocal[i]];
407 }
408}
Note: See TracBrowser for help on using the repository browser.