1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2008 - 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_chunk_sparse_matrix_templates_h
17 #define dealii_chunk_sparse_matrix_templates_h
18
19
20 #include <deal.II/base/config.h>
21
22 #include <deal.II/base/parallel.h>
23 #include <deal.II/base/template_constraints.h>
24
25 #include <deal.II/lac/chunk_sparse_matrix.h>
26 #include <deal.II/lac/full_matrix.h>
27 #include <deal.II/lac/vector.h>
28
29 #include <algorithm>
30 #include <cmath>
31 #include <functional>
32 #include <iomanip>
33 #include <numeric>
34 #include <ostream>
35 #include <vector>
36
37 DEAL_II_NAMESPACE_OPEN
38
39
40 namespace internal
41 {
42 // TODO: the goal of the ChunkSparseMatrix class is to stream data and use
43 // the vectorization features of modern processors. to make this happen,
44 // we will have to vectorize the functions in the following namespace, either
45 // by hand or by using, for example, optimized BLAS versions for them.
46 namespace ChunkSparseMatrixImplementation
47 {
48 /**
49 * Declare type for container size.
50 */
51 using size_type = types::global_dof_index;
52
53 /**
54 * Add the result of multiplying a chunk of size chunk_size times
55 * chunk_size by a source vector fragment of size chunk_size to the
56 * destination vector fragment.
57 */
58 template <typename MatrixIterator,
59 typename SrcIterator,
60 typename DstIterator>
61 inline void
chunk_vmult_add(const size_type chunk_size,const MatrixIterator matrix,const SrcIterator src,DstIterator dst)62 chunk_vmult_add(const size_type chunk_size,
63 const MatrixIterator matrix,
64 const SrcIterator src,
65 DstIterator dst)
66 {
67 MatrixIterator matrix_row = matrix;
68
69 for (size_type i = 0; i < chunk_size; ++i, matrix_row += chunk_size)
70 {
71 typename std::iterator_traits<DstIterator>::value_type sum = 0;
72
73 for (size_type j = 0; j < chunk_size; ++j)
74 sum += matrix_row[j] * src[j];
75
76 dst[i] += sum;
77 }
78 }
79
80
81
82 /**
83 * Like the previous function, but subtract. We need this for computing
84 * the residual.
85 */
86 template <typename MatrixIterator,
87 typename SrcIterator,
88 typename DstIterator>
89 inline void
chunk_vmult_subtract(const size_type chunk_size,const MatrixIterator matrix,const SrcIterator src,DstIterator dst)90 chunk_vmult_subtract(const size_type chunk_size,
91 const MatrixIterator matrix,
92 const SrcIterator src,
93 DstIterator dst)
94 {
95 MatrixIterator matrix_row = matrix;
96
97 for (size_type i = 0; i < chunk_size; ++i, matrix_row += chunk_size)
98 {
99 typename std::iterator_traits<DstIterator>::value_type sum = 0;
100
101 for (size_type j = 0; j < chunk_size; ++j)
102 sum += matrix_row[j] * src[j];
103
104 dst[i] -= sum;
105 }
106 }
107
108
109 /**
110 * Add the result of multiplying the transpose of a chunk of size
111 * chunk_size times chunk_size by a source vector fragment of size
112 * chunk_size to the destination vector fragment.
113 */
114 template <typename MatrixIterator,
115 typename SrcIterator,
116 typename DstIterator>
117 inline void
chunk_Tvmult_add(const size_type chunk_size,const MatrixIterator matrix,const SrcIterator src,DstIterator dst)118 chunk_Tvmult_add(const size_type chunk_size,
119 const MatrixIterator matrix,
120 const SrcIterator src,
121 DstIterator dst)
122 {
123 for (size_type i = 0; i < chunk_size; ++i)
124 {
125 typename std::iterator_traits<DstIterator>::value_type sum = 0;
126
127 for (size_type j = 0; j < chunk_size; ++j)
128 sum += matrix[j * chunk_size + i] * src[j];
129
130 dst[i] += sum;
131 }
132 }
133
134
135 /**
136 * Produce the result of the matrix scalar product $u^TMv$ for an
137 * individual chunk.
138 */
139 template <typename result_type,
140 typename MatrixIterator,
141 typename SrcIterator1,
142 typename SrcIterator2>
143 inline result_type
chunk_matrix_scalar_product(const size_type chunk_size,const MatrixIterator matrix,const SrcIterator1 u,const SrcIterator2 v)144 chunk_matrix_scalar_product(const size_type chunk_size,
145 const MatrixIterator matrix,
146 const SrcIterator1 u,
147 const SrcIterator2 v)
148 {
149 result_type result = 0;
150
151 MatrixIterator matrix_row = matrix;
152
153 for (size_type i = 0; i < chunk_size; ++i, matrix_row += chunk_size)
154 {
155 typename std::iterator_traits<SrcIterator2>::value_type sum = 0;
156
157 for (size_type j = 0; j < chunk_size; ++j)
158 sum += matrix_row[j] * v[j];
159
160 result += u[i] * sum;
161 }
162
163 return result;
164 }
165
166
167
168 /**
169 * Perform a vmult_add using the ChunkSparseMatrix data structures, but
170 * only using a subinterval of the matrix rows.
171 *
172 * In the sequential case, this function is called on all rows, in the
173 * parallel case it may be called on a subrange, at the discretion of the
174 * task scheduler.
175 */
176 template <typename number, typename InVector, typename OutVector>
177 void
vmult_add_on_subrange(const ChunkSparsityPattern & cols,const unsigned int begin_row,const unsigned int end_row,const number * values,const std::size_t * rowstart,const size_type * colnums,const InVector & src,OutVector & dst)178 vmult_add_on_subrange(const ChunkSparsityPattern &cols,
179 const unsigned int begin_row,
180 const unsigned int end_row,
181 const number * values,
182 const std::size_t * rowstart,
183 const size_type * colnums,
184 const InVector & src,
185 OutVector & dst)
186 {
187 const size_type m = cols.n_rows();
188 const size_type n = cols.n_cols();
189 const size_type chunk_size = cols.get_chunk_size();
190
191 // loop over all chunks. note that we need to treat the last chunk row
192 // and column differently if they have padding elements
193 const size_type n_filled_last_rows = m % chunk_size;
194 const size_type n_filled_last_cols = n % chunk_size;
195
196 const size_type last_regular_row =
197 n_filled_last_rows > 0 ?
198 std::min(m / chunk_size, static_cast<size_type>(end_row)) :
199 end_row;
200 const size_type irregular_col = n / chunk_size;
201
202 typename OutVector::iterator dst_ptr =
203 dst.begin() + chunk_size * begin_row;
204 const number *val_ptr =
205 &values[rowstart[begin_row] * chunk_size * chunk_size];
206 const size_type *colnum_ptr = &colnums[rowstart[begin_row]];
207 for (unsigned int chunk_row = begin_row; chunk_row < last_regular_row;
208 ++chunk_row)
209 {
210 const number *const val_end_of_row =
211 &values[rowstart[chunk_row + 1] * chunk_size * chunk_size];
212 while (val_ptr != val_end_of_row)
213 {
214 if (*colnum_ptr != irregular_col)
215 chunk_vmult_add(chunk_size,
216 val_ptr,
217 src.begin() + *colnum_ptr * chunk_size,
218 dst_ptr);
219 else
220 // we're at a chunk column that has padding
221 for (size_type r = 0; r < chunk_size; ++r)
222 for (size_type c = 0; c < n_filled_last_cols; ++c)
223 dst_ptr[r] += (val_ptr[r * chunk_size + c] *
224 src(*colnum_ptr * chunk_size + c));
225
226 ++colnum_ptr;
227 val_ptr += chunk_size * chunk_size;
228 }
229
230 dst_ptr += chunk_size;
231 }
232
233 // now deal with last chunk row if necessary
234 if (n_filled_last_rows > 0 && end_row == (m / chunk_size + 1))
235 {
236 const size_type chunk_row = last_regular_row;
237
238 const number *const val_end_of_row =
239 &values[rowstart[chunk_row + 1] * chunk_size * chunk_size];
240 while (val_ptr != val_end_of_row)
241 {
242 if (*colnum_ptr != irregular_col)
243 {
244 // we're at a chunk row but not column that has padding
245 for (size_type r = 0; r < n_filled_last_rows; ++r)
246 for (size_type c = 0; c < chunk_size; ++c)
247 dst_ptr[r] += (val_ptr[r * chunk_size + c] *
248 src(*colnum_ptr * chunk_size + c));
249 }
250 else
251 // we're at a chunk row and column that has padding
252 for (size_type r = 0; r < n_filled_last_rows; ++r)
253 for (size_type c = 0; c < n_filled_last_cols; ++c)
254 dst_ptr[r] += (val_ptr[r * chunk_size + c] *
255 src(*colnum_ptr * chunk_size + c));
256
257 ++colnum_ptr;
258 val_ptr += chunk_size * chunk_size;
259 }
260 }
261 Assert(std::size_t(colnum_ptr - colnums) == rowstart[end_row],
262 ExcInternalError());
263 Assert(std::size_t(val_ptr - values) ==
264 rowstart[end_row] * chunk_size * chunk_size,
265 ExcInternalError());
266 }
267 } // namespace ChunkSparseMatrixImplementation
268 } // namespace internal
269
270
271
272 template <typename number>
ChunkSparseMatrix()273 ChunkSparseMatrix<number>::ChunkSparseMatrix()
274 : cols(nullptr, "ChunkSparseMatrix")
275 , val(nullptr)
276 , max_len(0)
277 {}
278
279
280
281 template <typename number>
ChunkSparseMatrix(const ChunkSparseMatrix & m)282 ChunkSparseMatrix<number>::ChunkSparseMatrix(const ChunkSparseMatrix &m)
283 : Subscriptor(m)
284 , cols(nullptr, "ChunkSparseMatrix")
285 , val(nullptr)
286 , max_len(0)
287 {
288 Assert(m.cols == nullptr && m.val == nullptr && m.max_len == 0,
289 ExcMessage(
290 "This constructor can only be called if the provided argument "
291 "is an empty matrix. This constructor can not be used to "
292 "copy-construct a non-empty matrix. Use the "
293 "ChunkSparseMatrix::copy_from() function for that purpose."));
294 }
295
296
297
298 template <typename number>
299 ChunkSparseMatrix<number> &
300 ChunkSparseMatrix<number>::operator=(const ChunkSparseMatrix<number> &m)
301 {
302 (void)m;
303 Assert(m.cols == nullptr && m.val == nullptr && m.max_len == 0,
304 ExcMessage(
305 "This operator can only be called if the provided right "
306 "hand side is an empty matrix. This operator can not be "
307 "used to copy a non-empty matrix. Use the "
308 "ChunkSparseMatrix::copy_from() function for that purpose."));
309
310 return *this;
311 }
312
313
314
315 template <typename number>
ChunkSparseMatrix(const ChunkSparsityPattern & c)316 ChunkSparseMatrix<number>::ChunkSparseMatrix(const ChunkSparsityPattern &c)
317 : cols(nullptr, "ChunkSparseMatrix")
318 , val(nullptr)
319 , max_len(0)
320 {
321 // virtual functions called in constructors and destructors never use the
322 // override in a derived class
323 // for clarity be explicit on which function is called
324 ChunkSparseMatrix<number>::reinit(c);
325 }
326
327
328
329 template <typename number>
ChunkSparseMatrix(const ChunkSparsityPattern & c,const IdentityMatrix & id)330 ChunkSparseMatrix<number>::ChunkSparseMatrix(const ChunkSparsityPattern &c,
331 const IdentityMatrix & id)
332 : cols(nullptr, "ChunkSparseMatrix")
333 , val(nullptr)
334 , max_len(0)
335 {
336 (void)id;
337 Assert(c.n_rows() == id.m(), ExcDimensionMismatch(c.n_rows(), id.m()));
338 Assert(c.n_cols() == id.n(), ExcDimensionMismatch(c.n_cols(), id.n()));
339
340 // virtual functions called in constructors and destructors never use the
341 // override in a derived class
342 // for clarity be explicit on which function is called
343 ChunkSparseMatrix<number>::reinit(c);
344 for (size_type i = 0; i < n(); ++i)
345 this->set(i, i, 1.);
346 }
347
348
349
350 template <typename number>
~ChunkSparseMatrix()351 ChunkSparseMatrix<number>::~ChunkSparseMatrix()
352 {
353 cols = nullptr;
354 }
355
356
357
358 namespace internal
359 {
360 namespace ChunkSparseMatrixImplementation
361 {
362 template <typename T>
363 void
zero_subrange(const unsigned int begin,const unsigned int end,T * dst)364 zero_subrange(const unsigned int begin, const unsigned int end, T *dst)
365 {
366 std::memset(dst + begin, 0, (end - begin) * sizeof(T));
367 }
368 } // namespace ChunkSparseMatrixImplementation
369 } // namespace internal
370
371
372
373 template <typename number>
374 ChunkSparseMatrix<number> &
375 ChunkSparseMatrix<number>::operator=(const double d)
376 {
377 (void)d;
378 Assert(d == 0, ExcScalarAssignmentOnlyForZeroValue());
379
380 Assert(cols != nullptr, ExcNotInitialized());
381 Assert(cols->sparsity_pattern.compressed || cols->empty(),
382 ChunkSparsityPattern::ExcNotCompressed());
383
384 // do initial zeroing of elements in parallel. Try to achieve a similar
385 // layout as when doing matrix-vector products, as on some NUMA systems, a
386 // memory block is assigned to memory banks where the first access is
387 // generated. For sparse matrices, the first operations is usually the
388 // operator=. The grain size is chosen to reflect the number of rows in
389 // minimum_parallel_grain_size, weighted by the number of nonzero entries
390 // per row on average.
391 const unsigned int matrix_size = cols->sparsity_pattern.n_nonzero_elements() *
392 cols->chunk_size * cols->chunk_size;
393 const unsigned int grain_size =
394 internal::SparseMatrixImplementation::minimum_parallel_grain_size *
395 (matrix_size + m()) / m();
396 if (matrix_size > grain_size)
397 parallel::apply_to_subranges(
398 0U,
399 matrix_size,
400 [this](const unsigned int begin, const unsigned int end) {
401 internal::ChunkSparseMatrixImplementation::zero_subrange(begin,
402 end,
403 val.get());
404 },
405 grain_size);
406 else if (matrix_size > 0)
407 std::memset(val.get(), 0, matrix_size * sizeof(number));
408
409 return *this;
410 }
411
412
413
414 template <typename number>
415 ChunkSparseMatrix<number> &
416 ChunkSparseMatrix<number>::operator=(const IdentityMatrix &id)
417 {
418 (void)id;
419 Assert(cols->n_rows() == id.m(),
420 ExcDimensionMismatch(cols->n_rows(), id.m()));
421 Assert(cols->n_cols() == id.n(),
422 ExcDimensionMismatch(cols->n_cols(), id.n()));
423
424 *this = 0;
425 for (size_type i = 0; i < n(); ++i)
426 this->set(i, i, 1.);
427
428 return *this;
429 }
430
431
432
433 template <typename number>
434 void
reinit(const ChunkSparsityPattern & sparsity)435 ChunkSparseMatrix<number>::reinit(const ChunkSparsityPattern &sparsity)
436 {
437 cols = &sparsity;
438
439 if (cols->empty())
440 {
441 val.reset();
442 max_len = 0;
443 return;
444 }
445
446 // allocate not just m() * n() elements but enough so that we can store full
447 // chunks. this entails some padding elements
448 const size_type chunk_size = cols->get_chunk_size();
449 const size_type N =
450 cols->sparsity_pattern.n_nonzero_elements() * chunk_size * chunk_size;
451 if (N > max_len || max_len == 0)
452 {
453 val = std::make_unique<number[]>(N);
454 max_len = N;
455 }
456
457 // fill with zeros. do not just fill N elements but all that we allocated to
458 // ensure that also the padding elements are zero and not left at previous
459 // values
460 this->operator=(0.);
461 }
462
463
464
465 template <typename number>
466 void
clear()467 ChunkSparseMatrix<number>::clear()
468 {
469 cols = nullptr;
470 val.reset();
471 max_len = 0;
472 }
473
474
475
476 template <typename number>
477 bool
empty()478 ChunkSparseMatrix<number>::empty() const
479 {
480 if (cols == nullptr)
481 return true;
482 else
483 return cols->empty();
484 }
485
486
487
488 template <typename number>
489 typename ChunkSparseMatrix<number>::size_type
n_nonzero_elements()490 ChunkSparseMatrix<number>::n_nonzero_elements() const
491 {
492 Assert(cols != nullptr, ExcNotInitialized());
493 return cols->n_nonzero_elements();
494 }
495
496
497
498 template <typename number>
499 typename ChunkSparseMatrix<number>::size_type
n_actually_nonzero_elements()500 ChunkSparseMatrix<number>::n_actually_nonzero_elements() const
501 {
502 Assert(cols != nullptr, ExcNotInitialized());
503
504 // count those elements that are nonzero, even if they lie in the padding
505 // around the matrix. since we have the invariant that padding elements are
506 // zero, nothing bad can happen here
507 const size_type chunk_size = cols->get_chunk_size();
508 return std::count_if(val.get(),
509 val.get() + cols->sparsity_pattern.n_nonzero_elements() *
510 chunk_size * chunk_size,
511 [](const double element) { return element != 0.; });
512 }
513
514
515
516 template <typename number>
517 void
symmetrize()518 ChunkSparseMatrix<number>::symmetrize()
519 {
520 Assert(cols != nullptr, ExcNotInitialized());
521 Assert(cols->rows == cols->cols, ExcNotQuadratic());
522
523 Assert(false, ExcNotImplemented());
524 }
525
526
527
528 template <typename number>
529 template <typename somenumber>
530 ChunkSparseMatrix<number> &
copy_from(const ChunkSparseMatrix<somenumber> & matrix)531 ChunkSparseMatrix<number>::copy_from(
532 const ChunkSparseMatrix<somenumber> &matrix)
533 {
534 Assert(cols != nullptr, ExcNotInitialized());
535 Assert(val != nullptr, ExcNotInitialized());
536 Assert(cols == matrix.cols, ExcDifferentChunkSparsityPatterns());
537
538 // copy everything, including padding elements
539 const size_type chunk_size = cols->get_chunk_size();
540 std::copy(matrix.val.get(),
541 matrix.val.get() + cols->sparsity_pattern.n_nonzero_elements() *
542 chunk_size * chunk_size,
543 val.get());
544
545 return *this;
546 }
547
548
549
550 template <typename number>
551 template <typename somenumber>
552 void
copy_from(const FullMatrix<somenumber> & matrix)553 ChunkSparseMatrix<number>::copy_from(const FullMatrix<somenumber> &matrix)
554 {
555 // first delete previous content
556 *this = 0;
557
558 // then copy old matrix
559 for (size_type row = 0; row < matrix.m(); ++row)
560 for (size_type col = 0; col < matrix.n(); ++col)
561 if (matrix(row, col) != 0)
562 set(row, col, matrix(row, col));
563 }
564
565
566
567 template <typename number>
568 template <typename somenumber>
569 void
add(const number factor,const ChunkSparseMatrix<somenumber> & matrix)570 ChunkSparseMatrix<number>::add(const number factor,
571 const ChunkSparseMatrix<somenumber> &matrix)
572 {
573 Assert(cols != nullptr, ExcNotInitialized());
574 Assert(val != nullptr, ExcNotInitialized());
575 Assert(cols == matrix.cols, ExcDifferentChunkSparsityPatterns());
576
577 // add everything, including padding elements
578 const size_type chunk_size = cols->get_chunk_size();
579 number * val_ptr = val.get();
580 const somenumber * matrix_ptr = matrix.val.get();
581 const number *const end_ptr =
582 val.get() +
583 cols->sparsity_pattern.n_nonzero_elements() * chunk_size * chunk_size;
584
585 while (val_ptr != end_ptr)
586 *val_ptr++ += factor * *matrix_ptr++;
587 }
588
589
590
591 template <typename number>
592 void
extract_row_copy(const size_type row,const size_type array_length,size_type & row_length,size_type * column_indices,number * values)593 ChunkSparseMatrix<number>::extract_row_copy(const size_type row,
594 const size_type array_length,
595 size_type & row_length,
596 size_type * column_indices,
597 number * values) const
598 {
599 (void)array_length;
600 AssertIndexRange(cols->row_length(row), array_length + 1);
601 AssertIndexRange(row, m());
602 const unsigned int chunk_size = cols->get_chunk_size();
603 const size_type reduced_row = row / chunk_size;
604
605 SparsityPattern::iterator it = cols->sparsity_pattern.begin(reduced_row),
606 itend = cols->sparsity_pattern.end(reduced_row);
607 const number *val_ptr =
608 &val[(it - cols->sparsity_pattern.begin(0)) * chunk_size * chunk_size +
609 (row % chunk_size) * chunk_size];
610
611 // find out if we did padding and if this row is affected by it
612 if (cols->n_cols() % chunk_size == 0)
613 {
614 for (; it < itend; ++it)
615 {
616 for (unsigned int c = 0; c < chunk_size; ++c)
617 {
618 *values++ = val_ptr[c];
619 *column_indices++ = it->column() * chunk_size + c;
620 }
621 val_ptr += chunk_size * chunk_size;
622 }
623 row_length =
624 chunk_size * (cols->sparsity_pattern.row_length(reduced_row));
625 }
626 else
627 {
628 const unsigned int last_chunk_size = cols->n_cols() % chunk_size;
629 row_length = 0;
630 for (; it < itend; ++it)
631 {
632 const unsigned int next_chunk_size =
633 (it->column() == cols->sparsity_pattern.n_cols() - 1) ?
634 last_chunk_size :
635 chunk_size;
636 for (unsigned int c = 0; c < next_chunk_size; ++c, ++row_length)
637 {
638 *values++ = val_ptr[c];
639 *column_indices++ = it->column() * chunk_size + c;
640 }
641 val_ptr += chunk_size * chunk_size;
642 }
643 }
644 }
645
646
647
648 template <typename number>
649 template <class OutVector, class InVector>
650 void
vmult(OutVector & dst,const InVector & src)651 ChunkSparseMatrix<number>::vmult(OutVector &dst, const InVector &src) const
652 {
653 Assert(cols != nullptr, ExcNotInitialized());
654 Assert(val != nullptr, ExcNotInitialized());
655 Assert(m() == dst.size(), ExcDimensionMismatch(m(), dst.size()));
656 Assert(n() == src.size(), ExcDimensionMismatch(n(), src.size()));
657
658 Assert(!PointerComparison::equal(&src, &dst), ExcSourceEqualsDestination());
659
660 // set the output vector to zero and then add to it the contributions of
661 // vmults from individual chunks. this is what vmult_add does
662 dst = 0;
663 vmult_add(dst, src);
664 }
665
666
667
668 template <typename number>
669 template <class OutVector, class InVector>
670 void
Tvmult(OutVector & dst,const InVector & src)671 ChunkSparseMatrix<number>::Tvmult(OutVector &dst, const InVector &src) const
672 {
673 Assert(val != nullptr, ExcNotInitialized());
674 Assert(cols != nullptr, ExcNotInitialized());
675 Assert(n() == dst.size(), ExcDimensionMismatch(n(), dst.size()));
676 Assert(m() == src.size(), ExcDimensionMismatch(m(), src.size()));
677
678 Assert(!PointerComparison::equal(&src, &dst), ExcSourceEqualsDestination());
679
680 Assert(cols != nullptr, ExcNotInitialized());
681 Assert(val != nullptr, ExcNotInitialized());
682 Assert(m() == dst.size(), ExcDimensionMismatch(m(), dst.size()));
683 Assert(n() == src.size(), ExcDimensionMismatch(n(), src.size()));
684
685 Assert(!PointerComparison::equal(&src, &dst), ExcSourceEqualsDestination());
686
687 // set the output vector to zero and then add to it the contributions of
688 // vmults from individual chunks. this is what vmult_add does
689 dst = 0;
690 Tvmult_add(dst, src);
691 }
692
693
694
695 template <typename number>
696 template <class OutVector, class InVector>
697 void
vmult_add(OutVector & dst,const InVector & src)698 ChunkSparseMatrix<number>::vmult_add(OutVector &dst, const InVector &src) const
699 {
700 Assert(cols != nullptr, ExcNotInitialized());
701 Assert(val != nullptr, ExcNotInitialized());
702 Assert(m() == dst.size(), ExcDimensionMismatch(m(), dst.size()));
703 Assert(n() == src.size(), ExcDimensionMismatch(n(), src.size()));
704
705 Assert(!PointerComparison::equal(&src, &dst), ExcSourceEqualsDestination());
706 parallel::apply_to_subranges(
707 0U,
708 cols->sparsity_pattern.n_rows(),
709 [this, &src, &dst](const unsigned int begin_row,
710 const unsigned int end_row) {
711 internal::ChunkSparseMatrixImplementation::vmult_add_on_subrange(
712 *cols,
713 begin_row,
714 end_row,
715 val.get(),
716 cols->sparsity_pattern.rowstart.get(),
717 cols->sparsity_pattern.colnums.get(),
718 src,
719 dst);
720 },
721 internal::SparseMatrixImplementation::minimum_parallel_grain_size /
722 cols->chunk_size +
723 1);
724 }
725
726
727 template <typename number>
728 template <class OutVector, class InVector>
729 void
Tvmult_add(OutVector & dst,const InVector & src)730 ChunkSparseMatrix<number>::Tvmult_add(OutVector &dst, const InVector &src) const
731 {
732 Assert(cols != nullptr, ExcNotInitialized());
733 Assert(val != nullptr, ExcNotInitialized());
734 Assert(m() == dst.size(), ExcDimensionMismatch(m(), dst.size()));
735 Assert(n() == src.size(), ExcDimensionMismatch(n(), src.size()));
736
737 Assert(!PointerComparison::equal(&src, &dst), ExcSourceEqualsDestination());
738
739 const size_type n_chunk_rows = cols->sparsity_pattern.n_rows();
740
741 // loop over all chunks. note that we need to treat the last chunk row and
742 // column differently if they have padding elements
743 const bool rows_have_padding = (m() % cols->chunk_size != 0),
744 cols_have_padding = (n() % cols->chunk_size != 0);
745
746 const size_type n_regular_chunk_rows =
747 (rows_have_padding ? n_chunk_rows - 1 : n_chunk_rows);
748
749 // like in vmult_add, but don't keep an iterator into dst around since we're
750 // not traversing it sequentially this time
751 const number * val_ptr = val.get();
752 const size_type *colnum_ptr = cols->sparsity_pattern.colnums.get();
753
754 for (size_type chunk_row = 0; chunk_row < n_regular_chunk_rows; ++chunk_row)
755 {
756 const number *const val_end_of_row =
757 &val[cols->sparsity_pattern.rowstart[chunk_row + 1] * cols->chunk_size *
758 cols->chunk_size];
759 while (val_ptr != val_end_of_row)
760 {
761 if ((cols_have_padding == false) ||
762 (*colnum_ptr != cols->sparsity_pattern.n_cols() - 1))
763 internal::ChunkSparseMatrixImplementation::chunk_Tvmult_add(
764 cols->chunk_size,
765 val_ptr,
766 src.begin() + chunk_row * cols->chunk_size,
767 dst.begin() + *colnum_ptr * cols->chunk_size);
768 else
769 // we're at a chunk column that has padding
770 for (size_type r = 0; r < cols->chunk_size; ++r)
771 for (size_type c = 0; c < n() % cols->chunk_size; ++c)
772 dst(*colnum_ptr * cols->chunk_size + c) +=
773 (val_ptr[r * cols->chunk_size + c] *
774 src(chunk_row * cols->chunk_size + r));
775
776 ++colnum_ptr;
777 val_ptr += cols->chunk_size * cols->chunk_size;
778 }
779 }
780
781 // now deal with last chunk row if necessary
782 if (rows_have_padding)
783 {
784 const size_type chunk_row = n_chunk_rows - 1;
785
786 const number *const val_end_of_row =
787 &val[cols->sparsity_pattern.rowstart[chunk_row + 1] * cols->chunk_size *
788 cols->chunk_size];
789 while (val_ptr != val_end_of_row)
790 {
791 if ((cols_have_padding == false) ||
792 (*colnum_ptr != cols->sparsity_pattern.n_cols() - 1))
793 {
794 // we're at a chunk row but not column that has padding
795 for (size_type r = 0; r < m() % cols->chunk_size; ++r)
796 for (size_type c = 0; c < cols->chunk_size; ++c)
797 dst(*colnum_ptr * cols->chunk_size + c) +=
798 (val_ptr[r * cols->chunk_size + c] *
799 src(chunk_row * cols->chunk_size + r));
800 }
801 else
802 // we're at a chunk row and column that has padding
803 for (size_type r = 0; r < m() % cols->chunk_size; ++r)
804 for (size_type c = 0; c < n() % cols->chunk_size; ++c)
805 dst(*colnum_ptr * cols->chunk_size + c) +=
806 (val_ptr[r * cols->chunk_size + c] *
807 src(chunk_row * cols->chunk_size + r));
808
809 ++colnum_ptr;
810 val_ptr += cols->chunk_size * cols->chunk_size;
811 }
812 }
813 }
814
815
816 template <typename number>
817 template <typename somenumber>
818 somenumber
matrix_norm_square(const Vector<somenumber> & v)819 ChunkSparseMatrix<number>::matrix_norm_square(const Vector<somenumber> &v) const
820 {
821 Assert(cols != nullptr, ExcNotInitialized());
822 Assert(val != nullptr, ExcNotInitialized());
823 Assert(m() == v.size(), ExcDimensionMismatch(m(), v.size()));
824 Assert(n() == v.size(), ExcDimensionMismatch(n(), v.size()));
825
826 somenumber result = 0;
827
828 ////////////////
829 // like matrix_scalar_product, except that the two vectors are now the same
830
831 const size_type n_chunk_rows = cols->sparsity_pattern.n_rows();
832
833 // loop over all chunks. note that we need to treat the last chunk row and
834 // column differently if they have padding elements
835 const bool rows_have_padding = (m() % cols->chunk_size != 0),
836 cols_have_padding = (n() % cols->chunk_size != 0);
837
838 const size_type n_regular_chunk_rows =
839 (rows_have_padding ? n_chunk_rows - 1 : n_chunk_rows);
840
841 const number * val_ptr = val.get();
842 const size_type *colnum_ptr = cols->sparsity_pattern.colnums.get();
843 typename Vector<somenumber>::const_iterator v_ptr = v.begin();
844
845 for (size_type chunk_row = 0; chunk_row < n_regular_chunk_rows; ++chunk_row)
846 {
847 const number *const val_end_of_row =
848 &val[cols->sparsity_pattern.rowstart[chunk_row + 1] * cols->chunk_size *
849 cols->chunk_size];
850 while (val_ptr != val_end_of_row)
851 {
852 if ((cols_have_padding == false) ||
853 (*colnum_ptr != cols->sparsity_pattern.n_cols() - 1))
854 result += internal::ChunkSparseMatrixImplementation::
855 chunk_matrix_scalar_product<somenumber>(cols->chunk_size,
856 val_ptr,
857 v_ptr,
858 v.begin() +
859 *colnum_ptr *
860 cols->chunk_size);
861 else
862 // we're at a chunk column that has padding
863 for (size_type r = 0; r < cols->chunk_size; ++r)
864 for (size_type c = 0; c < n() % cols->chunk_size; ++c)
865 result += v(chunk_row * cols->chunk_size + r) *
866 (val_ptr[r * cols->chunk_size + c] *
867 v(*colnum_ptr * cols->chunk_size + c));
868
869 ++colnum_ptr;
870 val_ptr += cols->chunk_size * cols->chunk_size;
871 }
872
873
874 v_ptr += cols->chunk_size;
875 }
876
877 // now deal with last chunk row if necessary
878 if (rows_have_padding)
879 {
880 const size_type chunk_row = n_chunk_rows - 1;
881
882 const number *const val_end_of_row =
883 &val[cols->sparsity_pattern.rowstart[chunk_row + 1] * cols->chunk_size *
884 cols->chunk_size];
885 while (val_ptr != val_end_of_row)
886 {
887 if ((cols_have_padding == false) ||
888 (*colnum_ptr != cols->sparsity_pattern.n_cols() - 1))
889 {
890 // we're at a chunk row but not column that has padding
891 for (size_type r = 0; r < m() % cols->chunk_size; ++r)
892 for (size_type c = 0; c < cols->chunk_size; ++c)
893 result += v(chunk_row * cols->chunk_size + r) *
894 (val_ptr[r * cols->chunk_size + c] *
895 v(*colnum_ptr * cols->chunk_size + c));
896 }
897 else
898 // we're at a chunk row and column that has padding
899 for (size_type r = 0; r < m() % cols->chunk_size; ++r)
900 for (size_type c = 0; c < n() % cols->chunk_size; ++c)
901 result += v(chunk_row * cols->chunk_size + r) *
902 (val_ptr[r * cols->chunk_size + c] *
903 v(*colnum_ptr * cols->chunk_size + c));
904
905 ++colnum_ptr;
906 val_ptr += cols->chunk_size * cols->chunk_size;
907 }
908 }
909
910 return result;
911 }
912
913
914
915 template <typename number>
916 template <typename somenumber>
917 somenumber
matrix_scalar_product(const Vector<somenumber> & u,const Vector<somenumber> & v)918 ChunkSparseMatrix<number>::matrix_scalar_product(
919 const Vector<somenumber> &u,
920 const Vector<somenumber> &v) const
921 {
922 Assert(cols != nullptr, ExcNotInitialized());
923 Assert(val != nullptr, ExcNotInitialized());
924 Assert(m() == u.size(), ExcDimensionMismatch(m(), u.size()));
925 Assert(n() == v.size(), ExcDimensionMismatch(n(), v.size()));
926
927 // the following works like the vmult_add function
928 somenumber result = 0;
929
930 const size_type n_chunk_rows = cols->sparsity_pattern.n_rows();
931
932 // loop over all chunks. note that we need to treat the last chunk row and
933 // column differently if they have padding elements
934 const bool rows_have_padding = (m() % cols->chunk_size != 0),
935 cols_have_padding = (n() % cols->chunk_size != 0);
936
937 const size_type n_regular_chunk_rows =
938 (rows_have_padding ? n_chunk_rows - 1 : n_chunk_rows);
939
940 const number * val_ptr = val.get();
941 const size_type *colnum_ptr = cols->sparsity_pattern.colnums.get();
942 typename Vector<somenumber>::const_iterator u_ptr = u.begin();
943
944 for (size_type chunk_row = 0; chunk_row < n_regular_chunk_rows; ++chunk_row)
945 {
946 const number *const val_end_of_row =
947 &val[cols->sparsity_pattern.rowstart[chunk_row + 1] * cols->chunk_size *
948 cols->chunk_size];
949 while (val_ptr != val_end_of_row)
950 {
951 if ((cols_have_padding == false) ||
952 (*colnum_ptr != cols->sparsity_pattern.n_cols() - 1))
953 result += internal::ChunkSparseMatrixImplementation::
954 chunk_matrix_scalar_product<somenumber>(cols->chunk_size,
955 val_ptr,
956 u_ptr,
957 v.begin() +
958 *colnum_ptr *
959 cols->chunk_size);
960 else
961 // we're at a chunk column that has padding
962 for (size_type r = 0; r < cols->chunk_size; ++r)
963 for (size_type c = 0; c < n() % cols->chunk_size; ++c)
964 result += u(chunk_row * cols->chunk_size + r) *
965 (val_ptr[r * cols->chunk_size + c] *
966 v(*colnum_ptr * cols->chunk_size + c));
967
968 ++colnum_ptr;
969 val_ptr += cols->chunk_size * cols->chunk_size;
970 }
971
972
973 u_ptr += cols->chunk_size;
974 }
975
976 // now deal with last chunk row if necessary
977 if (rows_have_padding)
978 {
979 const size_type chunk_row = n_chunk_rows - 1;
980
981 const number *const val_end_of_row =
982 &val[cols->sparsity_pattern.rowstart[chunk_row + 1] * cols->chunk_size *
983 cols->chunk_size];
984 while (val_ptr != val_end_of_row)
985 {
986 if ((cols_have_padding == false) ||
987 (*colnum_ptr != cols->sparsity_pattern.n_cols() - 1))
988 {
989 // we're at a chunk row but not column that has padding
990 for (size_type r = 0; r < m() % cols->chunk_size; ++r)
991 for (size_type c = 0; c < cols->chunk_size; ++c)
992 result += u(chunk_row * cols->chunk_size + r) *
993 (val_ptr[r * cols->chunk_size + c] *
994 v(*colnum_ptr * cols->chunk_size + c));
995 }
996 else
997 // we're at a chunk row and column that has padding
998 for (size_type r = 0; r < m() % cols->chunk_size; ++r)
999 for (size_type c = 0; c < n() % cols->chunk_size; ++c)
1000 result += u(chunk_row * cols->chunk_size + r) *
1001 (val_ptr[r * cols->chunk_size + c] *
1002 v(*colnum_ptr * cols->chunk_size + c));
1003
1004 ++colnum_ptr;
1005 val_ptr += cols->chunk_size * cols->chunk_size;
1006 }
1007 }
1008
1009 return result;
1010 }
1011
1012
1013
1014 template <typename number>
1015 typename ChunkSparseMatrix<number>::real_type
l1_norm()1016 ChunkSparseMatrix<number>::l1_norm() const
1017 {
1018 Assert(cols != nullptr, ExcNotInitialized());
1019 Assert(val != nullptr, ExcNotInitialized());
1020
1021 const size_type n_chunk_rows = cols->sparsity_pattern.n_rows();
1022
1023 // loop over all rows and columns; it is safe to also loop over the padding
1024 // elements (they are zero) if we make sure that the vector into which we
1025 // sum column sums is large enough
1026 Vector<real_type> column_sums(cols->sparsity_pattern.n_cols() *
1027 cols->chunk_size);
1028
1029 for (size_type chunk_row = 0; chunk_row < n_chunk_rows; ++chunk_row)
1030 for (size_type j = cols->sparsity_pattern.rowstart[chunk_row];
1031 j < cols->sparsity_pattern.rowstart[chunk_row + 1];
1032 ++j)
1033 for (size_type r = 0; r < cols->chunk_size; ++r)
1034 for (size_type s = 0; s < cols->chunk_size; ++s)
1035 column_sums(cols->sparsity_pattern.colnums[j] * cols->chunk_size +
1036 s) +=
1037 numbers::NumberTraits<number>::abs(
1038 val[j * cols->chunk_size * cols->chunk_size +
1039 r * cols->chunk_size + s]);
1040
1041 return column_sums.linfty_norm();
1042 }
1043
1044
1045
1046 template <typename number>
1047 typename ChunkSparseMatrix<number>::real_type
linfty_norm()1048 ChunkSparseMatrix<number>::linfty_norm() const
1049 {
1050 Assert(cols != nullptr, ExcNotInitialized());
1051 Assert(val != nullptr, ExcNotInitialized());
1052
1053 // this function works like l1_norm(). it can be made more efficient
1054 // (without allocating a temporary vector) as is done in the SparseMatrix
1055 // class but since it is rarely called in time critical places it is
1056 // probably not worth it
1057 const size_type n_chunk_rows = cols->sparsity_pattern.n_rows();
1058
1059 // loop over all rows and columns; it is safe to also loop over the padding
1060 // elements (they are zero) if we make sure that the vector into which we
1061 // sum column sums is large enough
1062 Vector<real_type> row_sums(cols->sparsity_pattern.n_rows() *
1063 cols->chunk_size);
1064
1065 for (size_type chunk_row = 0; chunk_row < n_chunk_rows; ++chunk_row)
1066 for (size_type j = cols->sparsity_pattern.rowstart[chunk_row];
1067 j < cols->sparsity_pattern.rowstart[chunk_row + 1];
1068 ++j)
1069 for (size_type r = 0; r < cols->chunk_size; ++r)
1070 for (size_type s = 0; s < cols->chunk_size; ++s)
1071 row_sums(chunk_row * cols->chunk_size + r) +=
1072 numbers::NumberTraits<number>::abs(
1073 val[j * cols->chunk_size * cols->chunk_size +
1074 r * cols->chunk_size + s]);
1075
1076 return row_sums.linfty_norm();
1077 }
1078
1079
1080
1081 template <typename number>
1082 typename ChunkSparseMatrix<number>::real_type
frobenius_norm()1083 ChunkSparseMatrix<number>::frobenius_norm() const
1084 {
1085 // simply add up all entries in the sparsity pattern, without taking any
1086 // reference to rows or columns
1087 //
1088 // padding elements are zero, so we can add them up as well
1089 real_type norm_sqr = 0;
1090 for (const number *ptr = val.get(); ptr != val.get() + max_len; ++ptr)
1091 norm_sqr += numbers::NumberTraits<number>::abs_square(*ptr);
1092
1093 return std::sqrt(norm_sqr);
1094 }
1095
1096
1097
1098 template <typename number>
1099 template <typename somenumber>
1100 somenumber
residual(Vector<somenumber> & dst,const Vector<somenumber> & u,const Vector<somenumber> & b)1101 ChunkSparseMatrix<number>::residual(Vector<somenumber> & dst,
1102 const Vector<somenumber> &u,
1103 const Vector<somenumber> &b) const
1104 {
1105 Assert(cols != nullptr, ExcNotInitialized());
1106 Assert(val != nullptr, ExcNotInitialized());
1107 Assert(m() == dst.size(), ExcDimensionMismatch(m(), dst.size()));
1108 Assert(m() == b.size(), ExcDimensionMismatch(m(), b.size()));
1109 Assert(n() == u.size(), ExcDimensionMismatch(n(), u.size()));
1110
1111 Assert(&u != &dst, ExcSourceEqualsDestination());
1112
1113 // set dst=b, then subtract the result of A*u from it. since the purpose of
1114 // the current class is to promote streaming of data rather than more random
1115 // access patterns, breaking things up into two loops may be reasonable
1116 dst = b;
1117
1118 /////////
1119 // the rest of this function is like vmult_add, except that we subtract
1120 // rather than add A*u
1121 /////////
1122 const size_type n_chunk_rows = cols->sparsity_pattern.n_rows();
1123
1124 // loop over all chunks. note that we need to treat the last chunk row and
1125 // column differently if they have padding elements
1126 const bool rows_have_padding = (m() % cols->chunk_size != 0),
1127 cols_have_padding = (n() % cols->chunk_size != 0);
1128
1129 const size_type n_regular_chunk_rows =
1130 (rows_have_padding ? n_chunk_rows - 1 : n_chunk_rows);
1131
1132 const number * val_ptr = val.get();
1133 const size_type *colnum_ptr = cols->sparsity_pattern.colnums.get();
1134 typename Vector<somenumber>::iterator dst_ptr = dst.begin();
1135
1136 for (size_type chunk_row = 0; chunk_row < n_regular_chunk_rows; ++chunk_row)
1137 {
1138 const number *const val_end_of_row =
1139 &val[cols->sparsity_pattern.rowstart[chunk_row + 1] * cols->chunk_size *
1140 cols->chunk_size];
1141 while (val_ptr != val_end_of_row)
1142 {
1143 if ((cols_have_padding == false) ||
1144 (*colnum_ptr != cols->sparsity_pattern.n_cols() - 1))
1145 internal::ChunkSparseMatrixImplementation::chunk_vmult_subtract(
1146 cols->chunk_size,
1147 val_ptr,
1148 u.begin() + *colnum_ptr * cols->chunk_size,
1149 dst_ptr);
1150 else
1151 // we're at a chunk column that has padding
1152 for (size_type r = 0; r < cols->chunk_size; ++r)
1153 for (size_type c = 0; c < n() % cols->chunk_size; ++c)
1154 dst(chunk_row * cols->chunk_size + r) -=
1155 (val_ptr[r * cols->chunk_size + c] *
1156 u(*colnum_ptr * cols->chunk_size + c));
1157
1158 ++colnum_ptr;
1159 val_ptr += cols->chunk_size * cols->chunk_size;
1160 }
1161
1162
1163 dst_ptr += cols->chunk_size;
1164 }
1165
1166 // now deal with last chunk row if necessary
1167 if (rows_have_padding)
1168 {
1169 const size_type chunk_row = n_chunk_rows - 1;
1170
1171 const number *const val_end_of_row =
1172 &val[cols->sparsity_pattern.rowstart[chunk_row + 1] * cols->chunk_size *
1173 cols->chunk_size];
1174 while (val_ptr != val_end_of_row)
1175 {
1176 if ((cols_have_padding == false) ||
1177 (*colnum_ptr != cols->sparsity_pattern.n_cols() - 1))
1178 {
1179 // we're at a chunk row but not column that has padding
1180 for (size_type r = 0; r < m() % cols->chunk_size; ++r)
1181 for (size_type c = 0; c < cols->chunk_size; ++c)
1182 dst(chunk_row * cols->chunk_size + r) -=
1183 (val_ptr[r * cols->chunk_size + c] *
1184 u(*colnum_ptr * cols->chunk_size + c));
1185 }
1186 else
1187 // we're at a chunk row and column that has padding
1188 for (size_type r = 0; r < m() % cols->chunk_size; ++r)
1189 for (size_type c = 0; c < n() % cols->chunk_size; ++c)
1190 dst(chunk_row * cols->chunk_size + r) -=
1191 (val_ptr[r * cols->chunk_size + c] *
1192 u(*colnum_ptr * cols->chunk_size + c));
1193
1194 ++colnum_ptr;
1195 val_ptr += cols->chunk_size * cols->chunk_size;
1196 }
1197
1198
1199 dst_ptr += cols->chunk_size;
1200 }
1201
1202 // finally compute the norm
1203 return dst.l2_norm();
1204 }
1205
1206
1207
1208 template <typename number>
1209 template <typename somenumber>
1210 void
precondition_Jacobi(Vector<somenumber> & dst,const Vector<somenumber> & src,const number)1211 ChunkSparseMatrix<number>::precondition_Jacobi(Vector<somenumber> & dst,
1212 const Vector<somenumber> &src,
1213 const number /*om*/) const
1214 {
1215 (void)dst;
1216 (void)src;
1217 Assert(cols != nullptr, ExcNotInitialized());
1218 Assert(val != nullptr, ExcNotInitialized());
1219 Assert(m() == n(),
1220 ExcMessage("This operation is only valid on square matrices."));
1221
1222 Assert(dst.size() == n(), ExcDimensionMismatch(dst.size(), n()));
1223 Assert(src.size() == n(), ExcDimensionMismatch(src.size(), n()));
1224
1225 Assert(false, ExcNotImplemented());
1226 }
1227
1228
1229
1230 template <typename number>
1231 template <typename somenumber>
1232 void
precondition_SSOR(Vector<somenumber> & dst,const Vector<somenumber> & src,const number)1233 ChunkSparseMatrix<number>::precondition_SSOR(Vector<somenumber> & dst,
1234 const Vector<somenumber> &src,
1235 const number /*om*/) const
1236 {
1237 // to understand how this function works you may want to take a look at the
1238 // CVS archives to see the original version which is much clearer...
1239 (void)dst;
1240 (void)src;
1241 Assert(cols != nullptr, ExcNotInitialized());
1242 Assert(val != nullptr, ExcNotInitialized());
1243 Assert(m() == n(),
1244 ExcMessage("This operation is only valid on square matrices."));
1245
1246 Assert(dst.size() == n(), ExcDimensionMismatch(dst.size(), n()));
1247 Assert(src.size() == n(), ExcDimensionMismatch(src.size(), n()));
1248
1249 Assert(false, ExcNotImplemented());
1250 }
1251
1252
1253 template <typename number>
1254 template <typename somenumber>
1255 void
precondition_SOR(Vector<somenumber> & dst,const Vector<somenumber> & src,const number om)1256 ChunkSparseMatrix<number>::precondition_SOR(Vector<somenumber> & dst,
1257 const Vector<somenumber> &src,
1258 const number om) const
1259 {
1260 Assert(cols != nullptr, ExcNotInitialized());
1261 Assert(val != nullptr, ExcNotInitialized());
1262 Assert(m() == n(),
1263 ExcMessage("This operation is only valid on square matrices."));
1264
1265
1266 dst = src;
1267 SOR(dst, om);
1268 }
1269
1270
1271 template <typename number>
1272 template <typename somenumber>
1273 void
precondition_TSOR(Vector<somenumber> & dst,const Vector<somenumber> & src,const number om)1274 ChunkSparseMatrix<number>::precondition_TSOR(Vector<somenumber> & dst,
1275 const Vector<somenumber> &src,
1276 const number om) const
1277 {
1278 Assert(cols != nullptr, ExcNotInitialized());
1279 Assert(val != nullptr, ExcNotInitialized());
1280 Assert(m() == n(),
1281 ExcMessage("This operation is only valid on square matrices."));
1282
1283
1284 dst = src;
1285 TSOR(dst, om);
1286 }
1287
1288
1289 template <typename number>
1290 template <typename somenumber>
1291 void
SOR(Vector<somenumber> & dst,const number)1292 ChunkSparseMatrix<number>::SOR(Vector<somenumber> &dst,
1293 const number /*om*/) const
1294 {
1295 (void)dst;
1296 Assert(cols != nullptr, ExcNotInitialized());
1297 Assert(val != nullptr, ExcNotInitialized());
1298 Assert(m() == n(),
1299 ExcMessage("This operation is only valid on square matrices."));
1300 Assert(m() == dst.size(), ExcDimensionMismatch(m(), dst.size()));
1301
1302 Assert(false, ExcNotImplemented());
1303 }
1304
1305
1306 template <typename number>
1307 template <typename somenumber>
1308 void
TSOR(Vector<somenumber> & dst,const number)1309 ChunkSparseMatrix<number>::TSOR(Vector<somenumber> &dst,
1310 const number /*om*/) const
1311 {
1312 (void)dst;
1313 Assert(cols != nullptr, ExcNotInitialized());
1314 Assert(val != nullptr, ExcNotInitialized());
1315 Assert(m() == n(),
1316 ExcMessage("This operation is only valid on square matrices."));
1317 Assert(m() == dst.size(), ExcDimensionMismatch(m(), dst.size()));
1318
1319 Assert(false, ExcNotImplemented());
1320 }
1321
1322
1323 template <typename number>
1324 template <typename somenumber>
1325 void
PSOR(Vector<somenumber> & dst,const std::vector<size_type> & permutation,const std::vector<size_type> & inverse_permutation,const number)1326 ChunkSparseMatrix<number>::PSOR(
1327 Vector<somenumber> & dst,
1328 const std::vector<size_type> &permutation,
1329 const std::vector<size_type> &inverse_permutation,
1330 const number /*om*/) const
1331 {
1332 (void)dst;
1333 (void)permutation;
1334 (void)inverse_permutation;
1335 Assert(cols != nullptr, ExcNotInitialized());
1336 Assert(val != nullptr, ExcNotInitialized());
1337 Assert(m() == n(),
1338 ExcMessage("This operation is only valid on square matrices."));
1339
1340 Assert(m() == dst.size(), ExcDimensionMismatch(m(), dst.size()));
1341 Assert(m() == permutation.size(),
1342 ExcDimensionMismatch(m(), permutation.size()));
1343 Assert(m() == inverse_permutation.size(),
1344 ExcDimensionMismatch(m(), inverse_permutation.size()));
1345
1346 Assert(false, ExcNotImplemented());
1347 }
1348
1349
1350 template <typename number>
1351 template <typename somenumber>
1352 void
TPSOR(Vector<somenumber> & dst,const std::vector<size_type> & permutation,const std::vector<size_type> & inverse_permutation,const number)1353 ChunkSparseMatrix<number>::TPSOR(
1354 Vector<somenumber> & dst,
1355 const std::vector<size_type> &permutation,
1356 const std::vector<size_type> &inverse_permutation,
1357 const number /*om*/) const
1358 {
1359 (void)dst;
1360 (void)permutation;
1361 (void)inverse_permutation;
1362 Assert(cols != nullptr, ExcNotInitialized());
1363 Assert(val != nullptr, ExcNotInitialized());
1364 Assert(m() == n(),
1365 ExcMessage("This operation is only valid on square matrices."));
1366
1367 Assert(m() == dst.size(), ExcDimensionMismatch(m(), dst.size()));
1368 Assert(m() == permutation.size(),
1369 ExcDimensionMismatch(m(), permutation.size()));
1370 Assert(m() == inverse_permutation.size(),
1371 ExcDimensionMismatch(m(), inverse_permutation.size()));
1372
1373 Assert(false, ExcNotImplemented());
1374 }
1375
1376
1377
1378 template <typename number>
1379 template <typename somenumber>
1380 void
SOR_step(Vector<somenumber> & v,const Vector<somenumber> & b,const number)1381 ChunkSparseMatrix<number>::SOR_step(Vector<somenumber> & v,
1382 const Vector<somenumber> &b,
1383 const number /*om*/) const
1384 {
1385 (void)v;
1386 (void)b;
1387 Assert(cols != nullptr, ExcNotInitialized());
1388 Assert(val != nullptr, ExcNotInitialized());
1389 Assert(m() == n(),
1390 ExcMessage("This operation is only valid on square matrices."));
1391
1392 Assert(m() == v.size(), ExcDimensionMismatch(m(), v.size()));
1393 Assert(m() == b.size(), ExcDimensionMismatch(m(), b.size()));
1394
1395 Assert(false, ExcNotImplemented());
1396 }
1397
1398
1399
1400 template <typename number>
1401 template <typename somenumber>
1402 void
TSOR_step(Vector<somenumber> & v,const Vector<somenumber> & b,const number)1403 ChunkSparseMatrix<number>::TSOR_step(Vector<somenumber> & v,
1404 const Vector<somenumber> &b,
1405 const number /*om*/) const
1406 {
1407 (void)v;
1408 (void)b;
1409 Assert(cols != nullptr, ExcNotInitialized());
1410 Assert(val != nullptr, ExcNotInitialized());
1411 Assert(m() == n(),
1412 ExcMessage("This operation is only valid on square matrices."));
1413
1414 Assert(m() == v.size(), ExcDimensionMismatch(m(), v.size()));
1415 Assert(m() == b.size(), ExcDimensionMismatch(m(), b.size()));
1416
1417 Assert(false, ExcNotImplemented());
1418 }
1419
1420
1421
1422 template <typename number>
1423 template <typename somenumber>
1424 void
SSOR_step(Vector<somenumber> & v,const Vector<somenumber> & b,const number om)1425 ChunkSparseMatrix<number>::SSOR_step(Vector<somenumber> & v,
1426 const Vector<somenumber> &b,
1427 const number om) const
1428 {
1429 SOR_step(v, b, om);
1430 TSOR_step(v, b, om);
1431 }
1432
1433
1434
1435 template <typename number>
1436 template <typename somenumber>
1437 void
SSOR(Vector<somenumber> & dst,const number)1438 ChunkSparseMatrix<number>::SSOR(Vector<somenumber> &dst,
1439 const number /*om*/) const
1440 {
1441 (void)dst;
1442 Assert(cols != nullptr, ExcNotInitialized());
1443 Assert(val != nullptr, ExcNotInitialized());
1444 Assert(m() == n(),
1445 ExcMessage("This operation is only valid on square matrices."));
1446
1447 Assert(m() == dst.size(), ExcDimensionMismatch(m(), dst.size()));
1448
1449 Assert(false, ExcNotImplemented());
1450 }
1451
1452
1453
1454 template <typename number>
1455 void
print(std::ostream & out)1456 ChunkSparseMatrix<number>::print(std::ostream &out) const
1457 {
1458 AssertThrow(out, ExcIO());
1459
1460 Assert(cols != nullptr, ExcNotInitialized());
1461 Assert(val != nullptr, ExcNotInitialized());
1462
1463 Assert(false, ExcNotImplemented());
1464
1465 AssertThrow(out, ExcIO());
1466 }
1467
1468
1469 template <typename number>
1470 void
print_formatted(std::ostream & out,const unsigned int precision,const bool scientific,const unsigned int width_,const char * zero_string,const double denominator)1471 ChunkSparseMatrix<number>::print_formatted(std::ostream & out,
1472 const unsigned int precision,
1473 const bool scientific,
1474 const unsigned int width_,
1475 const char * zero_string,
1476 const double denominator) const
1477 {
1478 AssertThrow(out, ExcIO());
1479
1480 Assert(cols != nullptr, ExcNotInitialized());
1481 Assert(val != nullptr, ExcNotInitialized());
1482
1483 unsigned int width = width_;
1484
1485 Assert(false, ExcNotImplemented());
1486
1487 std::ios::fmtflags old_flags = out.flags();
1488 unsigned int old_precision = out.precision(precision);
1489
1490 if (scientific)
1491 {
1492 out.setf(std::ios::scientific, std::ios::floatfield);
1493 if (!width)
1494 width = precision + 7;
1495 }
1496 else
1497 {
1498 out.setf(std::ios::fixed, std::ios::floatfield);
1499 if (!width)
1500 width = precision + 2;
1501 }
1502
1503 for (size_type i = 0; i < m(); ++i)
1504 {
1505 for (size_type j = 0; j < n(); ++j)
1506 if (cols->sparsity_pattern(i, j) != SparsityPattern::invalid_entry)
1507 out << std::setw(width)
1508 << val[cols->sparsity_pattern(i, j)] * denominator << ' ';
1509 else
1510 out << std::setw(width) << zero_string << ' ';
1511 out << std::endl;
1512 };
1513 AssertThrow(out, ExcIO());
1514
1515 // reset output format
1516 out.precision(old_precision);
1517 out.flags(old_flags);
1518 }
1519
1520
1521
1522 template <typename number>
1523 void
print_pattern(std::ostream & out,const double threshold)1524 ChunkSparseMatrix<number>::print_pattern(std::ostream &out,
1525 const double threshold) const
1526 {
1527 AssertThrow(out, ExcIO());
1528
1529 Assert(cols != nullptr, ExcNotInitialized());
1530 Assert(val != nullptr, ExcNotInitialized());
1531
1532 const size_type chunk_size = cols->get_chunk_size();
1533
1534 // loop over all chunk rows and columns, and each time we find something
1535 // repeat it chunk_size times in both directions
1536 for (size_type i = 0; i < cols->sparsity_pattern.n_rows(); ++i)
1537 {
1538 for (size_type d = 0; d < chunk_size; ++d)
1539 for (size_type j = 0; j < cols->sparsity_pattern.n_cols(); ++j)
1540 if (cols->sparsity_pattern(i, j) == SparsityPattern::invalid_entry)
1541 {
1542 for (size_type e = 0; e < chunk_size; ++e)
1543 out << '.';
1544 }
1545 else if (std::fabs(val[cols->sparsity_pattern(i, j)]) > threshold)
1546 {
1547 for (size_type e = 0; e < chunk_size; ++e)
1548 out << '*';
1549 }
1550 else
1551 {
1552 for (size_type e = 0; e < chunk_size; ++e)
1553 out << ':';
1554 }
1555 out << std::endl;
1556 }
1557
1558 AssertThrow(out, ExcIO());
1559 }
1560
1561
1562
1563 template <typename number>
1564 void
block_write(std::ostream & out)1565 ChunkSparseMatrix<number>::block_write(std::ostream &out) const
1566 {
1567 AssertThrow(out, ExcIO());
1568
1569 // first the simple objects, bracketed in [...]
1570 out << '[' << max_len << "][";
1571 // then write out real data
1572 out.write(reinterpret_cast<const char *>(val.get()),
1573 reinterpret_cast<const char *>(val.get() + max_len) -
1574 reinterpret_cast<const char *>(val.get()));
1575 out << ']';
1576
1577 AssertThrow(out, ExcIO());
1578 }
1579
1580
1581
1582 template <typename number>
1583 void
block_read(std::istream & in)1584 ChunkSparseMatrix<number>::block_read(std::istream &in)
1585 {
1586 AssertThrow(in, ExcIO());
1587
1588 char c;
1589
1590 // first read in simple data
1591 in >> c;
1592 AssertThrow(c == '[', ExcIO());
1593 in >> max_len;
1594
1595 in >> c;
1596 AssertThrow(c == ']', ExcIO());
1597 in >> c;
1598 AssertThrow(c == '[', ExcIO());
1599
1600 // reallocate space
1601 val = std::make_unique<number[]>(max_len);
1602
1603 // then read data
1604 in.read(reinterpret_cast<char *>(val.get()),
1605 reinterpret_cast<char *>(val.get() + max_len) -
1606 reinterpret_cast<char *>(val.get()));
1607 in >> c;
1608 AssertThrow(c == ']', ExcIO());
1609 }
1610
1611
1612
1613 template <typename number>
1614 std::size_t
memory_consumption()1615 ChunkSparseMatrix<number>::memory_consumption() const
1616 {
1617 return sizeof(*this) + max_len * sizeof(number);
1618 }
1619
1620
1621 DEAL_II_NAMESPACE_CLOSE
1622
1623 #endif
1624