dune-istl 2.12-git
Loading...
Searching...
No Matches
arpackpp.hh
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root
2// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
3// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
4// vi: set et ts=4 sw=2 sts=2:
5#ifndef DUNE_ISTL_EIGENVALUE_ARPACKPP_HH
6#define DUNE_ISTL_EIGENVALUE_ARPACKPP_HH
7
8#if HAVE_ARPACKPP || defined DOXYGEN
9
10#include <cmath> // provides std::abs, std::pow, std::sqrt
11
12#include <iostream> // provides std::cout, std::endl
13#include <string> // provides std::string
14
15#include <dune/common/fvector.hh> // provides Dune::FieldVector
16#include <dune/common/exceptions.hh> // provides DUNE_THROW(...)
17
18#include <dune/istl/blocklevel.hh> // provides Dune::blockLevel
19#include <dune/istl/bvector.hh> // provides Dune::BlockVector
20#include <dune/istl/istlexception.hh> // provides Dune::ISTLError
21#include <dune/istl/io.hh> // provides Dune::printvector(...)
22
23#ifdef Status
24#undef Status // prevent preprocessor from damaging the ARPACK++
25 // code when "X11/Xlib.h" is included (the latter
26 // defines Status as "#define Status int" and
27 // ARPACK++ provides a class with a method called
28 // Status)
29#endif
30#include "arssym.h" // provides ARSymStdEig
31
32namespace Dune
33{
34
39 namespace Impl {
55 template <class BCRSMatrix>
56 class ArPackPlusPlus_BCRSMatrixWrapper;
57
58 template <class K, int N, int M>
60 class ArPackPlusPlus_BCRSMatrixWrapper<Dune::BCRSMatrix<FieldMatrix<K,N,M>>>
61 {
62 using BCRSMatrix = Dune::BCRSMatrix<FieldMatrix<K,N,M>>;
63
64 public:
66 typedef typename BCRSMatrix::field_type Real;
67
68 public:
70 ArPackPlusPlus_BCRSMatrixWrapper (const BCRSMatrix& A)
71 : A_(A),
72 m_(A_.M() * mBlock), n_(A_.N() * nBlock)
73 {
74 // assert that BCRSMatrix type has blocklevel 2
75 static_assert
76 (blockLevel<BCRSMatrix>() == 2,
77 "Only BCRSMatrices with blocklevel 2 are supported.");
78
79 // allocate memory for auxiliary block vector objects
80 // which are compatible to matrix rows / columns
81 domainBlockVector.resize(A_.N());
82 rangeBlockVector.resize(A_.M());
83 }
84
86 inline void multMv (Real* v, Real* w)
87 {
88 // get vector v as an object of appropriate type
89 arrayToDomainBlockVector(v,domainBlockVector);
90
91 // perform matrix-vector product
92 A_.mv(domainBlockVector,rangeBlockVector);
93
94 // get vector w from object of appropriate type
95 rangeBlockVectorToArray(rangeBlockVector,w);
96 };
97
99 inline void multMtMv (Real* v, Real* w)
100 {
101 // get vector v as an object of appropriate type
102 arrayToDomainBlockVector(v,domainBlockVector);
103
104 // perform matrix-vector product
105 A_.mv(domainBlockVector,rangeBlockVector);
106 A_.mtv(rangeBlockVector,domainBlockVector);
107
108 // get vector w from object of appropriate type
109 domainBlockVectorToArray(domainBlockVector,w);
110 };
111
113 inline void multMMtv (Real* v, Real* w)
114 {
115 // get vector v as an object of appropriate type
116 arrayToRangeBlockVector(v,rangeBlockVector);
117
118 // perform matrix-vector product
119 A_.mtv(rangeBlockVector,domainBlockVector);
120 A_.mv(domainBlockVector,rangeBlockVector);
121
122 // get vector w from object of appropriate type
123 rangeBlockVectorToArray(rangeBlockVector,w);
124 };
125
127 inline int nrows () const { return m_; }
128
130 inline int ncols () const { return n_; }
131
132 protected:
133 // Number of rows and columns in each block of the matrix
134 constexpr static int mBlock = BCRSMatrix::block_type::rows;
135 constexpr static int nBlock = BCRSMatrix::block_type::cols;
136
137 // Type of vectors in the domain of the linear map associated with
138 // the matrix, i.e. block vectors compatible to matrix rows
139 constexpr static int dbvBlockSize = nBlock;
140 typedef Dune::FieldVector<Real,dbvBlockSize> DomainBlockVectorBlock;
141 typedef Dune::BlockVector<DomainBlockVectorBlock> DomainBlockVector;
142
143 // Type of vectors in the range of the linear map associated with
144 // the matrix, i.e. block vectors compatible to matrix columns
145 constexpr static int rbvBlockSize = mBlock;
146 typedef Dune::FieldVector<Real,rbvBlockSize> RangeBlockVectorBlock;
147 typedef Dune::BlockVector<RangeBlockVectorBlock> RangeBlockVector;
148
149 // Types for vector index access
150 typedef typename DomainBlockVector::size_type dbv_size_type;
151 typedef typename RangeBlockVector::size_type rbv_size_type;
152 typedef typename DomainBlockVectorBlock::size_type dbvb_size_type;
153 typedef typename RangeBlockVectorBlock::size_type rbvb_size_type;
154
155 // Get vector v from a block vector object which is compatible to
156 // matrix rows
157 static inline void
158 domainBlockVectorToArray (const DomainBlockVector& dbv, Real* v)
159 {
160 for (dbv_size_type block = 0; block < dbv.N(); ++block)
161 for (dbvb_size_type iBlock = 0; iBlock < dbvBlockSize; ++iBlock)
162 v[block*dbvBlockSize + iBlock] = dbv[block][iBlock];
163 }
164
165 // Get vector v from a block vector object which is compatible to
166 // matrix columns
167 static inline void
168 rangeBlockVectorToArray (const RangeBlockVector& rbv, Real* v)
169 {
170 for (rbv_size_type block = 0; block < rbv.N(); ++block)
171 for (rbvb_size_type iBlock = 0; iBlock < rbvBlockSize; ++iBlock)
172 v[block*rbvBlockSize + iBlock] = rbv[block][iBlock];
173 }
174
175 public:
178 static inline void arrayToDomainBlockVector (const Real* v,
179 DomainBlockVector& dbv)
180 {
181 for (dbv_size_type block = 0; block < dbv.N(); ++block)
182 for (dbvb_size_type iBlock = 0; iBlock < dbvBlockSize; ++iBlock)
183 dbv[block][iBlock] = v[block*dbvBlockSize + iBlock];
184 }
185
188 static inline void arrayToRangeBlockVector (const Real* v,
189 RangeBlockVector& rbv)
190 {
191 for (rbv_size_type block = 0; block < rbv.N(); ++block)
192 for (rbvb_size_type iBlock = 0; iBlock < rbvBlockSize; ++iBlock)
193 rbv[block][iBlock] = v[block*rbvBlockSize + iBlock];
194 }
195
196 protected:
197 // The DUNE-ISTL BCRSMatrix
198 const BCRSMatrix& A_;
199
200 // Number of rows and columns in the matrix
201 const int m_, n_;
202
203 // Auxiliary block vector objects which are
204 // compatible to matrix rows / columns
205 mutable DomainBlockVector domainBlockVector;
206 mutable RangeBlockVector rangeBlockVector;
207 };
208
209
210 template <class K>
211 requires (Dune::IsNumber<K>::value)
212 class ArPackPlusPlus_BCRSMatrixWrapper<BCRSMatrix<K>>
213 {
214 using BCRSMatrix = Dune::BCRSMatrix<K>;
215
216 public:
218 typedef typename BCRSMatrix::field_type Real;
219
220 public:
222 ArPackPlusPlus_BCRSMatrixWrapper (const BCRSMatrix& A)
223 : A_(A),
224 m_(A_.M()), n_(A_.N())
225 {
226 // allocate memory for auxiliary vector objects
227 // which are compatible to matrix rows / columns
228 domainVector.resize(A_.N());
229 rangeVector.resize(A_.M());
230 }
231
233 inline void multMv (Real* v, Real* w)
234 {
235 // TODO: Use a span with DenseVector interface
236
237 // get vector v as an object of appropriate type
238 arrayToDomainBlockVector(v,domainVector);
239
240 // perform matrix-vector product
241 A_.mv(domainVector,rangeVector);
242
243 // get vector w from object of appropriate type
244 rangeVectorToArray(rangeVector,w);
245 };
246
248 inline void multMtMv (Real* v, Real* w)
249 {
250 // get vector v as an object of appropriate type
251 arrayToDomainBlockVector(v,domainVector);
252
253 // perform matrix-vector product
254 A_.mv(domainVector,rangeVector);
255 A_.mtv(rangeVector,domainVector);
256
257 // get vector w from object of appropriate type
258 domainVectorToArray(domainVector,w);
259 };
260
262 inline void multMMtv (Real* v, Real* w)
263 {
264 // get vector v as an object of appropriate type
265 arrayToRangeVector(v,rangeVector);
266
267 // perform matrix-vector product
268 A_.mtv(rangeVector,domainVector);
269 A_.mv(domainVector,rangeVector);
270
271 // get vector w from object of appropriate type
272 rangeVectorToArray(rangeVector,w);
273 };
274
276 inline int nrows () const { return m_; }
277
279 inline int ncols () const { return n_; }
280
281 protected:
282 // Type of vectors in the domain of the linear map associated with
283 typedef Dune::BlockVector<Real> DomainVector;
284
285 // Type of vectors in the range of the linear map associated with
286 typedef Dune::BlockVector<Real> RangeVector;
287
288 // Types for vector index access
289 typedef typename DomainVector::size_type dbv_size_type;
290 typedef typename RangeVector::size_type rbv_size_type;
291
292 // Get vector v from a block vector object which is compatible to
293 // matrix rows
294 static inline void
295 domainVectorToArray (const DomainVector& dbv, Real* v)
296 {
297 for (dbv_size_type i = 0; i < dbv.N(); ++i)
298 v[i] = dbv[i];
299 }
300
301 // Get vector v from a block vector object which is compatible to
302 // matrix columns
303 static inline void
304 rangeVectorToArray (const RangeVector& rbv, Real* v)
305 {
306 for (rbv_size_type i = 0; i < rbv.N(); ++i)
307 v[i] = rbv[i];
308 }
309
310 public:
313 static inline void arrayToDomainBlockVector (const Real* v,
314 DomainVector& dbv)
315 {
316 for (dbv_size_type i = 0; i < dbv.N(); ++i)
317 dbv[i] = v[i];
318 }
319
322 static inline void arrayToRangeBlockVector (const Real* v,
323 RangeVector& rbv)
324 {
325 for (rbv_size_type i = 0; i < rbv.N(); ++i)
326 rbv[i] = v[i];
327 }
328
329 protected:
330 // The DUNE-ISTL BCRSMatrix
331 const BCRSMatrix& A_;
332
333 // Number of rows and columns in the matrix
334 const int m_, n_;
335
336 // Auxiliary block vector objects which are
337 // compatible to matrix rows / columns
338 mutable DomainVector domainVector;
339 mutable RangeVector rangeVector;
340 };
341
342 } // end namespace Impl
343
383 template <typename BCRSMatrix, typename BlockVector>
385 {
386 public:
388
389 public:
409 const unsigned int nIterationsMax = 100000,
410 const unsigned int verbosity_level = 0)
411 : m_(m), nIterationsMax_(nIterationsMax),
412 verbosity_level_(verbosity_level),
413 nIterations_(0),
414 title_(" ArPackPlusPlus_Algorithms: "),
415 blank_(title_.length(),' ')
416 {}
417
429 inline void computeSymMaxMagnitude (const Real& epsilon,
430 BlockVector& x, Real& lambda) const
431 {
432 // print verbosity information
433 if (verbosity_level_ > 0)
434 std::cout << title_ << "Computing an approximation of "
435 << "the dominant eigenvalue of a matrix which "
436 << "is assumed to be symmetric." << std::endl;
437
438 // use type ArPackPlusPlus_BCRSMatrixWrapper to store matrix information
439 // and to perform the product A*v (LU decomposition is not used)
440 typedef Impl::ArPackPlusPlus_BCRSMatrixWrapper<BCRSMatrix> WrappedMatrix;
441 WrappedMatrix A(m_);
442
443 // get number of rows and columns in A
444 const int nrows = A.nrows();
445 const int ncols = A.ncols();
446
447 // assert that A is square
448 if (nrows != ncols)
449 DUNE_THROW(Dune::ISTLError,"Matrix is not square ("
450 << nrows << "x" << ncols << ").");
451
452 // allocate memory for variables, set parameters
453 const int nev = 1; // Number of eigenvalues to compute
454 int ncv = std::min(20, nrows); // Number of Arnoldi vectors generated at each iteration (0 == auto)
455 const Real tol = epsilon; // Stopping tolerance (relative accuracy of Ritz values) (0 == machine precision)
456 const int maxit = nIterationsMax_*nev; // Maximum number of Arnoldi update iterations allowed (0 == 100*nev)
457 Real* ev = new Real[nev]; // Computed eigenvalues of A
458 const bool ivec = true; // Flag deciding if eigenvectors shall be determined
459 int nconv; // Number of converged eigenvalues
460
461 // define what we need: eigenvalues with largest magnitude
462 char which[] = "LM";
463 ARSymStdEig<Real,WrappedMatrix>
464 dprob(nrows, nev, &A, &WrappedMatrix::multMv, which, ncv, tol, maxit);
465
466 // set ARPACK verbosity mode if requested
467 if (verbosity_level_ > 3) dprob.Trace();
468
469 // find eigenvalues and eigenvectors of A, obtain the eigenvalues
470 nconv = dprob.Eigenvalues(ev,ivec);
471
472 // obtain approximated dominant eigenvalue of A
473 lambda = ev[nev-1];
474
475 // obtain associated approximated eigenvector of A
476 Real* x_raw = dprob.RawEigenvector(nev-1);
477 WrappedMatrix::arrayToDomainBlockVector(x_raw,x);
478
479 // obtain number of Arnoldi update iterations actually taken
480 nIterations_ = dprob.GetIter();
481
482 // compute residual norm
483 BlockVector r(x);
484 Real* Ax_raw = new Real[nrows];
485 A.multMv(x_raw,Ax_raw);
486 WrappedMatrix::arrayToDomainBlockVector(Ax_raw,r);
487 r.axpy(-lambda,x);
488 const Real r_norm = r.two_norm();
489
490 // print verbosity information
491 if (verbosity_level_ > 0)
492 {
493 if (verbosity_level_ > 1)
494 {
495 // print some information about the problem
496 std::cout << blank_ << "Obtained eigenvalues of A by solving "
497 << "A*x = λ*x using the ARPACK++ class ARSym"
498 << "StdEig:" << std::endl;
499 std::cout << blank_ << " converged eigenvalues of A: "
500 << nconv << " / " << nev << std::endl;
501 std::cout << blank_ << " dominant eigenvalue of A: "
502 << lambda << std::endl;
503 }
504 std::cout << blank_ << "Result ("
505 << "#iterations = " << nIterations_ << ", "
506 << "║residual║_2 = " << r_norm << "): "
507 << "λ = " << lambda << std::endl;
508 if (verbosity_level_ > 2)
509 {
510 // print approximated eigenvector via DUNE-ISTL I/O methods
512 }
513 }
514
515 // free dynamically allocated memory
516 delete[] Ax_raw;
517 delete[] ev;
518 }
519
531 inline void computeSymMinMagnitude (const Real& epsilon,
532 BlockVector& x, Real& lambda) const
533 {
534 // print verbosity information
535 if (verbosity_level_ > 0)
536 std::cout << title_ << "Computing an approximation of the "
537 << "least dominant eigenvalue of a matrix which "
538 << "is assumed to be symmetric." << std::endl;
539
540 // use type ArPackPlusPlus_BCRSMatrixWrapper to store matrix information
541 // and to perform the product A*v (LU decomposition is not used)
542 typedef Impl::ArPackPlusPlus_BCRSMatrixWrapper<BCRSMatrix> WrappedMatrix;
543 WrappedMatrix A(m_);
544
545 // get number of rows and columns in A
546 const int nrows = A.nrows();
547 const int ncols = A.ncols();
548
549 // assert that A is square
550 if (nrows != ncols)
551 DUNE_THROW(Dune::ISTLError,"Matrix is not square ("
552 << nrows << "x" << ncols << ").");
553
554 // allocate memory for variables, set parameters
555 const int nev = 1; // Number of eigenvalues to compute
556 int ncv = std::min(20, nrows); // Number of Arnoldi vectors generated at each iteration (0 == auto)
557 const Real tol = epsilon; // Stopping tolerance (relative accuracy of Ritz values) (0 == machine precision)
558 const int maxit = nIterationsMax_*nev; // Maximum number of Arnoldi update iterations allowed (0 == 100*nev)
559 Real* ev = new Real[nev]; // Computed eigenvalues of A
560 const bool ivec = true; // Flag deciding if eigenvectors shall be determined
561 int nconv; // Number of converged eigenvalues
562
563 // define what we need: eigenvalues with smallest magnitude
564 char which[] = "SM";
565 ARSymStdEig<Real,WrappedMatrix>
566 dprob(nrows, nev, &A, &WrappedMatrix::multMv, which, ncv, tol, maxit);
567
568 // set ARPACK verbosity mode if requested
569 if (verbosity_level_ > 3) dprob.Trace();
570
571 // find eigenvalues and eigenvectors of A, obtain the eigenvalues
572 nconv = dprob.Eigenvalues(ev,ivec);
573
574 // obtain approximated least dominant eigenvalue of A
575 lambda = ev[nev-1];
576
577 // obtain associated approximated eigenvector of A
578 Real* x_raw = dprob.RawEigenvector(nev-1);
579 WrappedMatrix::arrayToDomainBlockVector(x_raw,x);
580
581 // obtain number of Arnoldi update iterations actually taken
582 nIterations_ = dprob.GetIter();
583
584 // compute residual norm
585 BlockVector r(x);
586 Real* Ax_raw = new Real[nrows];
587 A.multMv(x_raw,Ax_raw);
588 WrappedMatrix::arrayToDomainBlockVector(Ax_raw,r);
589 r.axpy(-lambda,x);
590 const Real r_norm = r.two_norm();
591
592 // print verbosity information
593 if (verbosity_level_ > 0)
594 {
595 if (verbosity_level_ > 1)
596 {
597 // print some information about the problem
598 std::cout << blank_ << "Obtained eigenvalues of A by solving "
599 << "A*x = λ*x using the ARPACK++ class ARSym"
600 << "StdEig:" << std::endl;
601 std::cout << blank_ << " converged eigenvalues of A: "
602 << nconv << " / " << nev << std::endl;
603 std::cout << blank_ << " least dominant eigenvalue of A: "
604 << lambda << std::endl;
605 }
606 std::cout << blank_ << "Result ("
607 << "#iterations = " << nIterations_ << ", "
608 << "║residual║_2 = " << r_norm << "): "
609 << "λ = " << lambda << std::endl;
610 if (verbosity_level_ > 2)
611 {
612 // print approximated eigenvector via DUNE-ISTL I/O methods
614 }
615 }
616
617 // free dynamically allocated memory
618 delete[] Ax_raw;
619 delete[] ev;
620 }
621
633 inline void computeSymCond2 (const Real& epsilon, Real& cond_2) const
634 {
635 // print verbosity information
636 if (verbosity_level_ > 0)
637 std::cout << title_ << "Computing an approximation of the "
638 << "spectral condition number of a matrix which "
639 << "is assumed to be symmetric." << std::endl;
640
641 // use type ArPackPlusPlus_BCRSMatrixWrapper to store matrix information
642 // and to perform the product A*v (LU decomposition is not used)
643 typedef Impl::ArPackPlusPlus_BCRSMatrixWrapper<BCRSMatrix> WrappedMatrix;
644 WrappedMatrix A(m_);
645
646 // get number of rows and columns in A
647 const int nrows = A.nrows();
648 const int ncols = A.ncols();
649
650 // assert that A is square
651 if (nrows != ncols)
652 DUNE_THROW(Dune::ISTLError,"Matrix is not square ("
653 << nrows << "x" << ncols << ").");
654
655 // allocate memory for variables, set parameters
656 const int nev = 2; // Number of eigenvalues to compute
657 int ncv = std::min(20, nrows); // Number of Arnoldi vectors generated at each iteration (0 == auto)
658 const Real tol = epsilon; // Stopping tolerance (relative accuracy of Ritz values) (0 == machine precision)
659 const int maxit = nIterationsMax_*nev; // Maximum number of Arnoldi update iterations allowed (0 == 100*nev)
660 Real* ev = new Real[nev]; // Computed eigenvalues of A
661 const bool ivec = true; // Flag deciding if eigenvectors shall be determined
662 int nconv; // Number of converged eigenvalues
663
664 // define what we need: eigenvalues from both ends of the spectrum
665 char which[] = "BE";
666 ARSymStdEig<Real,WrappedMatrix>
667 dprob(nrows, nev, &A, &WrappedMatrix::multMv, which, ncv, tol, maxit);
668
669 // set ARPACK verbosity mode if requested
670 if (verbosity_level_ > 3) dprob.Trace();
671
672 // find eigenvalues and eigenvectors of A, obtain the eigenvalues
673 nconv = dprob.Eigenvalues(ev,ivec);
674
675 // obtain approximated dominant and least dominant eigenvalue of A
676 const Real& lambda_max = ev[nev-1];
677 const Real& lambda_min = ev[0];
678
679 // obtain associated approximated eigenvectors of A
680 Real* x_max_raw = dprob.RawEigenvector(nev-1);
681 Real* x_min_raw = dprob.RawEigenvector(0);
682
683 // obtain approximated spectral condition number of A
684 cond_2 = std::abs(lambda_max / lambda_min);
685
686 // obtain number of Arnoldi update iterations actually taken
687 nIterations_ = dprob.GetIter();
688
689 // compute each residual norm
690 Real* Ax_max_raw = new Real[nrows];
691 Real* Ax_min_raw = new Real[nrows];
692 A.multMv(x_max_raw,Ax_max_raw);
693 A.multMv(x_min_raw,Ax_min_raw);
694 Real r_max_norm = 0.0;
695 Real r_min_norm = 0.0;
696 for (int i = 0; i < nrows; ++i)
697 {
698 r_max_norm += std::pow(Ax_max_raw[i] - lambda_max * x_max_raw[i],2);
699 r_min_norm += std::pow(Ax_min_raw[i] - lambda_min * x_min_raw[i],2);
700 }
701 r_max_norm = std::sqrt(r_max_norm);
702 r_min_norm = std::sqrt(r_min_norm);
703
704 // print verbosity information
705 if (verbosity_level_ > 0)
706 {
707 if (verbosity_level_ > 1)
708 {
709 // print some information about the problem
710 std::cout << blank_ << "Obtained eigenvalues of A by solving "
711 << "A*x = λ*x using the ARPACK++ class ARSym"
712 << "StdEig:" << std::endl;
713 std::cout << blank_ << " converged eigenvalues of A: "
714 << nconv << " / " << nev << std::endl;
715 std::cout << blank_ << " dominant eigenvalue of A: "
716 << lambda_max << std::endl;
717 std::cout << blank_ << " least dominant eigenvalue of A: "
718 << lambda_min << std::endl;
719 std::cout << blank_ << " spectral condition number of A: "
720 << cond_2 << std::endl;
721 }
722 std::cout << blank_ << "Result ("
723 << "#iterations = " << nIterations_ << ", "
724 << "║residual║_2 = {" << r_max_norm << ","
725 << r_min_norm << "}, " << "λ = {"
726 << lambda_max << "," << lambda_min
727 << "}): cond_2 = " << cond_2 << std::endl;
728 }
729
730 // free dynamically allocated memory
731 delete[] Ax_min_raw;
732 delete[] Ax_max_raw;
733 delete[] ev;
734 }
735
749 inline void computeNonSymMax (const Real& epsilon,
750 BlockVector& x, Real& sigma) const
751 {
752 // print verbosity information
753 if (verbosity_level_ > 0)
754 std::cout << title_ << "Computing an approximation of the "
755 << "largest singular value of a matrix which "
756 << "is assumed to be nonsymmetric." << std::endl;
757
758 // use type ArPackPlusPlus_BCRSMatrixWrapper to store matrix information
759 // and to perform the product A^T*A*v (LU decomposition is not used)
760 typedef Impl::ArPackPlusPlus_BCRSMatrixWrapper<BCRSMatrix> WrappedMatrix;
761 WrappedMatrix A(m_);
762
763 // get number of rows and columns in A
764 const int nrows = A.nrows();
765 const int ncols = A.ncols();
766
767 // assert that A has more rows than columns (extend code later to the opposite case!)
768 if (nrows < ncols)
769 DUNE_THROW(Dune::ISTLError,"Matrix has less rows than "
770 << "columns (" << nrows << "x" << ncols << ")."
771 << " This case is not implemented, yet.");
772
773 // allocate memory for variables, set parameters
774 const int nev = 1; // Number of eigenvalues to compute
775 int ncv = std::min(20, nrows); // Number of Arnoldi vectors generated at each iteration (0 == auto)
776 const Real tol = epsilon; // Stopping tolerance (relative accuracy of Ritz values) (0 == machine precision)
777 const int maxit = nIterationsMax_*nev; // Maximum number of Arnoldi update iterations allowed (0 == 100*nev)
778 Real* ev = new Real[nev]; // Computed eigenvalues of A^T*A
779 const bool ivec = true; // Flag deciding if eigenvectors shall be determined
780 int nconv; // Number of converged eigenvalues
781
782 // define what we need: eigenvalues with largest algebraic value
783 char which[] = "LA";
784 ARSymStdEig<Real,WrappedMatrix>
785 dprob(ncols, nev, &A, &WrappedMatrix::multMtMv, which, ncv, tol, maxit);
786
787 // set ARPACK verbosity mode if requested
788 if (verbosity_level_ > 3) dprob.Trace();
789
790 // find eigenvalues and eigenvectors of A^T*A, obtain the eigenvalues
791 nconv = dprob.Eigenvalues(ev,ivec);
792
793 // obtain approximated largest eigenvalue of A^T*A
794 const Real& lambda = ev[nev-1];
795
796 // obtain associated approximated eigenvector of A^T*A
797 Real* x_raw = dprob.RawEigenvector(nev-1);
798 WrappedMatrix::arrayToDomainBlockVector(x_raw,x);
799
800 // obtain number of Arnoldi update iterations actually taken
801 nIterations_ = dprob.GetIter();
802
803 // compute residual norm
804 BlockVector r(x);
805 Real* AtAx_raw = new Real[ncols];
806 A.multMtMv(x_raw,AtAx_raw);
807 WrappedMatrix::arrayToDomainBlockVector(AtAx_raw,r);
808 r.axpy(-lambda,x);
809 const Real r_norm = r.two_norm();
810
811 // calculate largest singular value of A (note that
812 // x is right-singular / left-singular vector of A)
813 sigma = std::sqrt(lambda);
814
815 // print verbosity information
816 if (verbosity_level_ > 0)
817 {
818 if (verbosity_level_ > 1)
819 {
820 // print some information about the problem
821 std::cout << blank_ << "Obtained singular values of A by sol"
822 << "ving (A^T*A)*x = σ²*x using the ARPACK++ "
823 << "class ARSymStdEig:" << std::endl;
824 std::cout << blank_ << " converged eigenvalues of A^T*A: "
825 << nconv << " / " << nev << std::endl;
826 std::cout << blank_ << " largest eigenvalue of A^T*A: "
827 << lambda << std::endl;
828 std::cout << blank_ << " => largest singular value of A: "
829 << sigma << std::endl;
830 }
831 std::cout << blank_ << "Result ("
832 << "#iterations = " << nIterations_ << ", "
833 << "║residual║_2 = " << r_norm << "): "
834 << "σ = " << sigma << std::endl;
835 if (verbosity_level_ > 2)
836 {
837 // print approximated right-singular / left-singular vector
838 // via DUNE-ISTL I/O methods
840 }
841 }
842
843 // free dynamically allocated memory
844 delete[] AtAx_raw;
845 delete[] ev;
846 }
847
861 inline void computeNonSymMin (const Real& epsilon,
862 BlockVector& x, Real& sigma) const
863 {
864 // print verbosity information
865 if (verbosity_level_ > 0)
866 std::cout << title_ << "Computing an approximation of the "
867 << "smallest singular value of a matrix which "
868 << "is assumed to be nonsymmetric." << std::endl;
869
870 // use type ArPackPlusPlus_BCRSMatrixWrapper to store matrix information
871 // and to perform the product A^T*A*v (LU decomposition is not used)
872 typedef Impl::ArPackPlusPlus_BCRSMatrixWrapper<BCRSMatrix> WrappedMatrix;
873 WrappedMatrix A(m_);
874
875 // get number of rows and columns in A
876 const int nrows = A.nrows();
877 const int ncols = A.ncols();
878
879 // assert that A has more rows than columns (extend code later to the opposite case!)
880 if (nrows < ncols)
881 DUNE_THROW(Dune::ISTLError,"Matrix has less rows than "
882 << "columns (" << nrows << "x" << ncols << ")."
883 << " This case is not implemented, yet.");
884
885 // allocate memory for variables, set parameters
886 const int nev = 1; // Number of eigenvalues to compute
887 int ncv = std::min(20, nrows); // Number of Arnoldi vectors generated at each iteration (0 == auto)
888 const Real tol = epsilon; // Stopping tolerance (relative accuracy of Ritz values) (0 == machine precision)
889 const int maxit = nIterationsMax_*nev; // Maximum number of Arnoldi update iterations allowed (0 == 100*nev)
890 Real* ev = new Real[nev]; // Computed eigenvalues of A^T*A
891 const bool ivec = true; // Flag deciding if eigenvectors shall be determined
892 int nconv; // Number of converged eigenvalues
893
894 // define what we need: eigenvalues with smallest algebraic value
895 char which[] = "SA";
896 ARSymStdEig<Real,WrappedMatrix>
897 dprob(ncols, nev, &A, &WrappedMatrix::multMtMv, which, ncv, tol, maxit);
898
899 // set ARPACK verbosity mode if requested
900 if (verbosity_level_ > 3) dprob.Trace();
901
902 // find eigenvalues and eigenvectors of A^T*A, obtain the eigenvalues
903 nconv = dprob.Eigenvalues(ev,ivec);
904
905 // obtain approximated smallest eigenvalue of A^T*A
906 const Real& lambda = ev[nev-1];
907
908 // obtain associated approximated eigenvector of A^T*A
909 Real* x_raw = dprob.RawEigenvector(nev-1);
910 WrappedMatrix::arrayToDomainBlockVector(x_raw,x);
911
912 // obtain number of Arnoldi update iterations actually taken
913 nIterations_ = dprob.GetIter();
914
915 // compute residual norm
916 BlockVector r(x);
917 Real* AtAx_raw = new Real[ncols];
918 A.multMtMv(x_raw,AtAx_raw);
919 WrappedMatrix::arrayToDomainBlockVector(AtAx_raw,r);
920 r.axpy(-lambda,x);
921 const Real r_norm = r.two_norm();
922
923 // calculate smallest singular value of A (note that
924 // x is right-singular / left-singular vector of A)
925 sigma = std::sqrt(lambda);
926
927 // print verbosity information
928 if (verbosity_level_ > 0)
929 {
930 if (verbosity_level_ > 1)
931 {
932 // print some information about the problem
933 std::cout << blank_ << "Obtained singular values of A by sol"
934 << "ving (A^T*A)*x = σ²*x using the ARPACK++ "
935 << "class ARSymStdEig:" << std::endl;
936 std::cout << blank_ << " converged eigenvalues of A^T*A: "
937 << nconv << " / " << nev << std::endl;
938 std::cout << blank_ << " smallest eigenvalue of A^T*A: "
939 << lambda << std::endl;
940 std::cout << blank_ << " => smallest singular value of A: "
941 << sigma << std::endl;
942 }
943 std::cout << blank_ << "Result ("
944 << "#iterations = " << nIterations_ << ", "
945 << "║residual║_2 = " << r_norm << "): "
946 << "σ = " << sigma << std::endl;
947 if (verbosity_level_ > 2)
948 {
949 // print approximated right-singular / left-singular vector
950 // via DUNE-ISTL I/O methods
952 }
953 }
954
955 // free dynamically allocated memory
956 delete[] AtAx_raw;
957 delete[] ev;
958 }
959
970 inline void computeNonSymCond2 (const Real& epsilon, Real& cond_2) const
971 {
972 // print verbosity information
973 if (verbosity_level_ > 0)
974 std::cout << title_ << "Computing an approximation of the "
975 << "spectral condition number of a matrix which "
976 << "is assumed to be nonsymmetric." << std::endl;
977
978 // use type ArPackPlusPlus_BCRSMatrixWrapper to store matrix information
979 // and to perform the product A^T*A*v (LU decomposition is not used)
980 typedef Impl::ArPackPlusPlus_BCRSMatrixWrapper<BCRSMatrix> WrappedMatrix;
981 WrappedMatrix A(m_);
982
983 // get number of rows and columns in A
984 const int nrows = A.nrows();
985 const int ncols = A.ncols();
986
987 // assert that A has more rows than columns (extend code later to the opposite case!)
988 if (nrows < ncols)
989 DUNE_THROW(Dune::ISTLError,"Matrix has less rows than "
990 << "columns (" << nrows << "x" << ncols << ")."
991 << " This case is not implemented, yet.");
992
993 // allocate memory for variables, set parameters
994 const int nev = 2; // Number of eigenvalues to compute
995 int ncv = std::min(20, nrows); // Number of Arnoldi vectors generated at each iteration (0 == auto)
996 const Real tol = epsilon; // Stopping tolerance (relative accuracy of Ritz values) (0 == machine precision)
997 const int maxit = nIterationsMax_*nev; // Maximum number of Arnoldi update iterations allowed (0 == 100*nev)
998 Real* ev = new Real[nev]; // Computed eigenvalues of A^T*A
999 const bool ivec = true; // Flag deciding if eigenvectors shall be determined
1000 int nconv; // Number of converged eigenvalues
1001
1002 // define what we need: eigenvalues from both ends of the spectrum
1003 char which[] = "BE";
1004 ARSymStdEig<Real,WrappedMatrix>
1005 dprob(ncols, nev, &A, &WrappedMatrix::multMtMv, which, ncv, tol, maxit);
1006
1007 // set ARPACK verbosity mode if requested
1008 if (verbosity_level_ > 3) dprob.Trace();
1009
1010 // find eigenvalues and eigenvectors of A^T*A, obtain the eigenvalues
1011 nconv = dprob.Eigenvalues(ev,ivec);
1012
1013 // obtain approximated largest and smallest eigenvalue of A^T*A
1014 const Real& lambda_max = ev[nev-1];
1015 const Real& lambda_min = ev[0];
1016
1017 // obtain associated approximated eigenvectors of A^T*A
1018 Real* x_max_raw = dprob.RawEigenvector(nev-1);
1019 Real* x_min_raw = dprob.RawEigenvector(0);
1020
1021 // obtain number of Arnoldi update iterations actually taken
1022 nIterations_ = dprob.GetIter();
1023
1024 // compute each residual norm
1025 Real* AtAx_max_raw = new Real[ncols];
1026 Real* AtAx_min_raw = new Real[ncols];
1027 A.multMtMv(x_max_raw,AtAx_max_raw);
1028 A.multMtMv(x_min_raw,AtAx_min_raw);
1029 Real r_max_norm = 0.0;
1030 Real r_min_norm = 0.0;
1031 for (int i = 0; i < ncols; ++i)
1032 {
1033 r_max_norm += std::pow(AtAx_max_raw[i] - lambda_max * x_max_raw[i],2);
1034 r_min_norm += std::pow(AtAx_min_raw[i] - lambda_min * x_min_raw[i],2);
1035 }
1036 r_max_norm = std::sqrt(r_max_norm);
1037 r_min_norm = std::sqrt(r_min_norm);
1038
1039 // calculate largest and smallest singular value of A
1040 const Real sigma_max = std::sqrt(lambda_max);
1041 const Real sigma_min = std::sqrt(lambda_min);
1042
1043 // obtain approximated spectral condition number of A
1044 cond_2 = sigma_max / sigma_min;
1045
1046 // print verbosity information
1047 if (verbosity_level_ > 0)
1048 {
1049 if (verbosity_level_ > 1)
1050 {
1051 // print some information about the problem
1052 std::cout << blank_ << "Obtained singular values of A by sol"
1053 << "ving (A^T*A)*x = σ²*x using the ARPACK++ "
1054 << "class ARSymStdEig:" << std::endl;
1055 std::cout << blank_ << " converged eigenvalues of A^T*A: "
1056 << nconv << " / " << nev << std::endl;
1057 std::cout << blank_ << " largest eigenvalue of A^T*A: "
1058 << lambda_max << std::endl;
1059 std::cout << blank_ << " smallest eigenvalue of A^T*A: "
1060 << lambda_min << std::endl;
1061 std::cout << blank_ << " => largest singular value of A: "
1062 << sigma_max << std::endl;
1063 std::cout << blank_ << " => smallest singular value of A: "
1064 << sigma_min << std::endl;
1065 }
1066 std::cout << blank_ << "Result ("
1067 << "#iterations = " << nIterations_ << ", "
1068 << "║residual║_2 = {" << r_max_norm << ","
1069 << r_min_norm << "}, " << "σ = {"
1070 << sigma_max << "," << sigma_min
1071 << "}): cond_2 = " << cond_2 << std::endl;
1072 }
1073
1074 // free dynamically allocated memory
1075 delete[] AtAx_min_raw;
1076 delete[] AtAx_max_raw;
1077 delete[] ev;
1078 }
1079
1084 inline unsigned int getIterationCount () const
1085 {
1086 if (nIterations_ == 0)
1087 DUNE_THROW(Dune::ISTLError,"No algorithm applied, yet.");
1088
1089 return nIterations_;
1090 }
1091
1092 protected:
1093 // parameters related to iterative eigenvalue algorithms
1095 const unsigned int nIterationsMax_;
1096
1097 // verbosity setting
1098 const unsigned int verbosity_level_;
1099
1100 // memory for storing temporary variables (mutable as they shall
1101 // just be effectless auxiliary variables of the const apply*(...)
1102 // methods)
1103 mutable unsigned int nIterations_;
1104
1105 // constants for printing verbosity information
1108 };
1109
1112} // namespace Dune
1113
1114#endif // HAVE_ARPACKPP
1115
1116#endif // DUNE_ISTL_EIGENVALUE_ARPACKPP_HH
Some generic functions for pretty printing vectors and matrices.
Helper functions for determining the vector/matrix block level.
This file implements a vector space as a tensor product of a given vector space. The number of compon...
void printvector(std::ostream &s, const V &v, std::string title, std::string rowtext, int columns=1, int width=10, int precision=2)
Print an ISTL vector.
Definition io.hh:89
static constexpr size_type M()
static constexpr size_type N()
#define DUNE_THROW(E,...)
A sparse block matrix with compressed row storage.
Definition bcrsmatrix.hh:468
typename Imp::BlockTraits< B >::field_type field_type
export the type representing the field
Definition bcrsmatrix.hh:490
A vector of blocks with memory management.
Definition bvector.hh:392
typename Imp::BlockTraits< B >::field_type field_type
export the type representing the field
Definition bvector.hh:398
Wrapper to use a range of ARPACK++ eigenvalue solvers.
Definition arpackpp.hh:385
const unsigned int verbosity_level_
Definition arpackpp.hh:1098
unsigned int getIterationCount() const
Return the number of iterations in last application of an algorithm.
Definition arpackpp.hh:1084
const std::string title_
Definition arpackpp.hh:1106
BlockVector::field_type Real
Definition arpackpp.hh:387
void computeSymMaxMagnitude(const Real &epsilon, BlockVector &x, Real &lambda) const
Assume the matrix to be square, symmetric and perform IRLM to compute an approximation lambda of its ...
Definition arpackpp.hh:429
void computeSymMinMagnitude(const Real &epsilon, BlockVector &x, Real &lambda) const
Assume the matrix to be square, symmetric and perform IRLM to compute an approximation lambda of its ...
Definition arpackpp.hh:531
const BCRSMatrix & m_
Definition arpackpp.hh:1094
const unsigned int nIterationsMax_
Definition arpackpp.hh:1095
const std::string blank_
Definition arpackpp.hh:1107
ArPackPlusPlus_Algorithms(const BCRSMatrix &m, const unsigned int nIterationsMax=100000, const unsigned int verbosity_level=0)
Construct from required parameters.
Definition arpackpp.hh:408
void computeSymCond2(const Real &epsilon, Real &cond_2) const
Assume the matrix to be square, symmetric and perform IRLM to compute an approximation of its spectra...
Definition arpackpp.hh:633
unsigned int nIterations_
Definition arpackpp.hh:1103
void computeNonSymMin(const Real &epsilon, BlockVector &x, Real &sigma) const
Assume the matrix to be nonsymmetric and perform IRLM to compute an approximation sigma of its smalle...
Definition arpackpp.hh:861
void computeNonSymCond2(const Real &epsilon, Real &cond_2) const
Assume the matrix to be nonsymmetric and perform IRLM to compute an approximation of its spectral con...
Definition arpackpp.hh:970
void computeNonSymMax(const Real &epsilon, BlockVector &x, Real &sigma) const
Assume the matrix to be nonsymmetric and perform IRLM to compute an approximation sigma of its larges...
Definition arpackpp.hh:749
derive error class from the base class in common
Definition istlexception.hh:19
T endl(T... args)
T min(T... args)
T pow(T... args)
T sqrt(T... args)