source: src/LinearAlgebra/MatrixContent.cpp@ b4cf2b

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 Candidate_v1.7.0 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 b4cf2b was b4cf2b, checked in by Frederik Heber <heber@…>, 15 years ago

First commit of SubspaceFactorizerUnitTest.

  • Property mode set to 100644
File size: 17.4 KB
Line 
1/*
2 * MatrixContent.cpp
3 *
4 * Created on: Nov 14, 2010
5 * Author: heber
6 */
7
8
9// include config.h
10#ifdef HAVE_CONFIG_H
11#include <config.h>
12#endif
13
14#include "Helpers/MemDebug.hpp"
15
16#include "LinearAlgebra/RealSpaceMatrix.hpp"
17#include "Helpers/Assert.hpp"
18#include "Exceptions/NotInvertibleException.hpp"
19#include "Helpers/fast_functions.hpp"
20#include "Helpers/Assert.hpp"
21#include "LinearAlgebra/Vector.hpp"
22#include "LinearAlgebra/VectorContent.hpp"
23#include "LinearAlgebra/MatrixContent.hpp"
24
25#include <gsl/gsl_blas.h>
26#include <gsl/gsl_eigen.h>
27#include <gsl/gsl_linalg.h>
28#include <gsl/gsl_matrix.h>
29#include <gsl/gsl_multimin.h>
30#include <gsl/gsl_vector.h>
31#include <cmath>
32#include <cassert>
33#include <iostream>
34#include <set>
35
36using namespace std;
37
38
39/** Constructor for class MatrixContent.
40 * \param rows number of rows
41 * \param columns number of columns
42 */
43MatrixContent::MatrixContent(size_t _rows, size_t _columns) :
44 rows(_rows),
45 columns(_columns)
46{
47 content = gsl_matrix_calloc(rows, columns);
48}
49
50/** Constructor for class MatrixContent.
51 * \param rows number of rows
52 * \param columns number of columns
53 * \param *src array with components to initialize matrix with
54 */
55MatrixContent::MatrixContent(size_t _rows, size_t _columns, const double *src) :
56 rows(_rows),
57 columns(_columns)
58{
59 content = gsl_matrix_calloc(rows, columns);
60 set(0,0, src[0]);
61 set(1,0, src[1]);
62 set(2,0, src[2]);
63
64 set(0,1, src[3]);
65 set(1,1, src[4]);
66 set(2,1, src[5]);
67
68 set(0,2, src[6]);
69 set(1,2, src[7]);
70 set(2,2, src[8]);
71}
72
73/** Constructor for class MatrixContent.
74 * We embed the given gls_matrix pointer within this class and set it to NULL
75 * afterwards.
76 * \param *src source gsl_matrix vector to embed within this class
77 */
78MatrixContent::MatrixContent(gsl_matrix *&src) :
79 rows(src->size1),
80 columns(src->size2)
81{
82 content = gsl_matrix_alloc(src->size1, src->size2);
83 gsl_matrix_memcpy(content,src);
84// content = src;
85// src = NULL;
86}
87
88/** Copy constructor for class MatrixContent.
89 * \param &src reference to source MatrixContent
90 */
91MatrixContent::MatrixContent(const MatrixContent &src) :
92 rows(src.rows),
93 columns(src.columns)
94{
95 content = gsl_matrix_alloc(src.rows, src.columns);
96 gsl_matrix_memcpy(content,src.content);
97}
98
99/** Copy constructor for class MatrixContent.
100 * \param *src pointer to source MatrixContent
101 */
102MatrixContent::MatrixContent(const MatrixContent *src) :
103 rows(src->rows),
104 columns(src->columns)
105{
106 ASSERT(src != NULL, "MatrixContent::MatrixContent - pointer to source matrix is NULL!");
107 content = gsl_matrix_alloc(src->rows, src->columns);
108 gsl_matrix_memcpy(content,src->content);
109}
110
111/** Destructor for class MatrixContent.
112 */
113MatrixContent::~MatrixContent()
114{
115 gsl_matrix_free(content);
116}
117
118/** Set matrix to identity.
119 */
120void MatrixContent::setIdentity()
121{
122 for(int i=rows;i--;){
123 for(int j=columns;j--;){
124 set(i,j,i==j);
125 }
126 }
127}
128
129/** Set all matrix components to zero.
130 */
131void MatrixContent::setZero()
132{
133 for(int i=rows;i--;){
134 for(int j=columns;j--;){
135 set(i,j,0.);
136 }
137 }
138}
139
140/** Set all matrix components to a given value.
141 * \param _value value to set each component to
142 */
143void MatrixContent::setValue(double _value)
144{
145 for(int i=rows;i--;){
146 for(int j=columns;j--;){
147 set(i,j,_value);
148 }
149 }
150}
151
152/** Copy operator for MatrixContent with self-assignment check.
153 * \param &src matrix to compare to
154 * \return reference to this
155 */
156MatrixContent &MatrixContent::operator=(const MatrixContent &src)
157{
158 if(&src!=this){
159 gsl_matrix_memcpy(content,src.content);
160 }
161 return *this;
162}
163
164/** Addition operator.
165 * \param &rhs matrix to add
166 * \return reference to this
167 */
168const MatrixContent &MatrixContent::operator+=(const MatrixContent &rhs)
169{
170 gsl_matrix_add(content, rhs.content);
171 return *this;
172}
173
174/** Subtraction operator.
175 * \param &rhs matrix to subtract
176 * \return reference to this
177 */
178const MatrixContent &MatrixContent::operator-=(const MatrixContent &rhs)
179 {
180 gsl_matrix_sub(content, rhs.content);
181 return *this;
182}
183
184/** Multiplication operator.
185 * Note that here matrix have to have same dimensions.
186 * \param &rhs matrix to multiply with
187 * \return reference to this
188 */
189const MatrixContent &MatrixContent::operator*=(const MatrixContent &rhs)
190{
191 ASSERT(rows == rhs.rows,
192 "MatrixContent::operator*=() - row dimension differ: "+toString(rows)+" != "+toString(rhs.rows)+".");
193 ASSERT(columns == rhs.columns,
194 "MatrixContent::operator*=() - columns dimension differ: "+toString(columns)+" != "+toString(rhs.columns)+".");
195 (*this) = (*this)*rhs;
196 return *this;
197}
198
199/** Multiplication with copy operator.
200 * \param &rhs matrix to multiply with
201 * \return reference to newly allocated MatrixContent
202 */
203const MatrixContent MatrixContent::operator*(const MatrixContent &rhs) const
204{
205 gsl_matrix *res = gsl_matrix_alloc(rows, rhs.columns);
206 gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, content, rhs.content, 0.0, res);
207 // gsl_matrix is taken over by constructor, hence no free
208 MatrixContent tmp(res);
209 gsl_matrix_free(res);
210 return tmp;
211}
212
213/* ========================== Accessing =============================== */
214
215/** Accessor for manipulating component (i,j).
216 * \param i row number
217 * \param j column number
218 * \return reference to component (i,j)
219 */
220double &MatrixContent::at(size_t i, size_t j)
221{
222 ASSERT((i>=0) && (i<rows),
223 "MatrixContent::at() - Index i="+toString(i)+" for Matrix access out of range [0,"+toString(rows)+"]");
224 ASSERT((j>=0) && (j<columns),
225 "MatrixContent::at() - Index j="+toString(j)+" for Matrix access out of range [0,"+toString(columns)+"]");
226 return *gsl_matrix_ptr (content, i, j);
227}
228
229/** Constant accessor for (value of) component (i,j).
230 * \param i row number
231 * \param j column number
232 * \return const component (i,j)
233 */
234const double MatrixContent::at(size_t i, size_t j) const
235{
236 ASSERT((i>=0) && (i<rows),
237 "MatrixContent::at() - Index i="+toString(i)+" for Matrix access out of range [0,"+toString(rows)+"]");
238 ASSERT((j>=0) && (j<columns),
239 "MatrixContent::at() - Index j="+toString(j)+" for Matrix access out of range [0,"+toString(columns)+"]");
240 return gsl_matrix_get(content, i, j);
241}
242
243/** These functions return a pointer to the \a m-th element of a matrix.
244 * If \a m or \a n lies outside the allowed range of 0 to MatrixContent::dimension-1 then the error handler is invoked and a null pointer is returned.
245 * \param m index
246 * \return pointer to \a m-th element
247 */
248double *MatrixContent::Pointer(size_t m, size_t n)
249{
250 return gsl_matrix_ptr (content, m, n);
251};
252
253/** These functions return a constant pointer to the \a m-th element of a matrix.
254 * If \a m or \a n lies outside the allowed range of 0 to MatrixContent::dimension-1 then the error handler is invoked and a null pointer is returned.
255 * \param m index
256 * \return const pointer to \a m-th element
257 */
258const double *MatrixContent::const_Pointer(size_t m, size_t n) const
259{
260 return gsl_matrix_const_ptr (content, m, n);
261};
262
263/* ========================== Initializing =============================== */
264
265/** Setter for component (i,j).
266 * \param i row numbr
267 * \param j column numnber
268 * \param value value to set componnt (i,j) to
269 */
270void MatrixContent::set(size_t i, size_t j, const double value)
271{
272 ASSERT((i>=0) && (i<rows),
273 "MatrixContent::set() - Index i="+toString(i)+" for Matrix access out of range [0,"+toString(rows)+"]");
274 ASSERT((j>=0) && (j<columns),
275 "MatrixContent::set() - Index j="+toString(j)+" for Matrix access out of range [0,"+toString(columns)+"]");
276 gsl_matrix_set(content,i,j,value);
277}
278
279/** This function sets the matrix from a double array.
280 * Creates a matrix view of the array and performs a memcopy.
281 * \param *x array of values (no dimension check is performed)
282 */
283void MatrixContent::setFromDoubleArray(double * x)
284{
285 gsl_matrix_view m = gsl_matrix_view_array (x, rows, columns);
286 gsl_matrix_memcpy (content, &m.matrix);
287};
288
289/* ====================== Exchanging elements ============================ */
290/** This function exchanges the \a i-th and \a j-th row of the matrix in-place.
291 * \param i i-th row to swap with ...
292 * \param j ... j-th row to swap against
293 */
294bool MatrixContent::SwapRows(size_t i, size_t j)
295{
296 return (gsl_matrix_swap_rows (content, i, j) == GSL_SUCCESS);
297};
298
299/** This function exchanges the \a i-th and \a j-th column of the matrix in-place.
300 * \param i i-th column to swap with ...
301 * \param j ... j-th column to swap against
302 */
303bool MatrixContent::SwapColumns(size_t i, size_t j)
304{
305 return (gsl_matrix_swap_columns (content, i, j) == GSL_SUCCESS);
306};
307
308/** This function exchanges the \a i-th row and \a j-th column of the matrix in-place.
309 * The matrix must be square for this operation to be possible.
310 * \param i i-th row to swap with ...
311 * \param j ... j-th column to swap against
312 */
313bool MatrixContent::SwapRowColumn(size_t i, size_t j)
314{
315 assert (rows == columns && "The matrix must be square for swapping row against column to be possible.");
316 return (gsl_matrix_swap_rowcol (content, i, j) == GSL_SUCCESS);
317};
318
319/** Return transposed matrix.
320 * \return new matrix that is transposed of this.
321 */
322MatrixContent MatrixContent::transpose() const
323{
324 gsl_matrix *res = gsl_matrix_alloc(columns, rows); // column and row dimensions exchanged!
325 gsl_matrix_transpose_memcpy(res, content);
326 MatrixContent newContent(res);
327 gsl_matrix_free(res);
328 return newContent;
329}
330
331/** Turn this matrix into its transposed.
332 * Note that this is only possible if rows == columns.
333 */
334MatrixContent &MatrixContent::transpose()
335{
336 ASSERT( rows == columns,
337 "MatrixContent::transpose() - cannot transpose onto itself as matrix not square: "+toString(rows)+"!="+toString(columns)+"!");
338 double tmp;
339 for (size_t i=0;i<rows;i++)
340 for (size_t j=i+1;j<rows;j++) {
341 tmp = at(j,i);
342 at(j,i) = at(i,j);
343 at(i,j) = tmp;
344 }
345 return *this;
346}
347
348/** Transform the matrix to its eigenbasis ans return resulting eigenvalues.
349 * Note that we only return real-space part in case of non-symmetric matrix.
350 * \warn return vector has to be freed'd
351 * TODO: encapsulate return value in boost::shared_ptr or in VectorContent.
352 * \return gsl_vector pointer to vector of eigenvalues
353 */
354gsl_vector* MatrixContent::transformToEigenbasis()
355{
356 if (rows == columns) { // symmetric
357 gsl_eigen_symmv_workspace *T = gsl_eigen_symmv_alloc(rows);
358 gsl_vector *eval = gsl_vector_alloc(rows);
359 gsl_matrix *evec = gsl_matrix_alloc(rows, rows);
360 gsl_eigen_symmv(content, eval, evec, T);
361 gsl_eigen_symmv_free(T);
362 gsl_matrix_memcpy(content, evec);
363 gsl_matrix_free(evec);
364 return eval;
365 } else { // non-symmetric
366 //ASSERT(false, "MatrixContent::transformToEigenbasis() - only implemented for square matrices: "+toString(rows)+"!="+toString(columns)+"!");
367
368 // blow up gsl_matrix in content to square matrix, fill other components with zero
369 const size_t greaterDimension = rows > columns ? rows : columns;
370 gsl_matrix *content_square = gsl_matrix_alloc(greaterDimension, greaterDimension);
371 for (size_t i=0; i<greaterDimension; i++) {
372 for (size_t j=0; j<greaterDimension; j++) {
373 const double value = ((i < rows) && (j < columns)) ? gsl_matrix_get(content,i,j) : 0.;
374 gsl_matrix_set(content_square, i,j, value);
375 }
376 }
377
378 // solve eigenvalue problem
379 gsl_eigen_nonsymmv_workspace *T = gsl_eigen_nonsymmv_alloc(rows);
380 gsl_vector_complex *eval = gsl_vector_complex_alloc(greaterDimension);
381 gsl_matrix_complex *evec = gsl_matrix_complex_alloc(greaterDimension, greaterDimension);
382 gsl_eigen_nonsymmv(content_square, eval, evec, T);
383 gsl_eigen_nonsymmv_free(T);
384
385 // copy eigenvectors real-parts into content_square and display
386 std::cout << "Resulting eigenvector matrix is [";
387 for (size_t i=0; i<greaterDimension; i++) {
388 for (size_t j=0; j<greaterDimension; j++) {
389 std::cout << "(" << GSL_REAL(gsl_matrix_complex_get(evec,i,j))
390 << "," << GSL_IMAG(gsl_matrix_complex_get(evec,i,j)) << ")";
391 if (j < greaterDimension-1)
392 std::cout << " ";
393 gsl_matrix_set(content_square, i,j, GSL_REAL(gsl_matrix_complex_get(evec,i,j)));
394 }
395 if (i < greaterDimension-1)
396 std::cout << "; ";
397 }
398 std::cout << "]" << std::endl;
399
400 // scan for zero rows and columns to drop
401 std::set<size_t> RowDropList;
402 std::set<size_t> ColumnDropList;
403 for (size_t i=0; i<greaterDimension; i++) { // only copy real space part
404 double Rsum = 0.;
405 double Csum = 0.;
406 for (size_t j=0; j<greaterDimension; j++) {
407 Rsum += fabs(GSL_REAL(gsl_matrix_complex_get(evec,i,j)));
408 Csum += fabs(GSL_REAL(gsl_matrix_complex_get(evec,j,i)));
409 }
410 Rsum /= (double)greaterDimension;
411 Csum /= (double)greaterDimension;
412 if (Rsum < MYEPSILON)
413 RowDropList.insert(i);
414 if (Csum < MYEPSILON)
415 ColumnDropList.insert(i);
416 }
417
418 // copy real-parts of complex eigenvalues and eigenvectors
419 gsl_vector *eval_real = gsl_vector_alloc(greaterDimension);
420 size_t I=0;
421 size_t J=0;
422 for (size_t i=0; i<greaterDimension; i++) { // only copy real space part
423 if (RowDropList.find(i) == RowDropList.end()) {
424 for (size_t j=0; j<greaterDimension; j++) {
425 if (ColumnDropList.find(j) == ColumnDropList.end()) {
426 if (fabs(GSL_IMAG(gsl_matrix_complex_get(evec,i,j))) > MYEPSILON)
427 std::cerr << "MatrixContent::transformToEigenbasis() - WARNING: eigenvectors are complex-valued!" << std::endl;
428 gsl_matrix_set(content, I,J, GSL_REAL(gsl_matrix_complex_get(evec,i,j)));
429 J++;
430 }
431 }
432 if (fabs(GSL_IMAG(gsl_vector_complex_get(eval,I))) > MYEPSILON)
433 std::cerr << "MatrixContent::transformToEigenbasis() - WARNING: eigenvectors are complex-valued!" << std::endl;
434 gsl_vector_set(eval_real, I, GSL_REAL(gsl_vector_complex_get(eval, i)));
435 I++;
436 }
437 }
438 gsl_matrix_complex_free(evec);
439 gsl_vector_complex_free(eval);
440 return eval_real;
441 }
442}
443
444/* ============================ Properties ============================== */
445/** Checks whether matrix' elements are strictly null.
446 * \return true - is null, false - else
447 */
448bool MatrixContent::IsNull() const
449{
450 return gsl_matrix_isnull (content);
451};
452
453/** Checks whether matrix' elements are strictly positive.
454 * \return true - is positive, false - else
455 */
456bool MatrixContent::IsPositive() const
457{
458 return gsl_matrix_ispos (content);
459};
460
461/** Checks whether matrix' elements are strictly negative.
462 * \return true - is negative, false - else
463 */
464bool MatrixContent::IsNegative() const
465{
466 return gsl_matrix_isneg (content);
467};
468
469/** Checks whether matrix' elements are strictly non-negative.
470 * \return true - is non-negative, false - else
471 */
472bool MatrixContent::IsNonNegative() const
473{
474 return gsl_matrix_isnonneg (content);
475};
476
477/** This function performs a Cholesky decomposition to determine whether matrix is positive definite.
478 * We check whether GSL returns GSL_EDOM as error, indicating that decomposition failed due to matrix not being positive-definite.
479 * \return true - matrix is positive-definite, false - else
480 */
481bool MatrixContent::IsPositiveDefinite() const
482{
483 if (rows != columns) // only possible for square matrices.
484 return false;
485 else
486 return (gsl_linalg_cholesky_decomp (content) != GSL_EDOM);
487};
488
489
490/** Calculates the determinant of the matrix.
491 * if matrix is square, uses LU decomposition.
492 */
493double MatrixContent::Determinant() const
494{
495 int signum = 0;
496 assert (rows == columns && "Determinant can only be calculated for square matrices.");
497 gsl_permutation *p = gsl_permutation_alloc(rows);
498 gsl_linalg_LU_decomp(content, p, &signum);
499 gsl_permutation_free(p);
500 return gsl_linalg_LU_det(content, signum);
501};
502
503/* ============================= Operators =============================== */
504
505/** Scalar multiplication operator.
506 * \param factor factor to scale with
507 */
508const MatrixContent &MatrixContent::operator*=(const double factor)
509{
510 gsl_matrix_scale(content, factor);
511 return *this;
512}
513
514/** Scalar multiplication and copy operator.
515 * \param factor factor to scale with
516 * \param &mat MatrixContent to scale
517 * \return copied and scaled MatrixContent
518 */
519const MatrixContent operator*(const double factor,const MatrixContent& mat)
520{
521 MatrixContent tmp = mat;
522 tmp*=factor;
523 return tmp;
524}
525
526/** Scalar multiplication and copy operator (with operands exchanged).
527 * \param &mat MatrixContent to scale
528 * \param factor factor to scale with
529 * \return copied and scaled MatrixContent
530 */
531const MatrixContent operator*(const MatrixContent &mat,const double factor)
532{
533 return factor*mat;
534}
535
536/** Equality operator.
537 * Note that we use numerical sensible checking, i.e. with threshold MYEPSILON.
538 * \param &rhs MatrixContent to checks against
539 */
540bool MatrixContent::operator==(const MatrixContent &rhs) const
541 {
542 if ((rows == rhs.rows) && (columns == rhs.columns)) {
543 for(int i=rows;i--;){
544 for(int j=columns;j--;){
545 if(fabs(at(i,j)-rhs.at(i,j))>MYEPSILON){
546 return false;
547 }
548 }
549 }
550 return true;
551 }
552 return false;
553}
554
555Vector operator*(const MatrixContent &mat,const Vector &vec)
556{
557 Vector result;
558 gsl_blas_dgemv( CblasNoTrans, 1.0, mat.content, vec.content->content, 0.0, result.content->content);
559 return result;
560}
561
562std::ostream & operator<<(std::ostream &ost, const MatrixContent &mat)
563{
564 ost << "[";
565 for (size_t i=0;i<mat.rows;i++) {
566 for (size_t j=0;j<mat.columns;j++) {
567 ost << mat.at(i,j);
568 if (j != mat.columns-1)
569 ost << " ";
570 }
571 if (i != mat.rows-1)
572 ost << "; ";
573 }
574 ost << "]";
575 return ost;
576}
Note: See TracBrowser for help on using the repository browser.