Reference documentation for deal.II version 9.1.0-pre
chunk_sparsity_pattern.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2008 - 2017 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_sparsity_pattern_h
17 #define dealii_chunk_sparsity_pattern_h
18 
19 
20 #include <deal.II/base/config.h>
21 
22 #include <deal.II/base/exceptions.h>
23 #include <deal.II/base/subscriptor.h>
24 #include <deal.II/base/vector_slice.h>
25 
26 #include <deal.II/lac/sparsity_pattern.h>
27 
28 #include <iostream>
29 #include <vector>
30 
31 DEAL_II_NAMESPACE_OPEN
32 
33 
34 template <typename>
35 class ChunkSparseMatrix;
36 
37 
48 {
49  // forward declaration
50  class Iterator;
51 
64  class Accessor
65  {
66  public:
70  Accessor(const ChunkSparsityPattern *matrix, const unsigned int row);
71 
75  Accessor(const ChunkSparsityPattern *matrix);
76 
81  unsigned int
82  row() const;
83 
87  std::size_t
88  reduced_index() const;
89 
94  unsigned int
95  column() const;
96 
106  bool
107  is_valid_entry() const;
108 
109 
113  bool
114  operator==(const Accessor &) const;
115 
116 
124  bool
125  operator<(const Accessor &) const;
126 
127  protected:
132 
137 
141  unsigned int chunk_row;
142 
146  unsigned int chunk_col;
147 
151  void
152  advance();
153 
157  friend class Iterator;
158  };
159 
160 
161 
165  class Iterator
166  {
167  public:
172  Iterator(const ChunkSparsityPattern *sp, const unsigned int row);
173 
177  Iterator &
178  operator++();
179 
183  Iterator
184  operator++(int);
185 
189  const Accessor &operator*() const;
190 
194  const Accessor *operator->() const;
195 
199  bool
200  operator==(const Iterator &) const;
201 
205  bool
206  operator!=(const Iterator &) const;
207 
215  bool
216  operator<(const Iterator &) const;
217 
218  private:
223  };
224 } // namespace ChunkSparsityPatternIterators
225 
226 
227 
239 {
240 public:
250 
259 
274  static const size_type invalid_entry = SparsityPattern::invalid_entry;
275 
282 
299 
307  const size_type n,
308  const size_type max_chunks_per_row,
309  const size_type chunk_size);
310 
319  const size_type n,
320  const std::vector<size_type> &row_lengths,
321  const size_type chunk_size);
322 
332  const size_type max_per_row,
333  const size_type chunk_size);
334 
343  const std::vector<size_type> &row_lengths,
344  const size_type chunk_size);
345 
349  ~ChunkSparsityPattern() override = default;
350 
357  operator=(const ChunkSparsityPattern &);
358 
367  void
368  reinit(const size_type m,
369  const size_type n,
370  const size_type max_per_row,
371  const size_type chunk_size);
372 
387  void
388  reinit(const size_type m,
389  const size_type n,
390  const std::vector<size_type> &row_lengths,
391  const size_type chunk_size);
392 
396  void
397  reinit(const size_type m,
398  const size_type n,
399  const VectorSlice<const std::vector<size_type>> &row_lengths,
400  const size_type chunk_size);
401 
414  void
415  compress();
416 
493  template <typename ForwardIterator>
494  void
495  copy_from(const size_type n_rows,
496  const size_type n_cols,
497  const ForwardIterator begin,
498  const ForwardIterator end,
499  const size_type chunk_size);
500 
506  template <typename SparsityPatternType>
507  void
508  copy_from(const SparsityPatternType &dsp, const size_type chunk_size);
509 
517  template <typename number>
518  void
519  copy_from(const FullMatrix<number> &matrix, const size_type chunk_size);
520 
538  template <typename Sparsity>
539  void
540  create_from(const unsigned int m,
541  const unsigned int n,
542  const Sparsity & sparsity_pattern_for_chunks,
543  const unsigned int chunk_size,
544  const bool optimize_diagonal = true);
545 
550  bool
551  empty() const;
552 
556  size_type
557  get_chunk_size() const;
558 
564  size_type
565  max_entries_per_row() const;
566 
573  void
574  add(const size_type i, const size_type j);
575 
583  void
584  symmetrize();
585 
590  inline size_type
591  n_rows() const;
592 
597  inline size_type
598  n_cols() const;
599 
603  bool
604  exists(const size_type i, const size_type j) const;
605 
609  size_type
610  row_length(const size_type row) const;
611 
618  size_type
619  bandwidth() const;
620 
629  size_type
630  n_nonzero_elements() const;
631 
635  bool
636  is_compressed() const;
637 
650  bool
651  stores_only_added_elements() const;
652 
658  iterator
659  begin() const;
660 
664  iterator
665  end() const;
666 
675  iterator
676  begin(const unsigned int r) const;
677 
686  iterator
687  end(const unsigned int r) const;
688 
699  void
700  block_write(std::ostream &out) const;
701 
715  void
716  block_read(std::istream &in);
717 
723  void
724  print(std::ostream &out) const;
725 
739  void
740  print_gnuplot(std::ostream &out) const;
741 
746  std::size_t
747  memory_consumption() const;
748 
757  int,
758  << "The provided number is invalid here: " << arg1);
762  DeclException2(ExcInvalidIndex,
763  int,
764  int,
765  << "The given index " << arg1 << " should be less than "
766  << arg2 << ".");
770  DeclException2(ExcNotEnoughSpace,
771  int,
772  int,
773  << "Upon entering a new entry to row " << arg1
774  << ": there was no free entry any more. " << std::endl
775  << "(Maximum number of entries for this row: " << arg2
776  << "; maybe the matrix is already compressed?)");
782  ExcNotCompressed,
783  "The operation you attempted is only allowed after the SparsityPattern "
784  "has been set up and compress() was called.");
790  ExcMatrixIsCompressed,
791  "The operation you attempted changes the structure of the SparsityPattern "
792  "and is not possible after compress() has been called.");
800  DeclException2(ExcIteratorRange,
801  int,
802  int,
803  << "The iterators denote a range of " << arg1
804  << " elements, but the given number of rows was " << arg2);
813  int,
814  << "The number of partitions you gave is " << arg1
815  << ", but must be greater than zero.");
820  int,
821  int,
822  << "The array has size " << arg1 << " but should have size "
823  << arg2);
825 private:
830 
835 
840 
846 
850  template <typename>
851  friend class ChunkSparseMatrix;
852 
857 };
858 
859 
861 /*---------------------- Inline functions -----------------------------------*/
862 
863 #ifndef DOXYGEN
864 
866 {
868  const unsigned int row)
869  : sparsity_pattern(sparsity_pattern)
870  , reduced_accessor(row == sparsity_pattern->n_rows() ?
871  *sparsity_pattern->sparsity_pattern.end() :
872  *sparsity_pattern->sparsity_pattern.begin(
873  row / sparsity_pattern->get_chunk_size()))
874  , chunk_row(row == sparsity_pattern->n_rows() ?
875  0 :
876  row % sparsity_pattern->get_chunk_size())
877  , chunk_col(0)
878  {}
879 
880 
881 
882  inline Accessor::Accessor(const ChunkSparsityPattern *sparsity_pattern)
883  : sparsity_pattern(sparsity_pattern)
884  , reduced_accessor(*sparsity_pattern->sparsity_pattern.end())
885  , chunk_row(0)
886  , chunk_col(0)
887  {}
888 
889 
890 
891  inline bool
892  Accessor::is_valid_entry() const
893  {
894  return reduced_accessor.is_valid_entry() &&
895  sparsity_pattern->get_chunk_size() * reduced_accessor.row() +
896  chunk_row <
898  sparsity_pattern->get_chunk_size() * reduced_accessor.column() +
899  chunk_col <
901  }
902 
903 
904 
905  inline unsigned int
906  Accessor::row() const
907  {
908  Assert(is_valid_entry() == true, ExcInvalidIterator());
909 
910  return sparsity_pattern->get_chunk_size() * reduced_accessor.row() +
911  chunk_row;
912  }
913 
914 
915 
916  inline unsigned int
917  Accessor::column() const
918  {
919  Assert(is_valid_entry() == true, ExcInvalidIterator());
920 
921  return sparsity_pattern->get_chunk_size() * reduced_accessor.column() +
922  chunk_col;
923  }
924 
925 
926 
927  inline std::size_t
928  Accessor::reduced_index() const
929  {
930  Assert(is_valid_entry() == true, ExcInvalidIterator());
931 
932  return reduced_accessor.index_within_sparsity;
933  }
934 
935 
936 
937  inline bool
938  Accessor::operator==(const Accessor &other) const
939  {
940  // no need to check for equality of sparsity patterns as this is done in
941  // the reduced case already and every ChunkSparsityPattern has its own
942  // reduced sparsity pattern
943  return (reduced_accessor == other.reduced_accessor &&
944  chunk_row == other.chunk_row && chunk_col == other.chunk_col);
945  }
946 
947 
948 
949  inline bool
950  Accessor::operator<(const Accessor &other) const
951  {
952  Assert(sparsity_pattern == other.sparsity_pattern, ExcInternalError());
953 
954  if (chunk_row != other.chunk_row)
955  {
956  if (reduced_accessor.index_within_sparsity ==
957  reduced_accessor.sparsity_pattern->n_nonzero_elements())
958  return false;
959  if (other.reduced_accessor.index_within_sparsity ==
960  reduced_accessor.sparsity_pattern->n_nonzero_elements())
961  return true;
962 
963  const unsigned int global_row = sparsity_pattern->get_chunk_size() *
964  reduced_accessor.row() +
965  chunk_row,
966  other_global_row =
967  sparsity_pattern->get_chunk_size() *
968  other.reduced_accessor.row() +
969  other.chunk_row;
970  if (global_row < other_global_row)
971  return true;
972  else if (global_row > other_global_row)
973  return false;
974  }
975 
976  return (reduced_accessor.index_within_sparsity <
977  other.reduced_accessor.index_within_sparsity ||
978  (reduced_accessor.index_within_sparsity ==
979  other.reduced_accessor.index_within_sparsity &&
980  chunk_col < other.chunk_col));
981  }
982 
983 
984  inline void
985  Accessor::advance()
986  {
987  const unsigned int chunk_size = sparsity_pattern->get_chunk_size();
988  Assert(chunk_row < chunk_size && chunk_col < chunk_size,
990  Assert(reduced_accessor.row() * chunk_size + chunk_row <
992  reduced_accessor.column() * chunk_size + chunk_col <
995  if (chunk_size == 1)
996  {
997  reduced_accessor.advance();
998  return;
999  }
1000 
1001  ++chunk_col;
1002 
1003  // end of chunk
1004  if (chunk_col == chunk_size ||
1005  reduced_accessor.column() * chunk_size + chunk_col ==
1007  {
1008  const unsigned int reduced_row = reduced_accessor.row();
1009  // end of row
1010  if (reduced_accessor.index_within_sparsity + 1 ==
1011  reduced_accessor.sparsity_pattern->rowstart[reduced_row + 1])
1012  {
1013  ++chunk_row;
1014 
1015  chunk_col = 0;
1016 
1017  // end of chunk rows or end of matrix
1018  if (chunk_row == chunk_size ||
1019  (reduced_row * chunk_size + chunk_row ==
1021  {
1022  chunk_row = 0;
1023  reduced_accessor.advance();
1024  }
1025  // go back to the beginning of the same reduced row but with
1026  // chunk_row increased by one
1027  else
1028  reduced_accessor.index_within_sparsity =
1029  reduced_accessor.sparsity_pattern->rowstart[reduced_row];
1030  }
1031  // advance within chunk
1032  else
1033  {
1034  reduced_accessor.advance();
1035  chunk_col = 0;
1036  }
1037  }
1038  }
1039 
1040 
1041 
1042  inline Iterator::Iterator(const ChunkSparsityPattern *sparsity_pattern,
1043  const unsigned int row)
1044  : accessor(sparsity_pattern, row)
1045  {}
1046 
1047 
1048 
1049  inline Iterator &
1050  Iterator::operator++()
1051  {
1052  accessor.advance();
1053  return *this;
1054  }
1055 
1056 
1057 
1058  inline Iterator
1059  Iterator::operator++(int)
1060  {
1061  const Iterator iter = *this;
1062  accessor.advance();
1063  return iter;
1064  }
1065 
1066 
1067 
1068  inline const Accessor &Iterator::operator*() const
1069  {
1070  return accessor;
1071  }
1072 
1073 
1074 
1075  inline const Accessor *Iterator::operator->() const
1076  {
1077  return &accessor;
1078  }
1079 
1080 
1081  inline bool
1082  Iterator::operator==(const Iterator &other) const
1083  {
1084  return (accessor == other.accessor);
1085  }
1086 
1087 
1088 
1089  inline bool
1090  Iterator::operator!=(const Iterator &other) const
1091  {
1092  return !(accessor == other.accessor);
1093  }
1094 
1095 
1096  inline bool
1097  Iterator::operator<(const Iterator &other) const
1098  {
1099  return accessor < other.accessor;
1100  }
1101 
1102 } // namespace ChunkSparsityPatternIterators
1103 
1104 
1105 
1108 {
1109  return iterator(this, 0);
1110 }
1111 
1112 
1115 {
1116  return iterator(this, n_rows());
1117 }
1118 
1119 
1120 
1122 ChunkSparsityPattern::begin(const unsigned int r) const
1123 {
1124  Assert(r < n_rows(), ExcIndexRange(r, 0, n_rows()));
1125  return iterator(this, r);
1126 }
1127 
1128 
1129 
1131 ChunkSparsityPattern::end(const unsigned int r) const
1132 {
1133  Assert(r < n_rows(), ExcIndexRange(r, 0, n_rows())) return iterator(this,
1134  r + 1);
1135 }
1136 
1137 
1138 
1141 {
1142  return rows;
1143 }
1144 
1145 
1148 {
1149  return cols;
1150 }
1151 
1152 
1153 
1156 {
1157  return chunk_size;
1158 }
1159 
1160 
1161 
1162 inline bool
1164 {
1166 }
1167 
1168 
1169 
1170 template <typename ForwardIterator>
1171 void
1173  const size_type n_cols,
1174  const ForwardIterator begin,
1175  const ForwardIterator end,
1176  const size_type chunk_size)
1177 {
1178  Assert(static_cast<size_type>(std::distance(begin, end)) == n_rows,
1179  ExcIteratorRange(std::distance(begin, end), n_rows));
1180 
1181  // first determine row lengths for each row. if the matrix is quadratic,
1182  // then we might have to add an additional entry for the diagonal, if that
1183  // is not yet present. as we have to call compress anyway later on, don't
1184  // bother to check whether that diagonal entry is in a certain row or not
1185  const bool is_square = (n_rows == n_cols);
1186  std::vector<size_type> row_lengths;
1187  row_lengths.reserve(n_rows);
1188  for (ForwardIterator i = begin; i != end; ++i)
1189  row_lengths.push_back(std::distance(i->begin(), i->end()) +
1190  (is_square ? 1 : 0));
1191  reinit(n_rows, n_cols, row_lengths, chunk_size);
1192 
1193  // now enter all the elements into the matrix
1194  size_type row = 0;
1195  using inner_iterator =
1196  typename std::iterator_traits<ForwardIterator>::value_type::const_iterator;
1197  for (ForwardIterator i = begin; i != end; ++i, ++row)
1198  {
1199  const inner_iterator end_of_row = i->end();
1200  for (inner_iterator j = i->begin(); j != end_of_row; ++j)
1201  {
1202  const size_type col =
1203  internal::SparsityPatternTools::get_column_index_from_iterator(*j);
1204  Assert(col < n_cols, ExcInvalidIndex(col, n_cols));
1205 
1206  add(row, col);
1207  }
1208  }
1209 
1210  // finally compress everything. this also sorts the entries within each row
1211  compress();
1212 }
1213 
1214 
1215 #endif // DOXYGEN
1216 
1217 DEAL_II_NAMESPACE_CLOSE
1218 
1219 #endif
size_type n_rows() const
void copy_from(const size_type n_rows, const size_type n_cols, const ForwardIterator begin, const ForwardIterator end, const size_type chunk_size)
#define DeclException2(Exception2, type1, type2, outsequence)
Definition: exceptions.h:420
static::ExceptionBase & ExcInvalidIndex(int arg1, int arg2)
static const size_type invalid_entry
types::global_dof_index size_type
bool is_compressed() const
static::ExceptionBase & ExcMETISNotInstalled()
bool operator==(const Accessor &) const
const ChunkSparsityPattern * sparsity_pattern
void add(const size_type i, const size_type j)
ChunkSparsityPatternIterators::Iterator iterator
static::ExceptionBase & ExcIndexRange(int arg1, int arg2, int arg3)
SymmetricTensor< rank_, dim, Number > operator*(const SymmetricTensor< rank_, dim, Number > &t, const Number &factor)
unsigned long long int global_dof_index
Definition: types.h:72
SparsityPattern sparsity_pattern
iterator end() const
static::ExceptionBase & ExcInvalidIterator()
iterator begin() const
size_type get_chunk_size() const
static::ExceptionBase & ExcInvalidNumberOfPartitions(int arg1)
#define DeclException1(Exception1, type1, outsequence)
Definition: exceptions.h:408
#define Assert(cond, exc)
Definition: exceptions.h:1227
static::ExceptionBase & ExcInvalidArraySize(int arg1, int arg2)
bool operator<(const Accessor &) const
#define DeclExceptionMsg(Exception, defaulttext)
Definition: exceptions.h:397
size_type n_cols() const
#define DeclException0(Exception0)
Definition: exceptions.h:385
static::ExceptionBase & ExcInvalidNumber(unsigned int arg1)
static::ExceptionBase & ExcIteratorRange(int arg1, int arg2)
SymmetricTensor< 2, dim, Number > symmetrize(const Tensor< 2, dim, Number > &t)
static::ExceptionBase & ExcIteratorPastEnd()
Accessor(const ChunkSparsityPattern *matrix, const unsigned int row)
size_type n_cols() const
size_type n_rows() const
static::ExceptionBase & ExcEmptyObject()
SparsityPatternIterators::Accessor reduced_accessor
void reinit(const size_type m, const size_type n, const size_type max_per_row, const size_type chunk_size)
static::ExceptionBase & ExcInternalError()