Reference documentation for deal.II version 9.3.3
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
sparsity_pattern.h
Go to the documentation of this file.
1// ---------------------------------------------------------------------
2//
3// Copyright (C) 2000 - 2021 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
26
27// boost::serialization::make_array used to be in array.hpp, but was
28// moved to a different file in BOOST 1.64
29#include <boost/version.hpp>
30#if BOOST_VERSION >= 106400
31# include <boost/serialization/array_wrapper.hpp>
32#else
33# include <boost/serialization/array.hpp>
34#endif
35#include <boost/serialization/split_member.hpp>
36
37#include <algorithm>
38#include <iostream>
39#include <memory>
40#include <vector>
41
43
44// Forward declarations
45#ifndef DOXYGEN
46class SparsityPattern;
50template <typename number>
51class FullMatrix;
52template <typename number>
53class SparseMatrix;
54template <typename number>
56template <typename number>
57class SparseILU;
58
60{
61 class Accessor;
62}
63#endif
64
69namespace internals
70{
71 namespace SparsityPatternTools
72 {
77
85
91 template <typename value>
93 get_column_index_from_iterator(const std::pair<size_type, value> &i);
94
100 template <typename value>
102 get_column_index_from_iterator(const std::pair<const size_type, value> &i);
103
104 } // namespace SparsityPatternTools
105} // namespace internals
106
107
112{
113 // forward declaration
114 class Iterator;
115
120
132 {
133 public:
138
143
148
155
161 row() const;
162
169 index() const;
170
182
188 column() const;
189
199 bool
201
205 bool
206 operator==(const Accessor &) const;
207
215 bool
216 operator<(const Accessor &) const;
217
218 protected:
220 "The instance of this class was initialized"
221 " without SparsityPattern object, which"
222 " means that it is a dummy accessor that can"
223 " not do any operations.");
224
229
237 std::size_t linear_index;
238
242 void
244
245 // Grant access to iterator class.
247
248 // Grant access to accessor class of ChunkSparsityPattern.
250 };
251
252
253
278 class Iterator : public LinearIndexIterator<Iterator, Accessor>
279 {
280 public:
285
290
296 Iterator(const SparsityPatternBase *sp, const std::size_t linear_index);
297
303 };
304} // namespace SparsityPatternIterators
305
306
307
325{
326public:
331
337
346
362
369 // @{
376
380 ~SparsityPatternBase() override = default;
381
390 void
391 reinit(const size_type m, const size_type n, const unsigned int max_per_row);
392
403 void
404 reinit(const size_type m,
405 const size_type n,
406 const std::vector<unsigned int> &row_lengths);
407
413 virtual void
415 const size_type n,
416 const ArrayView<const unsigned int> &row_lengths) = 0;
417
425 void
426 symmetrize();
427
434 void
435 add(const size_type i, const size_type j);
436
437 // @}
438
442 // @{
443
453 begin() const;
454
459 end() const;
460
473 begin(const size_type r) const;
474
484 end(const size_type r) const;
485
486
487 // @}
488
492 // @{
493
497 bool
499
504 bool
505 empty() const;
506
510 bool
511 exists(const size_type i, const size_type j) const;
512
519 max_entries_per_row() const;
520
531 bandwidth() const;
532
541 std::size_t
543
547 bool
549
555 n_rows() const;
556
562 n_cols() const;
563
567 unsigned int
568 row_length(const size_type row) const;
569
574 std::size_t
575 memory_consumption() const;
576
577 // @}
578
582 // @{
583
595 column_number(const size_type row, const unsigned int index) const;
596
605 row_position(const size_type i, const size_type j) const;
606
618 std::pair<size_type, size_type>
619 matrix_position(const std::size_t global_index) const;
620
621 // @}
622
626 // @{
627
633 void
634 print(std::ostream &out) const;
635
649 void
650 print_gnuplot(std::ostream &out) const;
651
659 void
660 print_svg(std::ostream &out) const;
661
667 template <class Archive>
668 void
669 save(Archive &ar, const unsigned int version) const;
670
676 template <class Archive>
677 void
678 load(Archive &ar, const unsigned int version);
679
680#ifdef DOXYGEN
686 template <class Archive>
687 void
688 serialize(Archive &archive, const unsigned int version);
689#else
690 // This macro defines the serialize() method that is compatible with
691 // the templated save() and load() method that have been implemented.
692 BOOST_SERIALIZATION_SPLIT_MEMBER()
693#endif
694
695 // @}
696
708 "The operation you attempted is only allowed after the SparsityPattern "
709 "has been set up and compress() was called.");
710
715 int,
716 int,
717 << "Upon entering a new entry to row " << arg1
718 << ": there was no free entry any more. " << std::endl
719 << "(Maximum number of entries for this row: " << arg2
720 << "; maybe the matrix is already compressed?)");
721
728 "The operation you attempted changes the structure of the SparsityPattern "
729 "and is not possible after compress() has been called.");
730
731 // @}
732
733
734protected:
743
748
753
759 std::size_t max_vec_len;
760
768 unsigned int max_row_length;
769
783 std::unique_ptr<std::size_t[]> rowstart;
784
807 std::unique_ptr<size_type[]> colnums;
808
813
814 // Make all sparse matrices friends of this class.
815 template <typename number>
816 friend class SparseMatrix;
817 template <typename number>
819 template <typename number>
820 friend class SparseILU;
821 template <typename number>
822 friend class ChunkSparseMatrix;
823
826
827 // Also give access to internal details to the iterator/accessor classes.
831};
832
869{
870public:
875
881
890
897
904 // @{
911
928
937 const size_type n,
938 const unsigned int max_per_row);
939
940
950 const size_type n,
951 const std::vector<unsigned int> &row_lengths);
952
961 SparsityPattern(const size_type m, const unsigned int max_per_row);
962
971 const std::vector<unsigned int> &row_lengths);
972
995 SparsityPattern(const SparsityPattern &original,
996 const unsigned int max_per_row,
997 const size_type extra_off_diagonals);
998
1002 ~SparsityPattern() override = default;
1003
1010 operator=(const SparsityPattern &);
1011
1017 virtual void
1018 reinit(const size_type m,
1019 const size_type n,
1020 const ArrayView<const unsigned int> &row_lengths) override;
1021
1034 void
1035 compress();
1036
1037
1114 template <typename ForwardIterator>
1115 void
1117 const size_type n_cols,
1118 const ForwardIterator begin,
1119 const ForwardIterator end);
1120
1125 void
1127
1132 void
1133 copy_from(const SparsityPattern &sp);
1134
1149 template <typename number>
1150 void
1152
1159 template <typename ForwardIterator>
1160 void
1161 add_entries(const size_type row,
1162 ForwardIterator begin,
1163 ForwardIterator end,
1164 const bool indices_are_sorted = false);
1165
1166 // @}
1167
1168
1172 // @{
1176 bool
1178
1191 bool
1193
1198 std::size_t
1199 memory_consumption() const;
1200
1201 // @}
1205 // @{
1228 size_type
1229 operator()(const size_type i, const size_type j) const;
1230
1231 // @}
1235 // @{
1236
1247 void
1248 block_write(std::ostream &out) const;
1249
1263 void
1264 block_read(std::istream &in);
1265
1270 template <class Archive>
1271 void
1272 save(Archive &ar, const unsigned int version) const;
1273
1278 template <class Archive>
1279 void
1280 load(Archive &ar, const unsigned int version);
1281
1282#ifdef DOXYGEN
1287 template <class Archive>
1288 void
1289 serialize(Archive &archive, const unsigned int version);
1290#else
1291 // This macro defines the serialize() method that is compatible with
1292 // the templated save() and load() method that have been implemented.
1293 BOOST_SERIALIZATION_SPLIT_MEMBER()
1294#endif
1295
1296 // @}
1297
1306 int,
1307 int,
1308 << "The iterators denote a range of " << arg1
1309 << " elements, but the given number of rows was " << arg2);
1314 int,
1315 << "The number of partitions you gave is " << arg1
1316 << ", but must be greater than zero.");
1318private:
1323
1324 // Make all sparse matrices friends of this class.
1325 template <typename number>
1326 friend class SparseMatrix;
1327 template <typename number>
1329 template <typename number>
1330 friend class SparseILU;
1331 template <typename number>
1332 friend class ChunkSparseMatrix;
1333
1336
1337 // Also give access to internal details to the iterator/accessor classes.
1341};
1342
1343
1345/*---------------------- Inline functions -----------------------------------*/
1346
1347#ifndef DOXYGEN
1348
1349
1351{
1352 inline Accessor::Accessor(const SparsityPatternBase *sparsity_pattern,
1353 const std::size_t i)
1354 : container(sparsity_pattern)
1355 , linear_index(i)
1356 {}
1357
1358
1359
1360 inline Accessor::Accessor(const SparsityPatternBase *sparsity_pattern)
1361 : container(sparsity_pattern)
1362 , linear_index(container->rowstart[container->rows])
1363 {}
1364
1365
1366
1367 inline Accessor::Accessor()
1368 : container(nullptr)
1369 , linear_index(numbers::invalid_size_type)
1370 {}
1371
1372
1373
1374 inline bool
1375 Accessor::is_valid_entry() const
1376 {
1377 Assert(container != nullptr, DummyAccessor());
1378 return (linear_index < container->rowstart[container->rows] &&
1379 container->colnums[linear_index] != SparsityPattern::invalid_entry);
1380 }
1381
1382
1383
1384 inline size_type
1385 Accessor::row() const
1386 {
1387 Assert(is_valid_entry() == true, ExcInvalidIterator());
1388
1389 const std::size_t *insert_point =
1390 std::upper_bound(container->rowstart.get(),
1391 container->rowstart.get() + container->rows + 1,
1392 linear_index);
1393 return insert_point - container->rowstart.get() - 1;
1394 }
1395
1396
1397
1398 inline size_type
1399 Accessor::column() const
1400 {
1401 Assert(is_valid_entry() == true, ExcInvalidIterator());
1402
1403 return (container->colnums[linear_index]);
1404 }
1405
1406
1407
1408 inline size_type
1409 Accessor::index() const
1410 {
1411 Assert(is_valid_entry() == true, ExcInvalidIterator());
1412
1413 return linear_index - container->rowstart[row()];
1414 }
1415
1416
1417
1418 inline size_type
1420 {
1421 Assert(is_valid_entry() == true, ExcInvalidIterator());
1422
1423 return linear_index;
1424 }
1425
1426
1427
1428 inline bool
1429 Accessor::operator==(const Accessor &other) const
1430 {
1431 return (container == other.container && linear_index == other.linear_index);
1432 }
1433
1434
1435
1436 inline bool
1437 Accessor::operator<(const Accessor &other) const
1438 {
1439 Assert(container != nullptr, DummyAccessor());
1440 Assert(other.container != nullptr, DummyAccessor());
1441 Assert(container == other.container, ExcInternalError());
1442
1443 return linear_index < other.linear_index;
1444 }
1445
1446
1447
1448 inline void
1450 {
1451 Assert(container != nullptr, DummyAccessor());
1452 Assert(linear_index < container->rowstart[container->rows],
1454 ++linear_index;
1455 }
1456
1457
1458 inline Iterator::Iterator(const SparsityPatternBase *sp,
1459 const std::size_t linear_index)
1460 : LinearIndexIterator<Iterator, Accessor>(Accessor(sp, linear_index))
1461 {}
1462
1463
1464 inline Iterator::Iterator(const Accessor &accessor)
1465 : LinearIndexIterator<Iterator, Accessor>(accessor)
1466 {}
1467
1468
1469} // namespace SparsityPatternIterators
1470
1471
1472
1475{
1476 if (n_rows() > 0)
1477 return {this, rowstart[0]};
1478 else
1479 return end();
1480}
1481
1482
1483
1486{
1487 if (n_rows() > 0)
1488 return {this, rowstart[rows]};
1489 else
1490 return {nullptr, 0};
1491}
1492
1493
1494
1497{
1499
1500 return {this, rowstart[r]};
1501}
1502
1503
1504
1507{
1509
1510 return {this, rowstart[r + 1]};
1511}
1512
1513
1514
1517{
1518 return rows;
1519}
1520
1521
1522
1525{
1526 return cols;
1527}
1528
1529
1530
1531inline bool
1533{
1534 return compressed;
1535}
1536
1537
1538
1539inline bool
1541{
1542 return (store_diagonal_first_in_row == false);
1543}
1544
1545
1546
1547inline unsigned int
1549{
1550 AssertIndexRange(row, rows);
1551 return rowstart[row + 1] - rowstart[row];
1552}
1553
1554
1555
1558 const unsigned int index) const
1559{
1560 AssertIndexRange(row, rows);
1561 AssertIndexRange(index, row_length(row));
1562
1563 return colnums[rowstart[row] + index];
1564}
1565
1566
1567
1568inline std::size_t
1570{
1572
1573 if ((rowstart != nullptr) && (colnums != nullptr))
1574 return rowstart[rows] - rowstart[0];
1575 else
1576 // the object is empty or has zero size
1577 return 0;
1578}
1579
1580
1581
1582template <class Archive>
1583inline void
1584SparsityPatternBase::save(Archive &ar, const unsigned int) const
1585{
1586 // forward to serialization function in the base class.
1587 ar &boost::serialization::base_object<const Subscriptor>(*this);
1588
1590
1591 ar &boost::serialization::make_array(rowstart.get(), max_dim + 1);
1592 ar &boost::serialization::make_array(colnums.get(), max_vec_len);
1593}
1594
1595
1596
1597template <class Archive>
1598inline void
1599SparsityPatternBase::load(Archive &ar, const unsigned int)
1600{
1601 // forward to serialization function in the base class.
1602 ar &boost::serialization::base_object<Subscriptor>(*this);
1603
1605
1606 rowstart = std::make_unique<std::size_t[]>(max_dim + 1);
1607 colnums = std::make_unique<size_type[]>(max_vec_len);
1608
1609 ar &boost::serialization::make_array(rowstart.get(), max_dim + 1);
1610 ar &boost::serialization::make_array(colnums.get(), max_vec_len);
1611}
1612
1613
1614
1615template <class Archive>
1616inline void
1617SparsityPattern::save(Archive &ar, const unsigned int) const
1618{
1619 // forward to serialization function in the base class.
1620 ar &boost::serialization::base_object<const SparsityPatternBase>(*this);
1622}
1623
1624
1625
1626template <class Archive>
1627inline void
1628SparsityPattern::load(Archive &ar, const unsigned int)
1629{
1630 // forward to serialization function in the base class.
1631 ar &boost::serialization::base_object<SparsityPatternBase>(*this);
1633}
1634
1635
1636
1637inline bool
1639{
1640 // it isn't quite necessary to compare *all* member variables. by only
1641 // comparing the essential ones, we can say that two sparsity patterns are
1642 // equal even if one is compressed and the other is not (in which case some
1643 // of the member variables are not yet set correctly)
1644 if (rows != sp2.rows || cols != sp2.cols || compressed != sp2.compressed)
1645 return false;
1646
1647 for (size_type i = 0; i < rows + 1; ++i)
1648 if (rowstart[i] != sp2.rowstart[i])
1649 return false;
1650
1651 for (size_type i = 0; i < rowstart[rows]; ++i)
1652 if (colnums[i] != sp2.colnums[i])
1653 return false;
1654
1655 return true;
1656}
1657
1658
1659
1660inline bool
1662{
1663 return (static_cast<const SparsityPatternBase &>(*this) == sp2) &&
1665}
1666
1667
1668
1669namespace internal
1670{
1671 namespace SparsityPatternTools
1672 {
1677
1678 inline size_type
1680 {
1681 return i;
1682 }
1683
1684
1685
1686 template <typename value>
1687 inline size_type
1688 get_column_index_from_iterator(const std::pair<size_type, value> &i)
1689 {
1690 return i.first;
1691 }
1692
1693
1694
1695 template <typename value>
1696 inline size_type
1697 get_column_index_from_iterator(const std::pair<const size_type, value> &i)
1698 {
1699 return i.first;
1700 }
1701 } // namespace SparsityPatternTools
1702} // namespace internal
1703
1704
1705
1706template <typename ForwardIterator>
1707void
1709 const size_type n_cols,
1710 const ForwardIterator begin,
1711 const ForwardIterator end)
1712{
1713 Assert(static_cast<size_type>(std::distance(begin, end)) == n_rows,
1714 ExcIteratorRange(std::distance(begin, end), n_rows));
1715
1716 // first determine row lengths for each row. if the matrix is quadratic,
1717 // then we might have to add an additional entry for the diagonal, if that
1718 // is not yet present. as we have to call compress anyway later on, don't
1719 // bother to check whether that diagonal entry is in a certain row or not
1720 const bool is_square = (n_rows == n_cols);
1721 std::vector<unsigned int> row_lengths;
1722 row_lengths.reserve(n_rows);
1723 for (ForwardIterator i = begin; i != end; ++i)
1724 row_lengths.push_back(std::distance(i->begin(), i->end()) +
1725 (is_square ? 1 : 0));
1726 reinit(n_rows, n_cols, row_lengths);
1727
1728 // now enter all the elements into the matrix. note that if the matrix is
1729 // quadratic, then we already have the diagonal element preallocated
1730 //
1731 // for use in the inner loop, we define an alias to the type of the inner
1732 // iterators
1733 size_type row = 0;
1734 using inner_iterator =
1735 typename std::iterator_traits<ForwardIterator>::value_type::const_iterator;
1736 for (ForwardIterator i = begin; i != end; ++i, ++row)
1737 {
1738 size_type * cols = &colnums[rowstart[row]] + (is_square ? 1 : 0);
1739 const inner_iterator end_of_row = i->end();
1740 for (inner_iterator j = i->begin(); j != end_of_row; ++j)
1741 {
1742 const size_type col =
1745
1746 if ((col != row) || !is_square)
1747 *cols++ = col;
1748 }
1749 }
1750
1751 // finally compress everything. this also sorts the entries within each row
1752 compress();
1753}
1754
1755
1756#endif // DOXYGEN
1757
1759
1760#endif
bool operator==(const AlignedVector< T > &lhs, const AlignedVector< T > &rhs)
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:402
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:403
void load(Archive &ar, const unsigned int version)
static ::ExceptionBase & ExcInvalidIterator()
void block_write(std::ostream &out) const
bool stores_only_added_elements() const
void add_entries(const size_type row, ForwardIterator begin, ForwardIterator end, const bool indices_are_sorted=false)
void serialize(Archive &archive, const unsigned int version)
static ::ExceptionBase & DummyAccessor()
SparsityPattern & operator=(const SparsityPattern &)
#define Assert(cond, exc)
Definition: exceptions.h:1465
static ::ExceptionBase & ExcIteratorPastEnd()
SparsityPatternBase::size_type size_type
#define DeclException2(Exception2, type1, type2, outsequence)
Definition: exceptions.h:538
~SparsityPattern() override=default
void copy_from(const size_type n_rows, const size_type n_cols, const ForwardIterator begin, const ForwardIterator end)
#define AssertIndexRange(index, range)
Definition: exceptions.h:1690
#define DeclExceptionMsg(Exception, defaulttext)
Definition: exceptions.h:493
static ::ExceptionBase & ExcInvalidNumberOfPartitions(int arg1)
static ::ExceptionBase & ExcInternalError()
#define DeclException1(Exception1, type1, outsequence)
Definition: exceptions.h:515
virtual void reinit(const size_type m, const size_type n, const ArrayView< const unsigned int > &row_lengths) override
size_type operator()(const size_type i, const size_type j) const
void save(Archive &ar, const unsigned int version) const
std::size_t memory_consumption() const
bool operator==(const SparsityPattern &) const
void block_read(std::istream &in)
static ::ExceptionBase & ExcIteratorRange(int arg1, int arg2)
void serialize(Archive &archive, const unsigned int version)
void save(Archive &ar, const unsigned int version) const
std::size_t n_nonzero_elements() const
bool operator==(const SparsityPatternBase &) const
unsigned int max_row_length
Iterator(const SparsityPatternBase *sp, const std::size_t linear_index)
void print_svg(std::ostream &out) const
void add(const size_type i, const size_type j)
SparsityPatternIterators::Iterator iterator
types::global_dof_index size_type
void reinit(const size_type m, const size_type n, const unsigned int max_per_row)
unsigned int row_length(const size_type row) const
static ::ExceptionBase & ExcNotCompressed()
size_type n_rows() const
std::unique_ptr< size_type[]> colnums
std::unique_ptr< std::size_t[]> rowstart
void print(std::ostream &out) const
types::global_dof_index size_type
size_type get_column_index_from_iterator(const size_type i)
types::global_dof_index size_type
bool operator==(const Accessor &) const
bool exists(const size_type i, const size_type j) const
iterator end() const
size_type column_number(const size_type row, const unsigned int index) const
iterator begin(const size_type r) const
virtual void reinit(const size_type m, const size_type n, const ArrayView< const unsigned int > &row_lengths)=0
void print_gnuplot(std::ostream &out) const
static ::ExceptionBase & ExcNotEnoughSpace(int arg1, int arg2)
static const size_type invalid_entry
size_type bandwidth() const
bool is_compressed() const
size_type max_entries_per_row() const
void load(Archive &ar, const unsigned int version)
std::pair< size_type, size_type > matrix_position(const std::size_t global_index) const
~SparsityPatternBase() override=default
const SparsityPatternBase * container
std::size_t memory_consumption() const
size_type get_column_index_from_iterator(const std::pair< const size_type, value > &i)
SparsityPatternIterators::Iterator const_iterator
iterator begin() const
Iterator(const Accessor &accessor)
bool operator<(const Accessor &) const
Accessor(const SparsityPatternBase *matrix)
Accessor(const SparsityPatternBase *matrix, const std::size_t linear_index)
size_type row_position(const size_type i, const size_type j) const
iterator end(const size_type r) const
static ::ExceptionBase & ExcMatrixIsCompressed()
size_type n_cols() const
@ matrix
Contents is actually a matrix.
VectorType::value_type * end(VectorType &V)
VectorType::value_type * begin(VectorType &V)
TrilinosWrappers::types::int_type global_index(const Epetra_BlockMap &map, const ::types::global_dof_index i)
const types::global_dof_index invalid_size_type
Definition: types.h:205
unsigned int global_dof_index
Definition: types.h:76
bool operator<(const SynchronousIterators< Iterators > &a, const SynchronousIterators< Iterators > &b)
void advance(std::tuple< I1, I2 > &t, const unsigned int n)