Reference documentation for deal.II version 8.4.2
lapack_full_matrix.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2005 - 2015 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 
17 #include <deal.II/lac/lapack_full_matrix.h>
18 #include <deal.II/lac/lapack_templates.h>
19 #include <deal.II/lac/lapack_support.h>
20 #include <deal.II/lac/full_matrix.h>
21 #include <deal.II/lac/sparse_matrix.h>
22 #include <deal.II/lac/vector.h>
23 #include <deal.II/lac/block_vector.h>
24 
25 #include <iostream>
26 #include <iomanip>
27 
28 DEAL_II_NAMESPACE_OPEN
29 
30 using namespace LAPACKSupport;
31 
32 template <typename number>
34  :
35  TransposeTable<number> (n,n),
36  state (matrix)
37 {}
38 
39 
40 template <typename number>
42  const size_type n)
43  :
44  TransposeTable<number> (m, n),
45  state (matrix)
46 {}
47 
48 
49 template <typename number>
51  :
52  TransposeTable<number> (M),
53  state (matrix)
54 {}
55 
56 
57 template <typename number>
60 {
62  state = LAPACKSupport::matrix;
63  return *this;
64 }
65 
66 
67 template <typename number>
68 void
70 {
71  this->TransposeTable<number>::reinit (n, n);
72  state = LAPACKSupport::matrix;
73 }
74 
75 
76 template <typename number>
77 void
79  const size_type n)
80 {
81  this->TransposeTable<number>::reinit (m, n);
82  state = LAPACKSupport::matrix;
83 }
84 
85 
86 template <typename number>
87 template <typename number2>
90 {
91  Assert (this->n_rows() == M.n_rows(), ExcDimensionMismatch(this->n_rows(), M.n_rows()));
92  Assert (this->n_cols() == M.n(), ExcDimensionMismatch(this->n_cols(), M.n()));
93  for (size_type i=0; i<this->n_rows(); ++i)
94  for (size_type j=0; j<this->n_cols(); ++j)
95  (*this)(i,j) = M(i,j);
96 
97  state = LAPACKSupport::matrix;
98  return *this;
99 }
100 
101 
102 template <typename number>
103 template <typename number2>
106 {
107  Assert (this->n_rows() == M.n(), ExcDimensionMismatch(this->n_rows(), M.n()));
108  Assert (this->n_cols() == M.m(), ExcDimensionMismatch(this->n_cols(), M.m()));
109  for (size_type i=0; i<this->n_rows(); ++i)
110  for (size_type j=0; j<this->n_cols(); ++j)
111  (*this)(i,j) = M.el(i,j);
112 
113  state = LAPACKSupport::matrix;
114  return *this;
115 }
116 
117 
118 template <typename number>
121 {
122  (void)d;
123  Assert (d==0, ExcScalarAssignmentOnlyForZeroValue());
124 
125  if (this->n_elements() != 0)
126  this->reset_values();
127 
128  state = LAPACKSupport::matrix;
129  return *this;
130 }
131 
132 
133 template <typename number>
134 void
136  Vector<number> &w,
137  const Vector<number> &v,
138  const bool adding) const
139 {
140  const int mm = this->n_rows();
141  const int nn = this->n_cols();
142  const number alpha = 1.;
143  const number beta = (adding ? 1. : 0.);
144  const number null = 0.;
145 
146  switch (state)
147  {
148  case matrix:
149  case inverse_matrix:
150  {
151  AssertDimension(v.size(), this->n_cols());
152  AssertDimension(w.size(), this->n_rows());
153 
154  gemv("N", &mm, &nn, &alpha, &this->values[0], &mm, v.val, &one, &beta, w.val, &one);
155  break;
156  }
157  case svd:
158  {
159  AssertDimension(v.size(), this->n_cols());
160  AssertDimension(w.size(), this->n_rows());
161  // Compute V^T v
162  work.resize(std::max(mm,nn));
163  gemv("N", &nn, &nn, &alpha, &svd_vt->values[0], &nn, v.val, &one, &null, &work[0], &one);
164  // Multiply by singular values
165  for (size_type i=0; i<wr.size(); ++i)
166  work[i] *= wr[i];
167  // Multiply with U
168  gemv("N", &mm, &mm, &alpha, &svd_u->values[0], &mm, &work[0], &one, &beta, w.val, &one);
169  break;
170  }
171  case inverse_svd:
172  {
173  AssertDimension(w.size(), this->n_cols());
174  AssertDimension(v.size(), this->n_rows());
175  // Compute U^T v
176  work.resize(std::max(mm,nn));
177  gemv("T", &mm, &mm, &alpha, &svd_u->values[0], &mm, v.val, &one, &null, &work[0], &one);
178  // Multiply by singular values
179  for (size_type i=0; i<wr.size(); ++i)
180  work[i] *= wr[i];
181  // Multiply with V
182  gemv("T", &nn, &nn, &alpha, &svd_vt->values[0], &nn, &work[0], &one, &beta, w.val, &one);
183  break;
184  }
185  default:
186  Assert (false, ExcState(state));
187  }
188 }
189 
190 
191 template <typename number>
192 void
194  Vector<number> &w,
195  const Vector<number> &v,
196  const bool adding) const
197 {
198  const int mm = this->n_rows();
199  const int nn = this->n_cols();
200  const number alpha = 1.;
201  const number beta = (adding ? 1. : 0.);
202  const number null = 0.;
203 
204  switch (state)
205  {
206  case matrix:
207  case inverse_matrix:
208  {
209  AssertDimension(w.size(), this->n_cols());
210  AssertDimension(v.size(), this->n_rows());
211 
212  gemv("T", &mm, &nn, &alpha, &this->values[0], &mm, v.val, &one, &beta, w.val, &one);
213  break;
214  }
215  case svd:
216  {
217  AssertDimension(w.size(), this->n_cols());
218  AssertDimension(v.size(), this->n_rows());
219 
220  // Compute U^T v
221  work.resize(std::max(mm,nn));
222  gemv("T", &mm, &mm, &alpha, &svd_u->values[0], &mm, v.val, &one, &null, &work[0], &one);
223  // Multiply by singular values
224  for (size_type i=0; i<wr.size(); ++i)
225  work[i] *= wr[i];
226  // Multiply with V
227  gemv("T", &nn, &nn, &alpha, &svd_vt->values[0], &nn, &work[0], &one, &beta, w.val, &one);
228  break;
229  case inverse_svd:
230  {
231  AssertDimension(v.size(), this->n_cols());
232  AssertDimension(w.size(), this->n_rows());
233 
234  // Compute V^T v
235  work.resize(std::max(mm,nn));
236  gemv("N", &nn, &nn, &alpha, &svd_vt->values[0], &nn, v.val, &one, &null, &work[0], &one);
237  // Multiply by singular values
238  for (size_type i=0; i<wr.size(); ++i)
239  work[i] *= wr[i];
240  // Multiply with U
241  gemv("N", &mm, &mm, &alpha, &svd_u->values[0], &mm, &work[0], &one, &beta, w.val, &one);
242  break;
243  }
244  }
245  default:
246  Assert (false, ExcState(state));
247  }
248 }
249 
250 
251 template <typename number>
252 void
254  const Vector<number> &v) const
255 {
256  vmult(w, v, true);
257 }
258 
259 
260 template <typename number>
261 void
263  const Vector<number> &v) const
264 {
265  Tvmult(w, v, true);
266 }
267 
268 
269 template <typename number>
270 void
272  const LAPACKFullMatrix<number> &B,
273  const bool adding) const
274 {
275  Assert(state == matrix || state == inverse_matrix, ExcState(state));
276  Assert(B.state == matrix || B.state == inverse_matrix, ExcState(state));
277  Assert(C.state == matrix || C.state == inverse_matrix, ExcState(state));
278  Assert (this->n_cols() == B.n_rows(), ExcDimensionMismatch(this->n_cols(), B.n_rows()));
279  Assert (C.n_cols() == B.n_cols(), ExcDimensionMismatch(C.n_cols(), B.n_cols()));
280  Assert (C.n_rows() == this->n_rows(), ExcDimensionMismatch(this->n_rows(), C.n_rows()));
281  const int mm = this->n_rows();
282  const int nn = B.n_cols();
283  const int kk = this->n_cols();
284  const number alpha = 1.;
285  const number beta = (adding ? 1. : 0.);
286 
287  gemm("N", "N", &mm, &nn, &kk, &alpha, &this->values[0], &mm, &B.values[0],
288  &kk, &beta, &C.values[0], &mm);
289 }
290 
291 
292 template <typename number>
293 void
295  const LAPACKFullMatrix<number> &B,
296  const bool adding) const
297 {
298  Assert(state == matrix || state == inverse_matrix, ExcState(state));
299  Assert(B.state == matrix || B.state == inverse_matrix, ExcState(state));
300  Assert (this->n_cols() == B.n_rows(), ExcDimensionMismatch(this->n_cols(), B.n_rows()));
301  Assert (C.n_cols() == B.n_cols(), ExcDimensionMismatch(C.n_cols(), B.n_cols()));
302  Assert (C.n_rows() == this->n_rows(), ExcDimensionMismatch(this->n_rows(), C.n_rows()));
303  const int mm = this->n_rows();
304  const int nn = B.n_cols();
305  const int kk = this->n_cols();
306  const number alpha = 1.;
307  const number beta = (adding ? 1. : 0.);
308 
309  // since FullMatrix stores the matrix in transposed order compared to this
310  // matrix, compute B^T * A^T = (A * B)^T
311  gemm("T", "T", &nn, &mm, &kk, &alpha, &B.values[0], &kk, &this->values[0],
312  &mm, &beta, &C(0,0), &nn);
313 }
314 
315 
316 
317 template <typename number>
318 void
320  const LAPACKFullMatrix<number> &B,
321  const bool adding) const
322 {
323  Assert(state == matrix || state == inverse_matrix, ExcState(state));
324  Assert(B.state == matrix || B.state == inverse_matrix, ExcState(state));
325  Assert(C.state == matrix || C.state == inverse_matrix, ExcState(state));
326  Assert (this->n_rows() == B.n_rows(), ExcDimensionMismatch(this->n_rows(), B.n_rows()));
327  Assert (C.n_cols() == B.n_cols(), ExcDimensionMismatch(C.n_cols(), B.n_cols()));
328  Assert (C.n_rows() == this->n_cols(), ExcDimensionMismatch(this->n_cols(), C.n_rows()));
329  const int mm = this->n_cols();
330  const int nn = B.n_cols();
331  const int kk = B.n_rows();
332  const number alpha = 1.;
333  const number beta = (adding ? 1. : 0.);
334 
335  gemm("T", "N", &mm, &nn, &kk, &alpha, &this->values[0], &kk, &B.values[0],
336  &kk, &beta, &C.values[0], &mm);
337 }
338 
339 
340 template <typename number>
341 void
343  const LAPACKFullMatrix<number> &B,
344  const bool adding) const
345 {
346  Assert(state == matrix || state == inverse_matrix, ExcState(state));
347  Assert(B.state == matrix || B.state == inverse_matrix, ExcState(state));
348  Assert (this->n_rows() == B.n_rows(), ExcDimensionMismatch(this->n_rows(), B.n_rows()));
349  Assert (C.n_cols() == B.n_cols(), ExcDimensionMismatch(C.n_cols(), B.n_cols()));
350  Assert (C.n_rows() == this->n_cols(), ExcDimensionMismatch(this->n_cols(), C.n_rows()));
351  const int mm = this->n_cols();
352  const int nn = B.n_cols();
353  const int kk = B.n_rows();
354  const number alpha = 1.;
355  const number beta = (adding ? 1. : 0.);
356 
357  // since FullMatrix stores the matrix in transposed order compared to this
358  // matrix, compute B^T * A = (A^T * B)^T
359  gemm("T", "N", &nn, &mm, &kk, &alpha, &B.values[0], &kk, &this->values[0],
360  &kk, &beta, &C(0,0), &nn);
361 }
362 
363 
364 template <typename number>
365 void
367  const LAPACKFullMatrix<number> &B,
368  const bool adding) const
369 {
370  Assert(state == matrix || state == inverse_matrix, ExcState(state));
371  Assert(B.state == matrix || B.state == inverse_matrix, ExcState(state));
372  Assert(C.state == matrix || C.state == inverse_matrix, ExcState(state));
373  Assert (this->n_cols() == B.n_cols(), ExcDimensionMismatch(this->n_cols(), B.n_cols()));
374  Assert (C.n_cols() == B.n_rows(), ExcDimensionMismatch(C.n_cols(), B.n_rows()));
375  Assert (C.n_rows() == this->n_rows(), ExcDimensionMismatch(this->n_rows(), C.n_rows()));
376  const int mm = this->n_rows();
377  const int nn = B.n_rows();
378  const int kk = B.n_cols();
379  const number alpha = 1.;
380  const number beta = (adding ? 1. : 0.);
381 
382  gemm("N", "T", &mm, &nn, &kk, &alpha, &this->values[0], &mm, &B.values[0],
383  &nn, &beta, &C.values[0], &mm);
384 }
385 
386 
387 
388 template <typename number>
389 void
391  const LAPACKFullMatrix<number> &B,
392  const bool adding) const
393 {
394  Assert(state == matrix || state == inverse_matrix, ExcState(state));
395  Assert(B.state == matrix || B.state == inverse_matrix, ExcState(state));
396  Assert (this->n_cols() == B.n_cols(), ExcDimensionMismatch(this->n_cols(), B.n_cols()));
397  Assert (C.n_cols() == B.n_rows(), ExcDimensionMismatch(C.n_cols(), B.n_rows()));
398  Assert (C.n_rows() == this->n_rows(), ExcDimensionMismatch(this->n_rows(), C.n_rows()));
399  const int mm = this->n_rows();
400  const int nn = B.n_rows();
401  const int kk = B.n_cols();
402  const number alpha = 1.;
403  const number beta = (adding ? 1. : 0.);
404 
405  // since FullMatrix stores the matrix in transposed order compared to this
406  // matrix, compute B * A^T = (A * B^T)^T
407  gemm("N", "T", &nn, &mm, &kk, &alpha, &B.values[0], &nn, &this->values[0],
408  &mm, &beta, &C(0,0), &nn);
409 }
410 
411 
412 template <typename number>
413 void
415  const LAPACKFullMatrix<number> &B,
416  const bool adding) const
417 {
418  Assert(state == matrix || state == inverse_matrix, ExcState(state));
419  Assert(B.state == matrix || B.state == inverse_matrix, ExcState(state));
420  Assert(C.state == matrix || C.state == inverse_matrix, ExcState(state));
421  Assert (this->n_rows() == B.n_cols(), ExcDimensionMismatch(this->n_rows(), B.n_cols()));
422  Assert (C.n_cols() == B.n_rows(), ExcDimensionMismatch(C.n_cols(), B.n_rows()));
423  Assert (C.n_rows() == this->n_cols(), ExcDimensionMismatch(this->n_cols(), C.n_rows()));
424  const int mm = this->n_cols();
425  const int nn = B.n_rows();
426  const int kk = B.n_cols();
427  const number alpha = 1.;
428  const number beta = (adding ? 1. : 0.);
429 
430  gemm("T", "T", &mm, &nn, &kk, &alpha, &this->values[0], &kk, &B.values[0],
431  &nn, &beta, &C.values[0], &mm);
432 }
433 
434 
435 template <typename number>
436 void
438  const LAPACKFullMatrix<number> &B,
439  const bool adding) const
440 {
441  Assert(state == matrix || state == inverse_matrix, ExcState(state));
442  Assert(B.state == matrix || B.state == inverse_matrix, ExcState(state));
443  Assert (this->n_rows() == B.n_cols(), ExcDimensionMismatch(this->n_rows(), B.n_cols()));
444  Assert (C.n_cols() == B.n_rows(), ExcDimensionMismatch(C.n_cols(), B.n_rows()));
445  Assert (C.n_rows() == this->n_cols(), ExcDimensionMismatch(this->n_cols(), C.n_rows()));
446  const int mm = this->n_cols();
447  const int nn = B.n_rows();
448  const int kk = B.n_cols();
449  const number alpha = 1.;
450  const number beta = (adding ? 1. : 0.);
451 
452  // since FullMatrix stores the matrix in transposed order compared to this
453  // matrix, compute B * A = (A^T * B^T)^T
454  gemm("N", "N", &nn, &mm, &kk, &alpha, &B.values[0], &nn, &this->values[0],
455  &kk, &beta, &C(0,0), &nn);
456 }
457 
458 
459 template <typename number>
460 void
462 {
463  Assert(state == matrix, ExcState(state));
464  const int mm = this->n_rows();
465  const int nn = this->n_cols();
466  number *values = const_cast<number *> (&this->values[0]);
467  ipiv.resize(mm);
468  int info = 0;
469  getrf(&mm, &nn, values, &mm, &ipiv[0], &info);
470 
471  AssertThrow(info >= 0, ExcInternalError());
472  AssertThrow(info == 0, LACExceptions::ExcSingular());
473 
474  state = lu;
475 }
476 
477 
478 template <typename number>
479 void
481 {
482  Assert(state == matrix, ExcState(state));
483  state = LAPACKSupport::unusable;
484 
485  const int mm = this->n_rows();
486  const int nn = this->n_cols();
487  number *values = const_cast<number *> (&this->values[0]);
488  wr.resize(std::max(mm,nn));
489  std::fill(wr.begin(), wr.end(), 0.);
490  ipiv.resize(8*mm);
491 
492  svd_u.reset (new LAPACKFullMatrix<number>(mm,mm));
493  svd_vt.reset (new LAPACKFullMatrix<number>(nn,nn));
494  number *mu = const_cast<number *> (&svd_u->values[0]);
495  number *mvt = const_cast<number *> (&svd_vt->values[0]);
496  int info = 0;
497 
498  // First determine optimal workspace size
499  work.resize(1);
500  int lwork = -1;
501  gesdd(&LAPACKSupport::A, &mm, &nn, values, &mm,
502  &wr[0], mu, &mm, mvt, &nn,
503  &work[0], &lwork, &ipiv[0], &info);
504  AssertThrow (info==0, LAPACKSupport::ExcErrorCode("gesdd", info));
505  // Resize the work array. Add one to the size computed by LAPACK to be on
506  // the safe side.
507  lwork = static_cast<int>(work[0] + 1);
508 
509  work.resize(lwork);
510  // Do the actual SVD.
511  gesdd(&LAPACKSupport::A, &mm, &nn, values, &mm,
512  &wr[0], mu, &mm, mvt, &nn,
513  &work[0], &lwork, &ipiv[0], &info);
514  AssertThrow (info==0, LAPACKSupport::ExcErrorCode("gesdd", info));
515 
516  work.resize(0);
517  ipiv.resize(0);
518 
519  state = LAPACKSupport::svd;
520 }
521 
522 
523 template <typename number>
524 void
526 {
527  if (state == LAPACKSupport::matrix)
528  compute_svd();
529 
530  Assert (state==LAPACKSupport::svd, ExcState(state));
531 
532  const double lim = wr[0]*threshold;
533  for (size_type i=0; i<wr.size(); ++i)
534  {
535  if (wr[i] > lim)
536  wr[i] = 1./wr[i];
537  else
538  wr[i] = 0.;
539  }
540  state = LAPACKSupport::inverse_svd;
541 }
542 
543 
544 template <typename number>
545 void
547 {
548  Assert(state == matrix || state == lu,
549  ExcState(state));
550  const int mm = this->n_rows();
551  const int nn = this->n_cols();
552  Assert (nn == mm, ExcNotQuadratic());
553 
554  number *values = const_cast<number *> (&this->values[0]);
555  ipiv.resize(mm);
556  int info = 0;
557 
558  if (state == matrix)
559  {
560  getrf(&mm, &nn, values, &mm, &ipiv[0], &info);
561 
562  AssertThrow(info >= 0, ExcInternalError());
563  AssertThrow(info == 0, LACExceptions::ExcSingular());
564  }
565 
566  inv_work.resize (mm);
567  getri(&mm, values, &mm, &ipiv[0], &inv_work[0], &mm, &info);
568 
569  AssertThrow(info >= 0, ExcInternalError());
570  AssertThrow(info == 0, LACExceptions::ExcSingular());
571 
572  state = inverse_matrix;
573 }
574 
575 
576 template <typename number>
577 void
579  const bool transposed) const
580 {
581  Assert(state == lu, ExcState(state));
582  Assert(this->n_rows() == this->n_cols(),
583  LACExceptions::ExcNotQuadratic());
584  AssertDimension(this->n_rows(), v.size());
585 
586  const char *trans = transposed ? &T : &N;
587  const int nn = this->n_cols();
588  const number *values = &this->values[0];
589  int info = 0;
590 
591  getrs(trans, &nn, &one, values, &nn, &ipiv[0],
592  v.begin(), &nn, &info);
593 
594  AssertThrow(info == 0, ExcInternalError());
595 }
596 
597 
598 template <typename number>
599 void
601  const bool transposed) const
602 {
603  Assert(state == lu, ExcState(state));
604  Assert(B.state == matrix, ExcState(state));
605  Assert(this->n_rows() == this->n_cols(), LACExceptions::ExcNotQuadratic());
606  AssertDimension(this->n_rows(), B.n_rows());
607 
608  const char *trans = transposed ? &T : &N;
609  const int nn = this->n_cols();
610  const int kk = B.n_cols();
611  const number *values = &this->values[0];
612  int info = 0;
613 
614  getrs(trans, &nn, &kk, values, &nn, &ipiv[0], &B.values[0], &nn, &info);
615 
616  AssertThrow(info == 0, ExcInternalError());
617 }
618 
619 
620 template <typename number>
621 void
623  const bool left)
624 {
625  Assert(state == matrix, ExcState(state));
626  const int nn = this->n_cols();
627  wr.resize(nn);
628  wi.resize(nn);
629  if (right) vr.resize(nn*nn);
630  if (left) vl.resize(nn*nn);
631 
632  number *values = const_cast<number *> (&this->values[0]);
633 
634  int info = 0;
635  int lwork = 1;
636  const char *const jobvr = (right) ? (&V) : (&N);
637  const char *const jobvl = (left) ? (&V) : (&N);
638 
639  /*
640  * The LAPACK routine xGEEV requires a sufficiently large work array; the
641  * minimum requirement is
642  *
643  * work.size >= 4*nn.
644  *
645  * However, for better performance, a larger work array may be needed. The
646  * first call determines the optimal work size and the second does the work.
647  */
648  lwork = -1;
649  work.resize(1);
650 
651  geev(jobvl, jobvr, &nn, values, &nn,
652  &wr[0], &wi[0],
653  &vl[0], &nn, &vr[0], &nn,
654  &work[0], &lwork, &info);
655  // geev returns info=0 on success. Since we only queried the optimal size
656  // for work, everything else would not be acceptable.
657  Assert (info == 0, ExcInternalError());
658  // Allocate working array according to suggestion (same strategy as was
659  // noted in compute_svd).
660  lwork = static_cast<int>(work[0] + 1);
661 
662  // resize workspace array
663  work.resize((size_type ) lwork);
664 
665  // Finally compute the eigenvalues.
666  geev(jobvl, jobvr, &nn, values, &nn,
667  &wr[0], &wi[0],
668  &vl[0], &nn, &vr[0], &nn,
669  &work[0], &lwork, &info);
670  // Negative return value implies a wrong argument. This should be internal.
671 
672  Assert (info >=0, ExcInternalError());
673 //TODO:[GK] What if the QR method fails?
674  if (info != 0)
675  std::cerr << "LAPACK error in geev" << std::endl;
676 
677  state = LAPACKSupport::State(eigenvalues | unusable);
678 }
679 
680 
681 template <typename number>
682 void
684  const number upper_bound,
685  const number abs_accuracy,
686  Vector<number> &eigenvalues,
687  FullMatrix<number> &eigenvectors)
688 {
689  Assert(state == matrix, ExcState(state));
690  const int nn = (this->n_cols() > 0 ? this->n_cols() : 1);
691  Assert(static_cast<size_type>(nn) == this->n_rows(), ExcNotQuadratic());
692 
693  wr.resize(nn);
694  LAPACKFullMatrix<number> matrix_eigenvectors(nn, nn);
695 
696  number *values_A = const_cast<number *> (&this->values[0]);
697  number *values_eigenvectors = const_cast<number *> (&matrix_eigenvectors.values[0]);
698 
699  int info(0),
700  lwork(-1),
701  n_eigenpairs(0);
702  const char *const jobz(&V);
703  const char *const uplo(&U);
704  const char *const range(&V);
705  const int *const dummy(&one);
706  std::vector<int> iwork(static_cast<size_type> (5*nn));
707  std::vector<int> ifail(static_cast<size_type> (nn));
708 
709 
710  /*
711  * The LAPACK routine xSYEVX requires a sufficiently large work array; the
712  * minimum requirement is
713  *
714  * work.size >= 8*nn.
715  *
716  * However, for better performance, a larger work array may be needed. The
717  * first call determines the optimal work size and the second does the work.
718  */
719  work.resize(1);
720 
721  syevx (jobz, range,
722  uplo, &nn, values_A, &nn,
723  &lower_bound, &upper_bound,
724  dummy, dummy, &abs_accuracy,
725  &n_eigenpairs, &wr[0], values_eigenvectors,
726  &nn, &work[0], &lwork, &iwork[0],
727  &ifail[0], &info);
728  // syevx returns info=0 on success. Since we only queried the optimal size
729  // for work, everything else would not be acceptable.
730  Assert (info == 0, ExcInternalError());
731  // Allocate working array according to suggestion (same strategy as was noted in
732  // compute_svd).
733  lwork = static_cast<int>(work[0] + 1);
734  work.resize(static_cast<size_type> (lwork));
735 
736  // Finally compute the eigenvalues.
737  syevx (jobz, range,
738  uplo, &nn, values_A, &nn,
739  &lower_bound, &upper_bound,
740  dummy, dummy, &abs_accuracy,
741  &n_eigenpairs, &wr[0], values_eigenvectors,
742  &nn, &work[0], &lwork, &iwork[0],
743  &ifail[0], &info);
744 
745  // Negative return value implies a wrong argument. This should be internal.
746  Assert (info >=0, ExcInternalError());
747  if (info != 0)
748  std::cerr << "LAPACK error in syevx" << std::endl;
749 
750  eigenvalues.reinit(n_eigenpairs);
751  eigenvectors.reinit(nn, n_eigenpairs, true);
752 
753  for (size_type i=0; i < static_cast<size_type> (n_eigenpairs); ++i)
754  {
755  eigenvalues(i) = wr[i];
756  size_type col_begin(i*nn);
757  for (size_type j=0; j < static_cast<size_type> (nn); ++j)
758  {
759  eigenvectors(j,i) = values_eigenvectors[col_begin+j];
760  }
761  }
762 
763  state = LAPACKSupport::State(unusable);
764 }
765 
766 
767 template <typename number>
768 void
771  const number lower_bound,
772  const number upper_bound,
773  const number abs_accuracy,
774  Vector<number> &eigenvalues,
775  std::vector<Vector<number> > &eigenvectors,
776  const int itype)
777 {
778  Assert(state == matrix, ExcState(state));
779  const int nn = (this->n_cols() > 0 ? this->n_cols() : 1);
780  Assert(static_cast<size_type>(nn) == this->n_rows(), ExcNotQuadratic());
781  Assert(B.n_rows() == B.n_cols(), ExcNotQuadratic());
782  Assert(static_cast<size_type>(nn) == B.n_cols(),
783  ExcDimensionMismatch (nn, B.n_cols()));
784 
785  wr.resize(nn);
786  LAPACKFullMatrix<number> matrix_eigenvectors(nn, nn);
787 
788  number *values_A = const_cast<number *> (&this->values[0]);
789  number *values_B = const_cast<number *> (&B.values[0]);
790  number *values_eigenvectors = const_cast<number *> (&matrix_eigenvectors.values[0]);
791 
792  int info(0),
793  lwork(-1),
794  n_eigenpairs(0);
795  const char *const jobz(&V);
796  const char *const uplo(&U);
797  const char *const range(&V);
798  const int *const dummy(&one);
799  std::vector<int> iwork(static_cast<size_type> (5*nn));
800  std::vector<int> ifail(static_cast<size_type> (nn));
801 
802 
803  /*
804  * The LAPACK routine xSYGVX requires a sufficiently large work array; the
805  * minimum requirement is
806  *
807  * work.size >= 8*nn.
808  *
809  * However, for better performance, a larger work array may be needed. The
810  * first call determines the optimal work size and the second does the work.
811  */
812  work.resize(1);
813 
814  sygvx (&itype, jobz, range, uplo, &nn, values_A, &nn,
815  values_B, &nn, &lower_bound, &upper_bound,
816  dummy, dummy, &abs_accuracy, &n_eigenpairs,
817  &wr[0], values_eigenvectors, &nn, &work[0],
818  &lwork, &iwork[0], &ifail[0], &info);
819  // sygvx returns info=0 on success. Since we only queried the optimal size
820  // for work, everything else would not be acceptable.
821  Assert (info == 0, ExcInternalError());
822  // Allocate working array according to suggestion (same strategy as was
823  // noted in compute_svd).
824  lwork = static_cast<int>(work[0] + 1);
825 
826  // resize workspace arrays
827  work.resize(static_cast<size_type> (lwork));
828 
829  // Finally compute the generalized eigenvalues.
830  sygvx (&itype, jobz, range, uplo, &nn, values_A, &nn,
831  values_B, &nn, &lower_bound, &upper_bound,
832  dummy, dummy, &abs_accuracy, &n_eigenpairs,
833  &wr[0], values_eigenvectors, &nn, &work[0],
834  &lwork, &iwork[0], &ifail[0], &info);
835 
836  // Negative return value implies a wrong argument. This should be internal.
837  Assert (info >=0, ExcInternalError());
838  if (info != 0)
839  std::cerr << "LAPACK error in sygvx" << std::endl;
840 
841  eigenvalues.reinit(n_eigenpairs);
842  eigenvectors.resize(n_eigenpairs);
843 
844  for (size_type i=0; i < static_cast<size_type> (n_eigenpairs); ++i)
845  {
846  eigenvalues(i) = wr[i];
847  size_type col_begin(i*nn);
848  eigenvectors[i].reinit(nn, true);
849  for (size_type j=0; j < static_cast<size_type> (nn); ++j)
850  {
851  eigenvectors[i](j) = values_eigenvectors[col_begin+j];
852  }
853  }
854 
855  state = LAPACKSupport::State(unusable);
856 }
857 
858 
859 template <typename number>
860 void
863  std::vector<Vector<number> > &eigenvectors,
864  const int itype)
865 {
866  Assert(state == matrix, ExcState(state));
867  const int nn = this->n_cols();
868  Assert(static_cast<size_type>(nn) == this->n_rows(), ExcNotQuadratic());
869  Assert(B.n_rows() == B.n_cols(), ExcNotQuadratic());
870  Assert(static_cast<size_type>(nn) == B.n_cols(),
871  ExcDimensionMismatch (nn, B.n_cols()));
872  Assert(eigenvectors.size() <= static_cast<size_type>(nn),
873  ExcMessage ("eigenvectors.size() > matrix.n_cols()"));
874 
875  wr.resize(nn);
876  wi.resize(nn); //This is set purely for consistency reasons with the
877  //eigenvalues() function.
878 
879  number *values_A = const_cast<number *> (&this->values[0]);
880  number *values_B = const_cast<number *> (&B.values[0]);
881 
882  int info = 0;
883  int lwork = -1;
884  const char *const jobz = (eigenvectors.size() > 0) ? (&V) : (&N);
885  const char *const uplo = (&U);
886 
887  /*
888  * The LAPACK routine xSYGV requires a sufficiently large work array; the
889  * minimum requirement is
890  *
891  * work.size >= 3*nn - 1.
892  *
893  * However, for better performance, a larger work array may be needed. The
894  * first call determines the optimal work size and the second does the work.
895  */
896  work.resize(1);
897 
898  sygv (&itype, jobz, uplo, &nn, values_A, &nn,
899  values_B, &nn,
900  &wr[0], &work[0], &lwork, &info);
901  // sygv returns info=0 on success. Since we only queried the optimal size
902  // for work, everything else would not be acceptable.
903  Assert (info == 0, ExcInternalError());
904  // Allocate working array according to suggestion (same strategy as was
905  // noted in compute_svd).
906  lwork = static_cast<int>(work[0] + 1);
907 
908  // resize workspace array
909  work.resize((size_type) lwork);
910 
911  // Finally compute the generalized eigenvalues.
912  sygv (&itype, jobz, uplo, &nn, values_A, &nn,
913  values_B, &nn,
914  &wr[0], &work[0], &lwork, &info);
915  // Negative return value implies a wrong argument. This should be internal.
916 
917  Assert (info >=0, ExcInternalError());
918  if (info != 0)
919  std::cerr << "LAPACK error in sygv" << std::endl;
920 
921  for (size_type i=0; i < eigenvectors.size(); ++i)
922  {
923  size_type col_begin(i*nn);
924  eigenvectors[i].reinit(nn, true);
925  for (size_type j=0; j < static_cast<size_type>(nn); ++j)
926  {
927  eigenvectors[i](j) = values_A[col_begin+j];
928  }
929  }
930  state = LAPACKSupport::State(eigenvalues | unusable);
931 }
932 
933 
934 template <typename number>
935 void
937  std::ostream &out,
938  const unsigned int precision,
939  const bool scientific,
940  const unsigned int width_,
941  const char *zero_string,
942  const double denominator,
943  const double threshold) const
944 {
945  unsigned int width = width_;
946 
947  Assert ((!this->empty()) || (this->n_cols()+this->n_rows()==0),
948  ExcInternalError());
949 
950  // set output format, but store old
951  // state
952  std::ios::fmtflags old_flags = out.flags();
953  unsigned int old_precision = out.precision (precision);
954 
955  if (scientific)
956  {
957  out.setf (std::ios::scientific, std::ios::floatfield);
958  if (!width)
959  width = precision+7;
960  }
961  else
962  {
963  out.setf (std::ios::fixed, std::ios::floatfield);
964  if (!width)
965  width = precision+2;
966  }
967 
968  for (size_type i=0; i<this->n_rows(); ++i)
969  {
970  for (size_type j=0; j<this->n_cols(); ++j)
971  if (std::fabs(this->el(i,j)) > threshold)
972  out << std::setw(width)
973  << this->el(i,j) * denominator << ' ';
974  else
975  out << std::setw(width) << zero_string << ' ';
976  out << std::endl;
977  };
978 
979  AssertThrow (out, ExcIO());
980  // reset output format
981  out.flags (old_flags);
982  out.precision(old_precision);
983 }
984 
985 
986 //----------------------------------------------------------------------//
987 
988 template <typename number>
989 void
991 {
992  matrix = &M;
993  mem = 0;
994 }
995 
996 
997 template <typename number>
998 void
1001 {
1002  matrix = &M;
1003  mem = &V;
1004 }
1005 
1006 
1007 template <typename number>
1008 void
1010  const Vector<number> &src) const
1011 {
1012  dst = src;
1013  matrix->apply_lu_factorization(dst, false);
1014 }
1015 
1016 
1017 template <typename number>
1018 void
1020  const Vector<number> &src) const
1021 {
1022  dst = src;
1023  matrix->apply_lu_factorization(dst, true);
1024 }
1025 
1026 
1027 template <typename number>
1028 void
1030  const BlockVector<number> &src) const
1031 {
1032  Assert(mem != 0, ExcNotInitialized());
1033  Vector<number> *aux = mem->alloc();
1034  *aux = src;
1035  matrix->apply_lu_factorization(*aux, false);
1036  dst = *aux;
1037 }
1038 
1039 
1040 template <typename number>
1041 void
1043  const BlockVector<number> &src) const
1044 {
1045  Assert(mem != 0, ExcNotInitialized());
1046  Vector<number> *aux = mem->alloc();
1047  *aux = src;
1048  matrix->apply_lu_factorization(*aux, true);
1049  dst = *aux;
1050 }
1051 
1052 
1053 
1054 #include "lapack_full_matrix.inst"
1055 
1056 
1057 DEAL_II_NAMESPACE_CLOSE
LAPACKFullMatrix(const size_type size=0)
std_cxx11::shared_ptr< LAPACKFullMatrix< number > > svd_u
std::vector< number > work
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1052
void TmTmult(LAPACKFullMatrix< number > &C, const LAPACKFullMatrix< number > &B, const bool adding=false) const
void Tvmult(Vector< number2 > &w, const Vector< number2 > &v, const bool adding=false) const
LAPACKSupport::State state
AlignedVector< number >::reference el(const unsigned int i, const unsigned int j)
::ExceptionBase & ExcMessage(std::string arg1)
std::vector< number > vr
TableBase< N, T > & operator=(const TableBase< N, T > &src)
#define AssertThrow(cond, exc)
Definition: exceptions.h:358
void compute_eigenvalues_symmetric(const number lower_bound, const number upper_bound, const number abs_accuracy, Vector< number > &eigenvalues, FullMatrix< number > &eigenvectors)
unsigned int n_cols() const
void reinit(const size_type size)
size_type n_elements() const
void Tmmult(LAPACKFullMatrix< number > &C, const LAPACKFullMatrix< number > &B, const bool adding=false) const
size_type n() const
void mTmult(LAPACKFullMatrix< number > &C, const LAPACKFullMatrix< number > &B, const bool adding=false) const
TableBase< 2, T >::size_type size_type
Definition: table.h:1510
size_type n() const
std::vector< int > ipiv
std::vector< number > wr
void reinit(const TableIndices< N > &new_size, const bool omit_default_initialization=false)
std_cxx11::shared_ptr< LAPACKFullMatrix< number > > svd_vt
#define Assert(cond, exc)
Definition: exceptions.h:294
std::size_t size() const
std::vector< number > inv_work
unsigned int n_rows() const
std::vector< number > vl
std::vector< number > wi
iterator begin()
void vmult(Vector< number2 > &w, const Vector< number2 > &v, const bool adding=false) const
void compute_generalized_eigenvalues_symmetric(LAPACKFullMatrix< number > &B, const number lower_bound, const number upper_bound, const number abs_accuracy, Vector< number > &eigenvalues, std::vector< Vector< number > > &eigenvectors, const int itype=1)
void print_formatted(std::ostream &out, const unsigned int precision=3, const bool scientific=true, const unsigned int width=0, const char *zero_string=" ", const double denominator=1., const double threshold=0.) const
void compute_inverse_svd(const double threshold=0.)
LAPACKFullMatrix< number > & operator=(const LAPACKFullMatrix< number > &)
number el(const size_type i, const size_type j) const
void Tvmult_add(Vector< number2 > &w, const Vector< number2 > &v) const
unsigned int m() const
virtual void reinit(const size_type N, const bool omit_zeroing_entries=false)
size_type m() const
unsigned int n() const
void compute_eigenvalues(const bool right_eigenvectors=false, const bool left_eigenvectors=false)
void apply_lu_factorization(Vector< number > &v, const bool transposed) const
Number * val
Definition: vector.h:984
AlignedVector< number > values
Definition: table.h:634
void reinit(const unsigned int size1, const unsigned int size2, const bool omit_default_initialization=false)
void vmult_add(Vector< number2 > &w, const Vector< number2 > &v) const
void mmult(LAPACKFullMatrix< number > &C, const LAPACKFullMatrix< number > &B, const bool adding=false) const