1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1999 - 2019 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.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #ifndef dealii_full_matrix_h
17 #define dealii_full_matrix_h
18 
19 
20 #include <deal.II/base/config.h>
21 
22 #include <deal.II/base/numbers.h>
23 #include <deal.II/base/table.h>
24 #include <deal.II/base/tensor.h>
25 
26 #include <deal.II/differentiation/ad/ad_number_traits.h>
27 
28 #include <deal.II/lac/exceptions.h>
29 #include <deal.II/lac/identity_matrix.h>
30 
31 #include <cstring>
32 #include <iomanip>
33 #include <vector>
34 
35 DEAL_II_NAMESPACE_OPEN
36 
37 
38 // forward declarations
39 #ifndef DOXYGEN
40 template <typename number>
41 class Vector;
42 template <typename number>
43 class LAPACKFullMatrix;
44 #endif
45 
46 /*! @addtogroup Matrix1
47  *@{
48  */
49 
50 
51 /**
52  * Implementation of a classical rectangular scheme of numbers. The data type
53  * of the entries is provided in the template argument <tt>number</tt>.  The
54  * interface is quite fat and in fact has grown every time a new feature was
55  * needed. So, a lot of functions are provided.
56  *
57  * Internal calculations are usually done with the accuracy of the vector
58  * argument to functions. If there is no argument with a number type, the
59  * matrix number type is used.
60  *
61  * @note Instantiations for this template are provided for <tt>@<float@>,
62  * @<double@>, @<std::complex@<float@>@>,
63  * @<std::complex@<double@>@></tt>. Others can be generated in application
64  * programs, see
65  * @ref Instantiations
66  * for details.
67  */
68 template <typename number>
69 class FullMatrix : public Table<2, number>
70 {
71 public:
72   // The assertion in full_matrix.templates.h for whether or not a number is
73   // finite is not compatible for AD number types.
74   static_assert(
75     !Differentiation::AD::is_ad_number<number>::value,
76     "The FullMatrix class does not support auto-differentiable numbers.");
77 
78   /**
79    * A type of used to index into this container.
80    */
81   using size_type = std::size_t;
82 
83   /**
84    * Type of matrix entries. This alias is analogous to <tt>value_type</tt>
85    * in the standard library containers.
86    */
87   using value_type = number;
88 
89   /**
90    * Use the base class mutable iterator type.
91    */
92   using iterator = typename Table<2, number>::iterator;
93 
94   /**
95    * Use the base class constant iterator type.
96    */
97   using const_iterator = typename Table<2, number>::const_iterator;
98 
99   /**
100    * Use the base class iterator functions.
101    */
102   using Table<2, number>::begin;
103 
104   /**
105    * Use the base class iterator functions
106    */
107   using Table<2, number>::end;
108 
109   /**
110    * Declare a type that has holds real-valued numbers with the same precision
111    * as the template argument to this class. If the template argument of this
112    * class is a real data type, then real_type equals the template argument.
113    * If the template argument is a std::complex type then real_type equals the
114    * type underlying the complex numbers.
115    *
116    * This alias is used to represent the return type of norms.
117    */
118   using real_type = typename numbers::NumberTraits<number>::real_type;
119 
120   /**
121    * @name Constructors and initialization.  See also the base class Table.
122    */
123   //@{
124 
125   /**
126    * Constructor. Initialize the matrix as a square matrix with dimension
127    * <tt>n</tt>.
128    *
129    * In order to avoid the implicit conversion of integers and other types to
130    * a matrix, this constructor is declared <tt>explicit</tt>.
131    *
132    * By default, no memory is allocated.
133    */
134   explicit FullMatrix(const size_type n = 0);
135 
136   /**
137    * Constructor. Initialize the matrix as a rectangular matrix.
138    */
139   FullMatrix(const size_type rows, const size_type cols);
140 
141   /**
142    * Constructor initializing from an array of numbers. The array is arranged
143    * line by line. No range checking is performed.
144    */
145   FullMatrix(const size_type rows, const size_type cols, const number *entries);
146 
147   /**
148    * Construct a full matrix that equals the identity matrix of the size of
149    * the argument. Using this constructor, one can easily create an identity
150    * matrix of size <code>n</code> by saying
151    * @code
152    * FullMatrix<double> M(IdentityMatrix(n));
153    * @endcode
154    */
155   FullMatrix(const IdentityMatrix &id);
156   /**
157    * @}
158    */
159 
160   /**
161    * @name Copying into and out of other matrices
162    */
163   /**
164    * @{
165    */
166 
167   /**
168    * Variable assignment operator.
169    */
170   template <typename number2>
171   FullMatrix<number> &
172   operator=(const FullMatrix<number2> &);
173 
174   /**
175    * This operator assigns a scalar to a matrix. To avoid confusion with the
176    * semantics of this function, zero is the only value allowed for
177    * <tt>d</tt>, allowing you to clear a matrix in an intuitive way.
178    *
179    * @dealiiOperationIsMultithreaded
180    */
181   FullMatrix<number> &
182   operator=(const number d);
183 
184   /**
185    * Copy operator to create a full matrix that equals the identity matrix of
186    * the size of the argument. This way, one can easily create an identity
187    * matrix of size <code>n</code> by saying
188    * @code
189    *   M = IdentityMatrix(n);
190    * @endcode
191    */
192   FullMatrix<number> &
193   operator=(const IdentityMatrix &id);
194 
195   /**
196    * Assignment operator for a LapackFullMatrix. The calling matrix must be of
197    * the same size as the LAPACK matrix.
198    */
199   template <typename number2>
200   FullMatrix<number> &
201   operator=(const LAPACKFullMatrix<number2> &);
202 
203 
204   /**
205    * Assignment from different matrix classes. This assignment operator uses
206    * iterators of the typename MatrixType. Therefore, sparse matrices are
207    * possible sources.
208    */
209   template <typename MatrixType>
210   void
211   copy_from(const MatrixType &);
212 
213   /**
214    * Transposing assignment from different matrix classes. This assignment
215    * operator uses iterators of the typename MatrixType. Therefore, sparse
216    * matrices are possible sources.
217    */
218   template <typename MatrixType>
219   void
220   copy_transposed(const MatrixType &);
221 
222   /**
223    * Fill matrix with elements extracted from a tensor, taking rows included
224    * between <tt>r_i</tt> and <tt>r_j</tt> and columns between <tt>c_i</tt>
225    * and <tt>c_j</tt>. The resulting matrix is then inserted in the
226    * destination matrix at position <tt>(dst_r, dst_c)</tt> Checks on the
227    * indices are made.
228    */
229   template <int dim>
230   void
231   copy_from(const Tensor<2, dim> &T,
232             const unsigned int    src_r_i = 0,
233             const unsigned int    src_r_j = dim - 1,
234             const unsigned int    src_c_i = 0,
235             const unsigned int    src_c_j = dim - 1,
236             const size_type       dst_r   = 0,
237             const size_type       dst_c   = 0);
238 
239   /**
240    * Insert a submatrix (also rectangular) into a tensor, putting its upper
241    * left element at the specified position <tt>(dst_r, dst_c)</tt> and the
242    * other elements consequently. Default values are chosen so that no
243    * parameter needs to be specified if the size of the tensor and that of the
244    * matrix coincide.
245    */
246   template <int dim>
247   void copy_to(Tensor<2, dim> &   T,
248                const size_type    src_r_i = 0,
249                const size_type    src_r_j = dim - 1,
250                const size_type    src_c_i = 0,
251                const size_type    src_c_j = dim - 1,
252                const unsigned int dst_r   = 0,
253                const unsigned int dst_c   = 0) const;
254 
255   /**
256    * Copy a subset of the rows and columns of another matrix into the current
257    * object.
258    *
259    * @param matrix The matrix from which a subset is to be taken from.
260    * @param row_index_set The set of rows of @p matrix from which to extract.
261    * @param column_index_set The set of columns of @p matrix from which to
262    * extract. @pre The number of elements in @p row_index_set and @p
263    * column_index_set shall be equal to the number of rows and columns in the
264    * current object. In other words, the current object is not resized for
265    * this operation.
266    */
267   template <typename MatrixType, typename index_type>
268   void
269   extract_submatrix_from(const MatrixType &             matrix,
270                          const std::vector<index_type> &row_index_set,
271                          const std::vector<index_type> &column_index_set);
272 
273   /**
274    * Copy the elements of the current matrix object into a specified set of
275    * rows and columns of another matrix. Thus, this is a scatter operation.
276    *
277    * @param row_index_set The rows of @p matrix into which to write.
278    * @param column_index_set The columns of @p matrix into which to write.
279    * @param matrix The matrix within which certain elements are to be
280    * replaced. @pre The number of elements in @p row_index_set and @p
281    * column_index_set shall be equal to the number of rows and columns in the
282    * current object. In other words, the current object is not resized for
283    * this operation.
284    */
285   template <typename MatrixType, typename index_type>
286   void
287   scatter_matrix_to(const std::vector<index_type> &row_index_set,
288                     const std::vector<index_type> &column_index_set,
289                     MatrixType &                   matrix) const;
290 
291   /**
292    * Fill rectangular block.
293    *
294    * A rectangular block of the matrix <tt>src</tt> is copied into
295    * <tt>this</tt>. The upper left corner of the block being copied is
296    * <tt>(src_offset_i,src_offset_j)</tt>.  The upper left corner of the
297    * copied block is <tt>(dst_offset_i,dst_offset_j)</tt>.  The size of the
298    * rectangular block being copied is the maximum size possible, determined
299    * either by the size of <tt>this</tt> or <tt>src</tt>.
300    */
301   template <typename number2>
302   void
303   fill(const FullMatrix<number2> &src,
304        const size_type            dst_offset_i = 0,
305        const size_type            dst_offset_j = 0,
306        const size_type            src_offset_i = 0,
307        const size_type            src_offset_j = 0);
308 
309 
310   /**
311    * Make function of base class available.
312    */
313   template <typename number2>
314   void
315   fill(const number2 *);
316 
317   /**
318    * Fill with permutation of another matrix.
319    *
320    * The matrix <tt>src</tt> is copied into the target. The two permutation
321    * <tt>p_r</tt> and <tt>p_c</tt> operate in a way, such that <tt>result(i,j)
322    * = src(p_r[i], p_c[j])</tt>.
323    *
324    * The vectors may also be a selection from a larger set of integers, if the
325    * matrix <tt>src</tt> is bigger. It is also possible to duplicate rows or
326    * columns by this method.
327    */
328   template <typename number2>
329   void
330   fill_permutation(const FullMatrix<number2> &   src,
331                    const std::vector<size_type> &p_rows,
332                    const std::vector<size_type> &p_cols);
333 
334   /**
335    * Set a particular entry of the matrix to a value. Thus, calling
336    * <code>A.set(1,2,3.141);</code> is entirely equivalent to the operation
337    * <code>A(1,2) = 3.141;</code>. This function exists for compatibility with
338    * the various sparse matrix objects.
339    *
340    * @param i The row index of the element to be set.
341    * @param j The columns index of the element to be set.
342    * @param value The value to be written into the element.
343    */
344   void
345   set(const size_type i, const size_type j, const number value);
346   /**
347    * @}
348    */
349   /**
350    * @name Non-modifying operators
351    */
352   /**
353    * @{
354    */
355 
356   /**
357    * Comparison operator. Be careful with this thing, it may eat up huge
358    * amounts of computing time! It is most commonly used for internal
359    * consistency checks of programs.
360    */
361   bool
362   operator==(const FullMatrix<number> &) const;
363 
364   /**
365    * Number of rows of this matrix.  Note that the matrix is of dimension <i>m
366    * x n</i>.
367    */
368   size_type
369   m() const;
370 
371   /**
372    * Number of columns of this matrix.  Note that the matrix is of dimension
373    * <i>m x n</i>.
374    */
375   size_type
376   n() const;
377 
378   /**
379    * Return whether the matrix contains only elements with value zero. This
380    * function is mainly for internal consistency checks and should seldom be
381    * used when not in debug mode since it uses quite some time.
382    */
383   bool
384   all_zero() const;
385 
386   /**
387    * Return the square of the norm of the vector <tt>v</tt> induced by this
388    * matrix, i.e. <i>(v,Mv)</i>. This is useful, e.g. in the finite element
389    * context, where the <i>L<sup>2</sup></i> norm of a function equals the
390    * matrix norm with respect to the mass matrix of the vector representing
391    * the nodal values of the finite element function.
392    *
393    * Obviously, the matrix needs to be quadratic for this operation, and for
394    * the result to actually be a norm it also needs to be either real
395    * symmetric or complex hermitian.
396    *
397    * The underlying template types of both this matrix and the given vector
398    * should either both be real or complex-valued, but not mixed, for this
399    * function to make sense.
400    */
401   template <typename number2>
402   number2
403   matrix_norm_square(const Vector<number2> &v) const;
404 
405   /**
406    * Build the matrix scalar product <tt>u<sup>T</sup> M v</tt>. This function
407    * is mostly useful when building the cellwise scalar product of two
408    * functions in the finite element context.
409    *
410    * The underlying template types of both this matrix and the given vector
411    * should either both be real or complex-valued, but not mixed, for this
412    * function to make sense.
413    */
414   template <typename number2>
415   number2
416   matrix_scalar_product(const Vector<number2> &u,
417                         const Vector<number2> &v) const;
418 
419   /**
420    * Return the <i>l<sub>1</sub></i>-norm of the matrix, where $||M||_1 =
421    * \max_j \sum_i |M_{ij}|$ (maximum of the sums over columns).
422    */
423   real_type
424   l1_norm() const;
425 
426   /**
427    * Return the $l_\infty$-norm of the matrix, where $||M||_\infty = \max_i
428    * \sum_j |M_{ij}|$ (maximum of the sums over rows).
429    */
430   real_type
431   linfty_norm() const;
432 
433   /**
434    * Compute the Frobenius norm of the matrix.  Return value is the root of
435    * the square sum of all matrix entries.
436    *
437    * @note For the timid among us: this norm is not the norm compatible with
438    * the <i>l<sub>2</sub></i>-norm of the vector space.
439    */
440   real_type
441   frobenius_norm() const;
442 
443   /**
444    * Compute the relative norm of the skew-symmetric part. The return value is
445    * the Frobenius norm of the skew-symmetric part of the matrix divided by
446    * that of the matrix.
447    *
448    * Main purpose of this function is to check, if a matrix is symmetric
449    * within a certain accuracy, or not.
450    */
451   real_type
452   relative_symmetry_norm2() const;
453 
454   /**
455    * Compute the determinant of a matrix.  This is only implemented for one,
456    * two, and three dimensions, since for higher dimensions the numerical work
457    * explodes.  Obviously, the matrix needs to be quadratic for this function.
458    */
459   number
460   determinant() const;
461 
462   /**
463    * Return the trace of the matrix, i.e. the sum of the diagonal values
464    * (which happens to also equal the sum of the eigenvalues of a matrix).
465    * Obviously, the matrix needs to be quadratic for this function.
466    */
467   number
468   trace() const;
469 
470   /**
471    * Output of the matrix in user-defined format given by the specified
472    * precision and width. This function saves width and precision of the
473    * stream before setting these given values for output, and restores the
474    * previous values after output.
475    */
476   template <class StreamType>
477   void
478   print(StreamType &       s,
479         const unsigned int width     = 5,
480         const unsigned int precision = 2) const;
481 
482   /**
483    * Print the matrix and allow formatting of entries.
484    *
485    * The parameters allow for a flexible setting of the output format:
486    *
487    * @arg <tt>precision</tt> denotes the number of trailing digits.
488    *
489    * @arg <tt>scientific</tt> is used to determine the number format, where
490    * <tt>scientific</tt> = <tt>false</tt> means fixed point notation.
491    *
492    * @arg <tt>width</tt> denotes the with of each column. A zero entry for
493    * <tt>width</tt> makes the function compute a width, but it may be changed
494    * to a positive value, if output is crude.
495    *
496    * @arg <tt>zero_string</tt> specifies a string printed for zero entries.
497    *
498    * @arg <tt>denominator</tt> Multiply the whole matrix by this common
499    * denominator to get nicer numbers.
500    *
501    * @arg <tt>threshold</tt>: all entries with absolute value smaller than
502    * this are considered zero.
503    */
504   void
505   print_formatted(std::ostream &     out,
506                   const unsigned int precision   = 3,
507                   const bool         scientific  = true,
508                   const unsigned int width       = 0,
509                   const char *       zero_string = " ",
510                   const double       denominator = 1.,
511                   const double       threshold   = 0.) const;
512 
513   /**
514    * Determine an estimate for the memory consumption (in bytes) of this
515    * object.
516    */
517   std::size_t
518   memory_consumption() const;
519 
520   //@}
521   ///@name Iterator functions
522   //@{
523 
524   /**
525    * Mutable iterator starting at the first entry of row <tt>r</tt>.
526    */
527   iterator
528   begin(const size_type r);
529 
530   /**
531    * One past the end mutable iterator of row <tt>r</tt>.
532    */
533   iterator
534   end(const size_type r);
535 
536   /**
537    * Constant iterator starting at the first entry of row <tt>r</tt>.
538    */
539   const_iterator
540   begin(const size_type r) const;
541 
542   /**
543    * One past the end constant iterator of row <tt>r</tt>.
544    */
545   const_iterator
546   end(const size_type r) const;
547 
548   //@}
549   ///@name Modifying operators
550   //@{
551 
552   /**
553    * Scale the entire matrix by a fixed factor.
554    */
555   FullMatrix &
556   operator*=(const number factor);
557 
558   /**
559    * Scale the entire matrix by the inverse of the given factor.
560    */
561   FullMatrix &
562   operator/=(const number factor);
563 
564   /**
565    * Simple addition of a scaled matrix, i.e. <tt>*this += a*A</tt>.
566    *
567    * The matrix <tt>A</tt> may be a full matrix over an arbitrary underlying
568    * scalar type, as long as its data type is convertible to the data type of
569    * this matrix.
570    */
571   template <typename number2>
572   void
573   add(const number a, const FullMatrix<number2> &A);
574 
575   /**
576    * Multiple addition of scaled matrices, i.e. <tt>*this += a*A + b*B</tt>.
577    *
578    * The matrices <tt>A</tt> and <tt>B</tt> may be a full matrix over an
579    * arbitrary underlying scalar type, as long as its data type is convertible
580    * to the data type of this matrix.
581    */
582   template <typename number2>
583   void
584   add(const number               a,
585       const FullMatrix<number2> &A,
586       const number               b,
587       const FullMatrix<number2> &B);
588 
589   /**
590    * Multiple addition of scaled matrices, i.e. <tt>*this += a*A + b*B +
591    * c*C</tt>.
592    *
593    * The matrices <tt>A</tt>, <tt>B</tt> and <tt>C</tt> may be a full matrix
594    * over an arbitrary underlying scalar type, as long as its data type is
595    * convertible to the data type of this matrix.
596    */
597   template <typename number2>
598   void
599   add(const number               a,
600       const FullMatrix<number2> &A,
601       const number               b,
602       const FullMatrix<number2> &B,
603       const number               c,
604       const FullMatrix<number2> &C);
605 
606   /**
607    * Add rectangular block.
608    *
609    * A rectangular block of the matrix <tt>src</tt> is added to <tt>this</tt>.
610    * The upper left corner of the block being copied is
611    * <tt>(src_offset_i,src_offset_j)</tt>.  The upper left corner of the
612    * copied block is <tt>(dst_offset_i,dst_offset_j)</tt>.  The size of the
613    * rectangular block being copied is the maximum size possible, determined
614    * either by the size of <tt>this</tt> or <tt>src</tt> and the given
615    * offsets.
616    */
617   template <typename number2>
618   void
619   add(const FullMatrix<number2> &src,
620       const number               factor,
621       const size_type            dst_offset_i = 0,
622       const size_type            dst_offset_j = 0,
623       const size_type            src_offset_i = 0,
624       const size_type            src_offset_j = 0);
625 
626   /**
627    * Weighted addition of the transpose of <tt>B</tt> to <tt>this</tt>.
628    *
629    * <i>A += s B<sup>T</sup></i>
630    */
631   template <typename number2>
632   void
633   Tadd(const number s, const FullMatrix<number2> &B);
634 
635   /**
636    * Add transpose of a rectangular block.
637    *
638    * A rectangular block of the matrix <tt>src</tt> is transposed and
639    * addedadded to <tt>this</tt>. The upper left corner of the block being
640    * copied is <tt>(src_offset_i,src_offset_j)</tt> in the coordinates of the
641    * <b>non</b>-transposed matrix.  The upper left corner of the copied block
642    * is <tt>(dst_offset_i,dst_offset_j)</tt>.  The size of the rectangular
643    * block being copied is the maximum size possible, determined either by the
644    * size of <tt>this</tt> or <tt>src</tt>.
645    */
646   template <typename number2>
647   void
648   Tadd(const FullMatrix<number2> &src,
649        const number               factor,
650        const size_type            dst_offset_i = 0,
651        const size_type            dst_offset_j = 0,
652        const size_type            src_offset_i = 0,
653        const size_type            src_offset_j = 0);
654 
655   /**
656    * Add a single element at the given position.
657    */
658   void
659   add(const size_type row, const size_type column, const number value);
660 
661   /**
662    * Add an array of values given by <tt>values</tt> in the given global
663    * matrix row at columns specified by col_indices in the full matrix. This
664    * function is present for compatibility with the various sparse matrices in
665    * deal.II. In particular, the two boolean fields @p elide_zero_values and
666    * @p col_indices_are_sorted do not impact the performance of this routine,
667    * as opposed to the sparse matrix case and are indeed ignored in the
668    * implementation.
669    */
670   template <typename number2, typename index_type>
671   void
672   add(const size_type   row,
673       const size_type   n_cols,
674       const index_type *col_indices,
675       const number2 *   values,
676       const bool        elide_zero_values      = true,
677       const bool        col_indices_are_sorted = false);
678 
679   /**
680    * <i>A(i,1...n) += s*A(j,1...n)</i>.  Simple addition of rows of this
681    */
682   void
683   add_row(const size_type i, const number s, const size_type j);
684 
685   /**
686    * <i>A(i,1...n) += s*A(j,1...n) + t*A(k,1...n)</i>.  Multiple addition of
687    * rows of this.
688    */
689   void
690   add_row(const size_type i,
691           const number    s,
692           const size_type j,
693           const number    t,
694           const size_type k);
695 
696   /**
697    * <i>A(1...n,i) += s*A(1...n,j)</i>.  Simple addition of columns of this.
698    */
699   void
700   add_col(const size_type i, const number s, const size_type j);
701 
702   /**
703    * <i>A(1...n,i) += s*A(1...n,j) + t*A(1...n,k)</i>.  Multiple addition of
704    * columns of this.
705    */
706   void
707   add_col(const size_type i,
708           const number    s,
709           const size_type j,
710           const number    t,
711           const size_type k);
712 
713   /**
714    * Swap <i>A(i,1...n) <-> A(j,1...n)</i>.  Swap rows i and j of this
715    */
716   void
717   swap_row(const size_type i, const size_type j);
718 
719   /**
720    * Swap <i>A(1...n,i) <-> A(1...n,j)</i>.  Swap columns i and j of this
721    */
722   void
723   swap_col(const size_type i, const size_type j);
724 
725   /**
726    * Add constant to diagonal elements of this, i.e. add a multiple of the
727    * identity matrix.
728    */
729   void
730   diagadd(const number s);
731 
732   /**
733    * Assignment <tt>*this = a*A</tt>.
734    */
735   template <typename number2>
736   void
737   equ(const number a, const FullMatrix<number2> &A);
738 
739   /**
740    * Assignment <tt>*this = a*A + b*B</tt>.
741    */
742   template <typename number2>
743   void
744   equ(const number               a,
745       const FullMatrix<number2> &A,
746       const number               b,
747       const FullMatrix<number2> &B);
748 
749   /**
750    * Assignment <tt>*this = a*A + b*B + c*C</tt>.
751    */
752   template <typename number2>
753   void
754   equ(const number               a,
755       const FullMatrix<number2> &A,
756       const number               b,
757       const FullMatrix<number2> &B,
758       const number               c,
759       const FullMatrix<number2> &C);
760 
761   /**
762    * Symmetrize the matrix by forming the mean value between the existing
763    * matrix and its transpose, <i>A = 1/2(A+A<sup>T</sup>)</i>.
764    *
765    * Obviously the matrix must be quadratic for this operation.
766    */
767   void
768   symmetrize();
769 
770   /**
771    * A=Inverse(A). A must be a square matrix.  Inversion of this matrix by
772    * Gauss-Jordan algorithm with partial pivoting.  This process is well-
773    * behaved for positive definite matrices, but be aware of round-off errors
774    * in the indefinite case.
775    *
776    * In case deal.II was configured with LAPACK, the functions Xgetrf and
777    * Xgetri build an LU factorization and invert the matrix upon that
778    * factorization, providing best performance up to matrices with a few
779    * hundreds rows and columns.
780    *
781    * The numerical effort to invert an <tt>n x n</tt> matrix is of the order
782    * <tt>n**3</tt>.
783    */
784   void
785   gauss_jordan();
786 
787   /**
788    * Assign the inverse of the given matrix to <tt>*this</tt>. This function
789    * is hardcoded for quadratic matrices of dimension one to four. However,
790    * since the amount of code needed grows quickly, the method gauss_jordan()
791    * is invoked implicitly if the dimension is larger.
792    */
793   template <typename number2>
794   void
795   invert(const FullMatrix<number2> &M);
796 
797   /**
798    * Assign the Cholesky decomposition $A=:L L^T$ of the given matrix $A$ to
799    * <tt>*this</tt>, where $L$ is lower triangular matrix. The given matrix must
800    * be symmetric positive definite.
801    *
802    * ExcMatrixNotPositiveDefinite will be thrown in the case that the matrix
803    * is not positive definite.
804    */
805   template <typename number2>
806   void
807   cholesky(const FullMatrix<number2> &A);
808 
809   /**
810    * <tt>*this(i,j)</tt> = $V(i) W(j)$ where $V,W$ are vectors of the same
811    * length.
812    */
813   template <typename number2>
814   void
815   outer_product(const Vector<number2> &V, const Vector<number2> &W);
816 
817   /**
818    * Assign the left_inverse of the given matrix to <tt>*this</tt>. The
819    * calculation being performed is <i>(A<sup>T</sup>*A)<sup>-1</sup>
820    * *A<sup>T</sup></i>.
821    */
822   template <typename number2>
823   void
824   left_invert(const FullMatrix<number2> &M);
825 
826   /**
827    * Assign the right_inverse of the given matrix to <tt>*this</tt>. The
828    * calculation being performed is <i>A<sup>T</sup>*(A*A<sup>T</sup>)
829    * <sup>-1</sup></i>.
830    */
831   template <typename number2>
832   void
833   right_invert(const FullMatrix<number2> &M);
834 
835   //@}
836   ///@name Multiplications
837   //@{
838 
839   /**
840    * Matrix-matrix-multiplication.
841    *
842    * The optional parameter <tt>adding</tt> determines, whether the result is
843    * stored in <tt>C</tt> or added to <tt>C</tt>.
844    *
845    * if (adding) <i>C += A*B</i>
846    *
847    * if (!adding) <i>C = A*B</i>
848    *
849    * Assumes that <tt>A</tt> and <tt>B</tt> have compatible sizes and that
850    * <tt>C</tt> already has the right size.
851    *
852    * This function uses the BLAS function Xgemm if the product of the three
853    * matrix dimensions is larger than 300 and BLAS was detected during
854    * configuration. Using BLAS usually results in considerable performance
855    * gains.
856    */
857   template <typename number2>
858   void
859   mmult(FullMatrix<number2> &      C,
860         const FullMatrix<number2> &B,
861         const bool                 adding = false) const;
862 
863   /**
864    * Matrix-matrix-multiplication using transpose of <tt>this</tt>.
865    *
866    * The optional parameter <tt>adding</tt> determines, whether the result is
867    * stored in <tt>C</tt> or added to <tt>C</tt>.
868    *
869    * if (adding) <i>C += A<sup>T</sup>*B</i>
870    *
871    * if (!adding) <i>C = A<sup>T</sup>*B</i>
872    *
873    * Assumes that <tt>A</tt> and <tt>B</tt> have compatible sizes and that
874    * <tt>C</tt> already has the right size.
875    *
876    * This function uses the BLAS function Xgemm if the product of the three
877    * matrix dimensions is larger than 300 and BLAS was detected during
878    * configuration. Using BLAS usually results in considerable performance
879    * gains.
880    */
881   template <typename number2>
882   void
883   Tmmult(FullMatrix<number2> &      C,
884          const FullMatrix<number2> &B,
885          const bool                 adding = false) const;
886 
887   /**
888    * Matrix-matrix-multiplication using transpose of <tt>B</tt>.
889    *
890    * The optional parameter <tt>adding</tt> determines, whether the result is
891    * stored in <tt>C</tt> or added to <tt>C</tt>.
892    *
893    * if (adding) <i>C += A*B<sup>T</sup></i>
894    *
895    * if (!adding) <i>C = A*B<sup>T</sup></i>
896    *
897    * Assumes that <tt>A</tt> and <tt>B</tt> have compatible sizes and that
898    * <tt>C</tt> already has the right size.
899    *
900    * This function uses the BLAS function Xgemm if the product of the three
901    * matrix dimensions is larger than 300 and BLAS was detected during
902    * configuration. Using BLAS usually results in considerable performance
903    * gains.
904    */
905   template <typename number2>
906   void
907   mTmult(FullMatrix<number2> &      C,
908          const FullMatrix<number2> &B,
909          const bool                 adding = false) const;
910 
911   /**
912    * Matrix-matrix-multiplication using transpose of <tt>this</tt> and
913    * <tt>B</tt>.
914    *
915    * The optional parameter <tt>adding</tt> determines, whether the result is
916    * stored in <tt>C</tt> or added to <tt>C</tt>.
917    *
918    * if (adding) <i>C += A<sup>T</sup>*B<sup>T</sup></i>
919    *
920    * if (!adding) <i>C = A<sup>T</sup>*B<sup>T</sup></i>
921    *
922    * Assumes that <tt>A</tt> and <tt>B</tt> have compatible sizes and that
923    * <tt>C</tt> already has the right size.
924    *
925    * This function uses the BLAS function Xgemm if the product of the three
926    * matrix dimensions is larger than 300 and BLAS was detected during
927    * configuration. Using BLAS usually results in considerable performance
928    * gains.
929    */
930   template <typename number2>
931   void
932   TmTmult(FullMatrix<number2> &      C,
933           const FullMatrix<number2> &B,
934           const bool                 adding = false) const;
935 
936   /**
937    * Add to the current matrix the triple product <b>B A D</b>. Optionally,
938    * use the transposes of the matrices <b>B</b> and <b>D</b>. The scaling
939    * factor scales the whole product, which is helpful when adding a multiple
940    * of the triple product to the matrix.
941    *
942    * This product was written with the Schur complement <b>B<sup>T</sup>
943    * A<sup>-1</sup> D</b> in mind.  Note that in this case the argument for
944    * <tt>A</tt> must be the inverse of the matrix <b>A</b>.
945    */
946   void
947   triple_product(const FullMatrix<number> &A,
948                  const FullMatrix<number> &B,
949                  const FullMatrix<number> &D,
950                  const bool                transpose_B = false,
951                  const bool                transpose_D = false,
952                  const number              scaling     = number(1.));
953 
954   /**
955    * Matrix-vector-multiplication.
956    *
957    * The optional parameter <tt>adding</tt> determines, whether the result is
958    * stored in <tt>w</tt> or added to <tt>w</tt>.
959    *
960    * if (adding) <i>w += A*v</i>
961    *
962    * if (!adding) <i>w = A*v</i>
963    *
964    * Source and destination must not be the same vector.
965    */
966   template <typename number2>
967   void
968   vmult(Vector<number2> &      w,
969         const Vector<number2> &v,
970         const bool             adding = false) const;
971 
972   /**
973    * Adding Matrix-vector-multiplication.  <i>w += A*v</i>
974    *
975    * Source and destination must not be the same vector.
976    */
977   template <typename number2>
978   void
979   vmult_add(Vector<number2> &w, const Vector<number2> &v) const;
980 
981   /**
982    * Transpose matrix-vector-multiplication.
983    *
984    * The optional parameter <tt>adding</tt> determines, whether the result is
985    * stored in <tt>w</tt> or added to <tt>w</tt>.
986    *
987    * if (adding) <i>w += A<sup>T</sup>*v</i>
988    *
989    * if (!adding) <i>w = A<sup>T</sup>*v</i>
990    *
991    *
992    * Source and destination must not be the same vector.
993    */
994   template <typename number2>
995   void
996   Tvmult(Vector<number2> &      w,
997          const Vector<number2> &v,
998          const bool             adding = false) const;
999 
1000   /**
1001    * Adding transpose matrix-vector-multiplication.  <i>w +=
1002    * A<sup>T</sup>*v</i>
1003    *
1004    * Source and destination must not be the same vector.
1005    */
1006   template <typename number2>
1007   void
1008   Tvmult_add(Vector<number2> &w, const Vector<number2> &v) const;
1009 
1010   /**
1011    * Apply the Jacobi preconditioner, which multiplies every element of the
1012    * <tt>src</tt> vector by the inverse of the respective diagonal element and
1013    * multiplies the result with the damping factor <tt>omega</tt>.
1014    */
1015   template <typename somenumber>
1016   void
1017   precondition_Jacobi(Vector<somenumber> &      dst,
1018                       const Vector<somenumber> &src,
1019                       const number              omega = 1.) const;
1020 
1021   /**
1022    * <i>dst=b-A*x</i>. Residual calculation, returns the
1023    * <i>l<sub>2</sub></i>-norm |<i>dst</i>|.
1024    *
1025    * Source <i>x</i> and destination <i>dst</i> must not be the same vector.
1026    */
1027   template <typename number2, typename number3>
1028   number
1029   residual(Vector<number2> &      dst,
1030            const Vector<number2> &x,
1031            const Vector<number3> &b) const;
1032 
1033   /**
1034    * Forward elimination of lower triangle.  Inverts the lower triangle of a
1035    * rectangular matrix for a given right hand side.
1036    *
1037    * If the matrix has more columns than rows, this function only operates on
1038    * the left quadratic submatrix. If there are more rows, the upper quadratic
1039    * part of the matrix is considered.
1040    *
1041    * @note It is safe to use the same object for @p dst and @p src.
1042    */
1043   template <typename number2>
1044   void
1045   forward(Vector<number2> &dst, const Vector<number2> &src) const;
1046 
1047   /**
1048    * Backward elimination of upper triangle.
1049    *
1050    * See forward()
1051    *
1052    * @note It is safe to use the same object for @p dst and @p src.
1053    */
1054   template <typename number2>
1055   void
1056   backward(Vector<number2> &dst, const Vector<number2> &src) const;
1057 
1058   //@}
1059 
1060   /**
1061    * @addtogroup Exceptions
1062    * @{
1063    */
1064 
1065   /**
1066    * Exception
1067    */
1068   DeclException0(ExcEmptyMatrix);
1069 
1070   /**
1071    * Exception
1072    */
1073   DeclException1(
1074     ExcNotRegular,
1075     number,
1076     << "The maximal pivot is " << arg1
1077     << ", which is below the threshold. The matrix may be singular.");
1078   /**
1079    * Exception
1080    */
1081   DeclException3(ExcInvalidDestination,
1082                  size_type,
1083                  size_type,
1084                  size_type,
1085                  << "Target region not in matrix: size in this direction="
1086                  << arg1 << ", size of new matrix=" << arg2
1087                  << ", offset=" << arg3);
1088   /**
1089    * Exception
1090    */
1091   DeclExceptionMsg(ExcSourceEqualsDestination,
1092                    "You are attempting an operation on two matrices that "
1093                    "are the same object, but the operation requires that the "
1094                    "two objects are in fact different.");
1095   /**
1096    * Exception
1097    */
1098   DeclException0(ExcMatrixNotPositiveDefinite);
1099   //@}
1100 };
1101 
1102 /**@}*/
1103 
1104 #ifndef DOXYGEN
1105 /*-------------------------Inline functions -------------------------------*/
1106 
1107 
1108 
1109 template <typename number>
1110 inline typename FullMatrix<number>::size_type
m()1111 FullMatrix<number>::m() const
1112 {
1113   return this->n_rows();
1114 }
1115 
1116 
1117 
1118 template <typename number>
1119 inline typename FullMatrix<number>::size_type
n()1120 FullMatrix<number>::n() const
1121 {
1122   return this->n_cols();
1123 }
1124 
1125 
1126 
1127 template <typename number>
1128 FullMatrix<number> &
1129 FullMatrix<number>::operator=(const number d)
1130 {
1131   Assert(d == number(0), ExcScalarAssignmentOnlyForZeroValue());
1132   (void)d; // removes -Wunused-parameter warning in optimized mode
1133 
1134   if (this->n_elements() != 0)
1135     this->reset_values();
1136 
1137   return *this;
1138 }
1139 
1140 
1141 
1142 template <typename number>
1143 template <typename number2>
1144 inline void
fill(const number2 * src)1145 FullMatrix<number>::fill(const number2 *src)
1146 {
1147   Table<2, number>::fill(src);
1148 }
1149 
1150 
1151 
1152 template <typename number>
1153 template <typename MatrixType>
1154 void
copy_from(const MatrixType & M)1155 FullMatrix<number>::copy_from(const MatrixType &M)
1156 {
1157   this->reinit(M.m(), M.n());
1158 
1159   // loop over the elements of the argument matrix row by row, as suggested
1160   // in the documentation of the sparse matrix iterator class, and
1161   // copy them into the current object
1162   for (size_type row = 0; row < M.m(); ++row)
1163     {
1164       const typename MatrixType::const_iterator end_row = M.end(row);
1165       for (typename MatrixType::const_iterator entry = M.begin(row);
1166            entry != end_row;
1167            ++entry)
1168         this->el(row, entry->column()) = entry->value();
1169     }
1170 }
1171 
1172 
1173 
1174 template <typename number>
1175 template <typename MatrixType>
1176 void
copy_transposed(const MatrixType & M)1177 FullMatrix<number>::copy_transposed(const MatrixType &M)
1178 {
1179   this->reinit(M.n(), M.m());
1180 
1181   // loop over the elements of the argument matrix row by row, as suggested
1182   // in the documentation of the sparse matrix iterator class, and
1183   // copy them into the current object
1184   for (size_type row = 0; row < M.m(); ++row)
1185     {
1186       const typename MatrixType::const_iterator end_row = M.end(row);
1187       for (typename MatrixType::const_iterator entry = M.begin(row);
1188            entry != end_row;
1189            ++entry)
1190         this->el(entry->column(), row) = entry->value();
1191     }
1192 }
1193 
1194 
1195 
1196 template <typename number>
1197 template <typename MatrixType, typename index_type>
1198 inline void
extract_submatrix_from(const MatrixType & matrix,const std::vector<index_type> & row_index_set,const std::vector<index_type> & column_index_set)1199 FullMatrix<number>::extract_submatrix_from(
1200   const MatrixType &             matrix,
1201   const std::vector<index_type> &row_index_set,
1202   const std::vector<index_type> &column_index_set)
1203 {
1204   AssertDimension(row_index_set.size(), this->n_rows());
1205   AssertDimension(column_index_set.size(), this->n_cols());
1206 
1207   const size_type n_rows_submatrix = row_index_set.size();
1208   const size_type n_cols_submatrix = column_index_set.size();
1209 
1210   for (size_type sub_row = 0; sub_row < n_rows_submatrix; ++sub_row)
1211     for (size_type sub_col = 0; sub_col < n_cols_submatrix; ++sub_col)
1212       (*this)(sub_row, sub_col) =
1213         matrix.el(row_index_set[sub_row], column_index_set[sub_col]);
1214 }
1215 
1216 
1217 
1218 template <typename number>
1219 template <typename MatrixType, typename index_type>
1220 inline void
scatter_matrix_to(const std::vector<index_type> & row_index_set,const std::vector<index_type> & column_index_set,MatrixType & matrix)1221 FullMatrix<number>::scatter_matrix_to(
1222   const std::vector<index_type> &row_index_set,
1223   const std::vector<index_type> &column_index_set,
1224   MatrixType &                   matrix) const
1225 {
1226   AssertDimension(row_index_set.size(), this->n_rows());
1227   AssertDimension(column_index_set.size(), this->n_cols());
1228 
1229   const size_type n_rows_submatrix = row_index_set.size();
1230   const size_type n_cols_submatrix = column_index_set.size();
1231 
1232   for (size_type sub_row = 0; sub_row < n_rows_submatrix; ++sub_row)
1233     for (size_type sub_col = 0; sub_col < n_cols_submatrix; ++sub_col)
1234       matrix.set(row_index_set[sub_row],
1235                  column_index_set[sub_col],
1236                  (*this)(sub_row, sub_col));
1237 }
1238 
1239 
1240 template <typename number>
1241 inline void
set(const size_type i,const size_type j,const number value)1242 FullMatrix<number>::set(const size_type i,
1243                         const size_type j,
1244                         const number    value)
1245 {
1246   (*this)(i, j) = value;
1247 }
1248 
1249 
1250 
1251 template <typename number>
1252 template <typename number2>
1253 void
vmult_add(Vector<number2> & w,const Vector<number2> & v)1254 FullMatrix<number>::vmult_add(Vector<number2> &      w,
1255                               const Vector<number2> &v) const
1256 {
1257   vmult(w, v, true);
1258 }
1259 
1260 
1261 template <typename number>
1262 template <typename number2>
1263 void
Tvmult_add(Vector<number2> & w,const Vector<number2> & v)1264 FullMatrix<number>::Tvmult_add(Vector<number2> &      w,
1265                                const Vector<number2> &v) const
1266 {
1267   Tvmult(w, v, true);
1268 }
1269 
1270 
1271 //---------------------------------------------------------------------------
1272 template <typename number>
1273 inline typename FullMatrix<number>::iterator
begin(const size_type r)1274 FullMatrix<number>::begin(const size_type r)
1275 {
1276   AssertIndexRange(r, m());
1277   return iterator(this, r, 0);
1278 }
1279 
1280 
1281 
1282 template <typename number>
1283 inline typename FullMatrix<number>::iterator
end(const size_type r)1284 FullMatrix<number>::end(const size_type r)
1285 {
1286   AssertIndexRange(r, m());
1287   return iterator(this, r + 1, 0);
1288 }
1289 
1290 
1291 
1292 template <typename number>
1293 inline typename FullMatrix<number>::const_iterator
begin(const size_type r)1294 FullMatrix<number>::begin(const size_type r) const
1295 {
1296   AssertIndexRange(r, m());
1297   return const_iterator(this, r, 0);
1298 }
1299 
1300 
1301 
1302 template <typename number>
1303 inline typename FullMatrix<number>::const_iterator
end(const size_type r)1304 FullMatrix<number>::end(const size_type r) const
1305 {
1306   AssertIndexRange(r, m());
1307   return const_iterator(this, r + 1, 0);
1308 }
1309 
1310 
1311 
1312 template <typename number>
1313 inline void
add(const size_type r,const size_type c,const number v)1314 FullMatrix<number>::add(const size_type r, const size_type c, const number v)
1315 {
1316   AssertIndexRange(r, this->m());
1317   AssertIndexRange(c, this->n());
1318 
1319   this->operator()(r, c) += v;
1320 }
1321 
1322 
1323 
1324 template <typename number>
1325 template <typename number2, typename index_type>
1326 inline void
add(const size_type row,const size_type n_cols,const index_type * col_indices,const number2 * values,const bool,const bool)1327 FullMatrix<number>::add(const size_type   row,
1328                         const size_type   n_cols,
1329                         const index_type *col_indices,
1330                         const number2 *   values,
1331                         const bool,
1332                         const bool)
1333 {
1334   AssertIndexRange(row, this->m());
1335   for (size_type col = 0; col < n_cols; ++col)
1336     {
1337       AssertIndexRange(col_indices[col], this->n());
1338       this->operator()(row, col_indices[col]) += values[col];
1339     }
1340 }
1341 
1342 
1343 template <typename number>
1344 template <class StreamType>
1345 inline void
print(StreamType & s,const unsigned int w,const unsigned int p)1346 FullMatrix<number>::print(StreamType &       s,
1347                           const unsigned int w,
1348                           const unsigned int p) const
1349 {
1350   Assert(!this->empty(), ExcEmptyMatrix());
1351 
1352   // save the state of out stream
1353   const std::streamsize old_precision = s.precision(p);
1354   const std::streamsize old_width     = s.width(w);
1355 
1356   for (size_type i = 0; i < this->m(); ++i)
1357     {
1358       for (size_type j = 0; j < this->n(); ++j)
1359         {
1360           s.width(w);
1361           s.precision(p);
1362           s << this->el(i, j);
1363         }
1364       s << std::endl;
1365     }
1366 
1367   // reset output format
1368   s.precision(old_precision);
1369   s.width(old_width);
1370 }
1371 
1372 
1373 #endif // DOXYGEN
1374 
1375 DEAL_II_NAMESPACE_CLOSE
1376 
1377 #endif
1378