Reference documentation for deal.II version 9.1.0-pre
sparsity_pattern.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2000 - 2018 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_sparsity_pattern_h
17 #define dealii_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/std_cxx14/memory.h>
24 #include <deal.II/base/subscriptor.h>
25 
26 // boost::serialization::make_array used to be in array.hpp, but was
27 // moved to a different file in BOOST 1.64
28 #include <boost/version.hpp>
29 #if BOOST_VERSION >= 106400
30 # include <boost/serialization/array_wrapper.hpp>
31 #else
32 # include <boost/serialization/array.hpp>
33 #endif
34 #include <boost/serialization/split_member.hpp>
35 
36 #include <algorithm>
37 #include <iostream>
38 #include <vector>
39 
40 DEAL_II_NAMESPACE_OPEN
41 
42 class SparsityPattern;
45 template <typename number>
46 class FullMatrix;
47 template <typename number>
48 class SparseMatrix;
49 template <typename number>
51 template <typename number>
52 class SparseILU;
53 template <typename VectorType>
54 class VectorSlice;
55 
57 {
58  class Accessor;
59 }
60 
61 
66 namespace internals
67 {
68  namespace SparsityPatternTools
69  {
74 
80  size_type
81  get_column_index_from_iterator(const size_type i);
82 
88  template <typename value>
89  size_type
90  get_column_index_from_iterator(const std::pair<size_type, value> &i);
91 
97  template <typename value>
98  size_type
99  get_column_index_from_iterator(const std::pair<const size_type, value> &i);
100 
101  } // namespace SparsityPatternTools
102 } // namespace internals
103 
104 
109 {
110  // forward declaration
111  class Iterator;
112 
117 
131  class Accessor
132  {
133  public:
137  Accessor(const SparsityPattern *matrix,
138  const std::size_t index_within_sparsity);
139 
143  Accessor(const SparsityPattern *matrix);
144 
149  size_type
150  row() const;
151 
157  size_type
158  index() const;
159 
169  size_type
170  global_index() const;
171 
176  size_type
177  column() const;
178 
188  bool
189  is_valid_entry() const;
190 
194  bool
195  operator==(const Accessor &) const;
196 
204  bool
205  operator<(const Accessor &) const;
206 
207  protected:
212 
221 
225  void
226  advance();
227 
231  friend class Iterator;
232 
237  };
238 
239 
240 
265  class Iterator
266  {
267  public:
273  Iterator(const SparsityPattern *sp,
274  const std::size_t index_within_sparsity);
275 
279  Iterator &
280  operator++();
281 
285  Iterator
286  operator++(int);
287 
291  const Accessor &operator*() const;
292 
296  const Accessor *operator->() const;
297 
301  bool
302  operator==(const Iterator &) const;
303 
307  bool
308  operator!=(const Iterator &) const;
309 
317  bool
318  operator<(const Iterator &) const;
319 
326  int
327  operator-(const Iterator &p) const;
328 
329  private:
334  };
335 } // namespace SparsityPatternIterators
336 
337 
338 
374 {
375 public:
380 
386 
395 
396 
411  static const size_type invalid_entry = numbers::invalid_size_type;
412 
417  // @{
423  SparsityPattern();
424 
441 
449  SparsityPattern(const size_type m,
450  const size_type n,
451  const unsigned int max_per_row);
452 
453 
462  SparsityPattern(const size_type m,
463  const size_type n,
464  const std::vector<unsigned int> &row_lengths);
465 
474  SparsityPattern(const size_type m, const unsigned int max_per_row);
475 
483  SparsityPattern(const size_type m,
484  const std::vector<unsigned int> &row_lengths);
485 
508  SparsityPattern(const SparsityPattern &original,
509  const unsigned int max_per_row,
510  const size_type extra_off_diagonals);
511 
515  ~SparsityPattern() override = default;
516 
523  operator=(const SparsityPattern &);
524 
533  void
534  reinit(const size_type m, const size_type n, const unsigned int max_per_row);
535 
536 
551  void
552  reinit(const size_type m,
553  const size_type n,
554  const std::vector<unsigned int> &row_lengths);
555 
556 
560  void
561  reinit(const size_type m,
562  const size_type n,
563  const VectorSlice<const std::vector<unsigned int>> &row_lengths);
564 
577  void
578  compress();
579 
580 
657  template <typename ForwardIterator>
658  void
659  copy_from(const size_type n_rows,
660  const size_type n_cols,
661  const ForwardIterator begin,
662  const ForwardIterator end);
663 
668  void
669  copy_from(const DynamicSparsityPattern &dsp);
670 
675  void
676  copy_from(const SparsityPattern &sp);
677 
685  template <typename number>
686  void
687  copy_from(const FullMatrix<number> &matrix);
688 
696  void
697  symmetrize();
698 
705  void
706  add(const size_type i, const size_type j);
707 
714  template <typename ForwardIterator>
715  void
716  add_entries(const size_type row,
717  ForwardIterator begin,
718  ForwardIterator end,
719  const bool indices_are_sorted = false);
720 
721  // @}
722 
723 
724 
728  // @{
729 
738  iterator
739  begin() const;
740 
744  iterator
745  end() const;
746 
758  iterator
759  begin(const size_type r) const;
760 
769  iterator
770  end(const size_type r) const;
771 
772 
773  // @}
777  // @{
781  bool
782  operator==(const SparsityPattern &) const;
783 
788  bool
789  empty() const;
790 
796  size_type
797  max_entries_per_row() const;
798 
808  size_type
809  bandwidth() const;
810 
819  std::size_t
820  n_nonzero_elements() const;
821 
825  bool
826  is_compressed() const;
827 
832  size_type
833  n_rows() const;
834 
839  size_type
840  n_cols() const;
841 
845  unsigned int
846  row_length(const size_type row) const;
847 
860  bool
861  stores_only_added_elements() const;
862 
867  std::size_t
868  memory_consumption() const;
869 
870  // @}
874  // @{
897  size_type
898  operator()(const size_type i, const size_type j) const;
899 
911  std::pair<size_type, size_type>
912  matrix_position(const std::size_t global_index) const;
913 
917  bool
918  exists(const size_type i, const size_type j) const;
919 
927  size_type
928  row_position(const size_type i, const size_type j) const;
929 
940  size_type
941  column_number(const size_type row, const unsigned int index) const;
942 
943 
944  // @}
948  // @{
959  void
960  block_write(std::ostream &out) const;
961 
975  void
976  block_read(std::istream &in);
977 
983  void
984  print(std::ostream &out) const;
985 
999  void
1000  print_gnuplot(std::ostream &out) const;
1001 
1009  void
1010  print_svg(std::ostream &out) const;
1011 
1012 
1017  template <class Archive>
1018  void
1019  save(Archive &ar, const unsigned int version) const;
1020 
1025  template <class Archive>
1026  void
1027  load(Archive &ar, const unsigned int version);
1028 
1029  BOOST_SERIALIZATION_SPLIT_MEMBER()
1030 
1031  // @}
1032 
1033 
1040  DeclException2(ExcNotEnoughSpace,
1041  int,
1042  int,
1043  << "Upon entering a new entry to row " << arg1
1044  << ": there was no free entry any more. " << std::endl
1045  << "(Maximum number of entries for this row: " << arg2
1046  << "; maybe the matrix is already compressed?)");
1052  ExcNotCompressed,
1053  "The operation you attempted is only allowed after the SparsityPattern "
1054  "has been set up and compress() was called.");
1060  ExcMatrixIsCompressed,
1061  "The operation you attempted changes the structure of the SparsityPattern "
1062  "and is not possible after compress() has been called.");
1066  DeclException2(ExcIteratorRange,
1067  int,
1068  int,
1069  << "The iterators denote a range of " << arg1
1070  << " elements, but the given number of rows was " << arg2);
1075  int,
1076  << "The number of partitions you gave is " << arg1
1077  << ", but must be greater than zero.");
1079 private:
1087  size_type max_dim;
1088 
1093 
1098 
1104  std::size_t max_vec_len;
1105 
1113  unsigned int max_row_length;
1114 
1128  std::unique_ptr<std::size_t[]> rowstart;
1129 
1152  std::unique_ptr<size_type[]> colnums;
1153 
1157  bool compressed;
1158 
1162  bool store_diagonal_first_in_row;
1163 
1167  template <typename number>
1168  friend class SparseMatrix;
1169  template <typename number>
1170  friend class SparseLUDecomposition;
1171  template <typename number>
1172  friend class SparseILU;
1173  template <typename number>
1174  friend class ChunkSparseMatrix;
1175 
1176  friend class ChunkSparsityPattern;
1177 
1181  friend class SparsityPatternIterators::Iterator;
1182  friend class SparsityPatternIterators::Accessor;
1183  friend class ChunkSparsityPatternIterators::Accessor;
1184 };
1185 
1186 
1188 /*---------------------- Inline functions -----------------------------------*/
1189 
1190 #ifndef DOXYGEN
1191 
1192 
1193 namespace SparsityPatternIterators
1194 {
1195  inline Accessor::Accessor(const SparsityPattern *sparsity_pattern,
1196  const std::size_t i)
1197  : sparsity_pattern(sparsity_pattern)
1198  , index_within_sparsity(i)
1199  {}
1200 
1201 
1202 
1203  inline Accessor::Accessor(const SparsityPattern *sparsity_pattern)
1204  : sparsity_pattern(sparsity_pattern)
1205  , index_within_sparsity(sparsity_pattern->rowstart[sparsity_pattern->rows])
1206  {}
1207 
1208 
1209 
1210  inline bool
1211  Accessor::is_valid_entry() const
1212  {
1213  return (index_within_sparsity <
1214  sparsity_pattern->rowstart[sparsity_pattern->rows] &&
1215  sparsity_pattern->colnums[index_within_sparsity] !=
1217  }
1218 
1219 
1220 
1221  inline size_type
1222  Accessor::row() const
1223  {
1224  Assert(is_valid_entry() == true, ExcInvalidIterator());
1225 
1226  const std::size_t *insert_point =
1227  std::upper_bound(sparsity_pattern->rowstart.get(),
1228  sparsity_pattern->rowstart.get() +
1229  sparsity_pattern->rows + 1,
1230  index_within_sparsity);
1231  return insert_point - sparsity_pattern->rowstart.get() - 1;
1232  }
1233 
1234 
1235 
1236  inline size_type
1237  Accessor::column() const
1238  {
1239  Assert(is_valid_entry() == true, ExcInvalidIterator());
1240 
1241  return (sparsity_pattern->colnums[index_within_sparsity]);
1242  }
1243 
1244 
1245 
1246  inline size_type
1247  Accessor::index() const
1248  {
1249  Assert(is_valid_entry() == true, ExcInvalidIterator());
1250 
1251  return index_within_sparsity - sparsity_pattern->rowstart[row()];
1252  }
1253 
1254 
1255 
1256  inline size_type
1257  Accessor::global_index() const
1258  {
1259  Assert(is_valid_entry() == true, ExcInvalidIterator());
1260 
1261  return index_within_sparsity;
1262  }
1263 
1264 
1265 
1266  inline bool
1267  Accessor::operator==(const Accessor &other) const
1268  {
1269  return (sparsity_pattern == other.sparsity_pattern &&
1270  index_within_sparsity == other.index_within_sparsity);
1271  }
1272 
1273 
1274 
1275  inline bool
1276  Accessor::operator<(const Accessor &other) const
1277  {
1278  Assert(sparsity_pattern == other.sparsity_pattern, ExcInternalError());
1279 
1280  return index_within_sparsity < other.index_within_sparsity;
1281  }
1282 
1283 
1284  inline void
1286  {
1287  Assert(index_within_sparsity <
1288  sparsity_pattern->rowstart[sparsity_pattern->rows],
1289  ExcIteratorPastEnd());
1290  ++index_within_sparsity;
1291  }
1292 
1293 
1294 
1295  inline Iterator::Iterator(const SparsityPattern *sparsity_pattern,
1296  const std::size_t i)
1297  : accessor(sparsity_pattern, i)
1298  {}
1299 
1300 
1301 
1302  inline Iterator &
1304  {
1305  accessor.advance();
1306  return *this;
1307  }
1308 
1309 
1310 
1311  inline Iterator
1313  {
1314  const Iterator iter = *this;
1315  accessor.advance();
1316  return iter;
1317  }
1318 
1319 
1320 
1321  inline const Accessor &Iterator::operator*() const
1322  {
1323  return accessor;
1324  }
1325 
1326 
1327 
1328  inline const Accessor *Iterator::operator->() const
1329  {
1330  return &accessor;
1331  }
1332 
1333 
1334  inline bool
1335  Iterator::operator==(const Iterator &other) const
1336  {
1337  return (accessor == other.accessor);
1338  }
1339 
1340 
1341 
1342  inline bool
1343  Iterator::operator!=(const Iterator &other) const
1344  {
1345  return !(*this == other);
1346  }
1347 
1348 
1349 
1350  inline bool
1351  Iterator::operator<(const Iterator &other) const
1352  {
1353  return accessor < other.accessor;
1354  }
1355 
1356 
1357 
1358  inline int
1359  Iterator::operator-(const Iterator &other) const
1360  {
1361  Assert(accessor.sparsity_pattern == other.accessor.sparsity_pattern,
1362  ExcInternalError());
1363 
1364  return (*this)->index_within_sparsity - other->index_within_sparsity;
1365  }
1366 } // namespace SparsityPatternIterators
1367 
1368 
1369 
1371 SparsityPattern::begin() const
1372 {
1373  return iterator(this, rowstart[0]);
1374 }
1375 
1376 
1377 
1379 SparsityPattern::end() const
1380 {
1381  return iterator(this, rowstart[rows]);
1382 }
1383 
1384 
1385 
1387 SparsityPattern::begin(const size_type r) const
1388 {
1389  Assert(r < n_rows(), ExcIndexRangeType<size_type>(r, 0, n_rows()));
1390 
1391  return iterator(this, rowstart[r]);
1392 }
1393 
1394 
1395 
1397 SparsityPattern::end(const size_type r) const
1398 {
1399  Assert(r < n_rows(), ExcIndexRangeType<size_type>(r, 0, n_rows()));
1400 
1401  return iterator(this, rowstart[r + 1]);
1402 }
1403 
1404 
1405 
1408 {
1409  return rows;
1410 }
1411 
1412 
1413 
1416 {
1417  return cols;
1418 }
1419 
1420 
1421 
1422 inline bool
1424 {
1425  return compressed;
1426 }
1427 
1428 
1429 
1430 inline bool
1432 {
1433  return (store_diagonal_first_in_row == false);
1434 }
1435 
1436 
1437 
1438 inline unsigned int
1439 SparsityPattern::row_length(const size_type row) const
1440 {
1441  Assert(row < rows, ExcIndexRangeType<size_type>(row, 0, rows));
1442  return rowstart[row + 1] - rowstart[row];
1443 }
1444 
1445 
1446 
1449  const unsigned int index) const
1450 {
1451  Assert(row < rows, ExcIndexRangeType<size_type>(row, 0, rows));
1452  Assert(index < row_length(row), ExcIndexRange(index, 0, row_length(row)));
1453 
1454  return colnums[rowstart[row] + index];
1455 }
1456 
1457 
1458 
1459 inline std::size_t
1461 {
1462  Assert(compressed, ExcNotCompressed());
1463 
1464  if ((rowstart != nullptr) && (colnums != nullptr))
1465  return rowstart[rows] - rowstart[0];
1466  else
1467  // the object is empty or has zero size
1468  return 0;
1469 }
1470 
1471 
1472 
1473 template <class Archive>
1474 inline void
1475 SparsityPattern::save(Archive &ar, const unsigned int) const
1476 {
1477  // forward to serialization function in the base class.
1478  ar &static_cast<const Subscriptor &>(*this);
1479 
1480  ar &max_dim &rows &cols &max_vec_len &max_row_length &compressed
1481  &store_diagonal_first_in_row;
1482 
1483  ar &boost::serialization::make_array(rowstart.get(), max_dim + 1);
1484  ar &boost::serialization::make_array(colnums.get(), max_vec_len);
1485 }
1486 
1487 
1488 
1489 template <class Archive>
1490 inline void
1491 SparsityPattern::load(Archive &ar, const unsigned int)
1492 {
1493  // forward to serialization function in the base class.
1494  ar &static_cast<Subscriptor &>(*this);
1495 
1496  ar &max_dim &rows &cols &max_vec_len &max_row_length &compressed
1497  &store_diagonal_first_in_row;
1498 
1499  rowstart = std_cxx14::make_unique<std::size_t[]>(max_dim + 1);
1500  colnums = std_cxx14::make_unique<size_type[]>(max_vec_len);
1501 
1502  ar &boost::serialization::make_array(rowstart.get(), max_dim + 1);
1503  ar &boost::serialization::make_array(colnums.get(), max_vec_len);
1504 }
1505 
1506 
1507 
1508 inline bool
1510 {
1511  // it isn't quite necessary to compare *all* member variables. by only
1512  // comparing the essential ones, we can say that two sparsity patterns are
1513  // equal even if one is compressed and the other is not (in which case some
1514  // of the member variables are not yet set correctly)
1515  if (rows != sp2.rows || cols != sp2.cols || compressed != sp2.compressed ||
1516  store_diagonal_first_in_row != sp2.store_diagonal_first_in_row)
1517  return false;
1518 
1519  for (size_type i = 0; i < rows + 1; ++i)
1520  if (rowstart[i] != sp2.rowstart[i])
1521  return false;
1522 
1523  for (size_type i = 0; i < rowstart[rows]; ++i)
1524  if (colnums[i] != sp2.colnums[i])
1525  return false;
1526 
1527  return true;
1528 }
1529 
1530 
1531 
1532 namespace internal
1533 {
1534  namespace SparsityPatternTools
1535  {
1540 
1541  inline size_type
1542  get_column_index_from_iterator(const size_type i)
1543  {
1544  return i;
1545  }
1546 
1547 
1548 
1549  template <typename value>
1550  inline size_type
1551  get_column_index_from_iterator(const std::pair<size_type, value> &i)
1552  {
1553  return i.first;
1554  }
1555 
1556 
1557 
1558  template <typename value>
1559  inline size_type
1560  get_column_index_from_iterator(const std::pair<const size_type, value> &i)
1561  {
1562  return i.first;
1563  }
1564  } // namespace SparsityPatternTools
1565 } // namespace internal
1566 
1567 
1568 
1569 template <typename ForwardIterator>
1570 void
1572  const size_type n_cols,
1573  const ForwardIterator begin,
1574  const ForwardIterator end)
1575 {
1576  Assert(static_cast<size_type>(std::distance(begin, end)) == n_rows,
1577  ExcIteratorRange(std::distance(begin, end), n_rows));
1578 
1579  // first determine row lengths for each row. if the matrix is quadratic,
1580  // then we might have to add an additional entry for the diagonal, if that
1581  // is not yet present. as we have to call compress anyway later on, don't
1582  // bother to check whether that diagonal entry is in a certain row or not
1583  const bool is_square = (n_rows == n_cols);
1584  std::vector<unsigned int> row_lengths;
1585  row_lengths.reserve(n_rows);
1586  for (ForwardIterator i = begin; i != end; ++i)
1587  row_lengths.push_back(std::distance(i->begin(), i->end()) +
1588  (is_square ? 1 : 0));
1589  reinit(n_rows, n_cols, row_lengths);
1590 
1591  // now enter all the elements into the matrix. note that if the matrix is
1592  // quadratic, then we already have the diagonal element preallocated
1593  //
1594  // for use in the inner loop, we define an alias to the type of the inner
1595  // iterators
1596  size_type row = 0;
1597  using inner_iterator =
1598  typename std::iterator_traits<ForwardIterator>::value_type::const_iterator;
1599  for (ForwardIterator i = begin; i != end; ++i, ++row)
1600  {
1601  size_type * cols = &colnums[rowstart[row]] + (is_square ? 1 : 0);
1602  const inner_iterator end_of_row = i->end();
1603  for (inner_iterator j = i->begin(); j != end_of_row; ++j)
1604  {
1605  const size_type col =
1606  internal::SparsityPatternTools::get_column_index_from_iterator(*j);
1607  Assert(col < n_cols, ExcIndexRange(col, 0, n_cols));
1608 
1609  if ((col != row) || !is_square)
1610  *cols++ = col;
1611  }
1612  }
1613 
1614  // finally compress everything. this also sorts the entries within each row
1615  compress();
1616 }
1617 
1618 
1619 #endif // DOXYGEN
1620 
1621 DEAL_II_NAMESPACE_CLOSE
1622 
1623 #endif
const types::global_dof_index invalid_size_type
Definition: types.h:182
#define DeclException2(Exception2, type1, type2, outsequence)
Definition: exceptions.h:420
Iterator(const ChunkSparsityPattern *sp, const unsigned int row)
static const size_type invalid_entry
void save(Archive &ar, const unsigned int version) const
iterator begin() const
types::global_dof_index size_type
bool operator==(const Accessor &) const
STL namespace.
const Accessor * operator->() const
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
std::unique_ptr< size_type[]> colnums
static::ExceptionBase & ExcInvalidIterator()
static::ExceptionBase & ExcInvalidNumberOfPartitions(int arg1)
#define DeclException1(Exception1, type1, outsequence)
Definition: exceptions.h:408
#define Assert(cond, exc)
Definition: exceptions.h:1227
bool operator<(const Accessor &) const
#define DeclExceptionMsg(Exception, defaulttext)
Definition: exceptions.h:397
size_type n_cols() const
unsigned int row_length(const size_type row) const
size_type column_number(const size_type row, const unsigned int index) const
SymmetricTensor< 2, dim, Number > symmetrize(const Tensor< 2, dim, Number > &t)
bool stores_only_added_elements() const
iterator end() const
void load(Archive &ar, const unsigned int version)
void copy_from(const size_type n_rows, const size_type n_cols, const ForwardIterator begin, const ForwardIterator end)
bool operator<(const Iterator &) const
types::global_dof_index size_type
static::ExceptionBase & ExcIteratorPastEnd()
Accessor(const ChunkSparsityPattern *matrix, const unsigned int row)
bool operator==(const Iterator &) const
const SparsityPattern * sparsity_pattern
std::unique_ptr< std::size_t[]> rowstart
size_type n_rows() const
bool operator==(const SparsityPattern &) const
bool operator!=(const Iterator &) const
bool is_compressed() const
SymmetricTensor< rank_, dim, typename ProductType< Number, OtherNumber >::type > operator-(const SymmetricTensor< rank_, dim, Number > &left, const SymmetricTensor< rank_, dim, OtherNumber > &right)
std::size_t n_nonzero_elements() const
const Accessor & operator*() const
static::ExceptionBase & ExcInternalError()