source: src/LinearAlgebra/MatrixContent.cpp@ 9b410d

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

Replace MYEPSILON in LinearAlgebra/ by LINALG_MYEPSILON.

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