deal.II version GIT relicensing-6816-g8d70a4508a 2026-09-28 16:30:01+00:00
\(\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\}}\)
Loading...
Searching...
No Matches
sparsity_pattern.h
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2000 - 2025 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#ifndef dealii_sparsity_pattern_h
14#define dealii_sparsity_pattern_h
15
16
17#include <deal.II/base/config.h>
18
23
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 <memory>
39#include <vector>
40
42
43// Forward declarations
44#ifndef DOXYGEN
45class SparsityPattern;
48template <typename number>
49class FullMatrix;
50template <typename number>
51class SparseMatrix;
52template <typename number>
54template <typename number>
55class SparseILU;
56
58{
59 class Accessor;
60}
61#endif
62
68namespace internals
69{
70 namespace SparsityPatternTools
71 {
76
84
90 template <typename value>
92 get_column_index_from_iterator(const std::pair<size_type, value> &i);
93
99 template <typename value>
101 get_column_index_from_iterator(const std::pair<const size_type, value> &i);
102
103 } // namespace SparsityPatternTools
104} // namespace internals
105
106
111{
112 // forward declaration
113 class Iterator;
114
119
131 {
132 public:
137
141 Accessor(const SparsityPattern *matrix, const std::size_t linear_index);
142
146 Accessor(const SparsityPattern *matrix);
147
154
160 row() const;
161
168 index() const;
169
181
187 column() const;
188
198 bool
200
204 bool
205 operator==(const Accessor &) const;
206
214 bool
215 operator<(const Accessor &) const;
216
217 protected:
219 "The instance of this class was initialized"
220 " without SparsityPattern object, which"
221 " means that it is a dummy accessor that can"
222 " not do any operations.");
223
228
236 std::size_t linear_index;
237
241 void
243
244 // Grant access to iterator class.
246
247 // Grant access to accessor class of ChunkSparsityPattern.
249 };
250
251
252
277 class Iterator : public LinearIndexIterator<Iterator, Accessor>
278 {
279 public:
284
289
295 Iterator(const SparsityPattern *sp, const std::size_t linear_index);
296
302 };
303} // namespace SparsityPatternIterators
304
341{
342public:
347
363
369
378
394 begin() const;
395
400 end() const;
401
414 begin(const size_type r) const;
415
425 end(const size_type r) const;
426
447
464
473 const size_type n,
474 const unsigned int max_per_row);
475
476
486 const size_type n,
487 const std::vector<unsigned int> &row_lengths);
488
497 SparsityPattern(const size_type m, const unsigned int max_per_row);
498
507 const std::vector<unsigned int> &row_lengths);
508
531 SparsityPattern(const SparsityPattern &original,
532 const unsigned int max_per_row,
533 const size_type extra_off_diagonals);
534
541 operator=(const SparsityPattern &);
542
553 void
554 reinit(const size_type m,
555 const size_type n,
556 const ArrayView<const unsigned int> &row_lengths);
557
561 void
562 reinit(const size_type m,
563 const size_type n,
564 const std::vector<unsigned int> &row_lengths);
565
574 void
575 reinit(const size_type m, const size_type n, const unsigned int max_per_row);
576
589 void
590 compress();
591
592
669 template <typename ForwardIterator>
670 void
672 const size_type n_cols,
673 const ForwardIterator begin,
674 const ForwardIterator end);
675
680 void
682
687 void
688 copy_from(const SparsityPattern &sp);
689
704 template <typename number>
705 void
706 copy_from(const FullMatrix<number> &matrix);
707
714 void
715 add(const size_type i, const size_type j);
716
723 template <typename ForwardIterator>
724 void
725 add_entries(const size_type row,
726 ForwardIterator begin,
727 ForwardIterator end,
728 const bool indices_are_sorted = false);
729
730 virtual void
731 add_row_entries(const size_type &row,
732 const ArrayView<const size_type> &columns,
733 const bool indices_are_sorted = false) override;
734
736
744 void
745 symmetrize();
746
767 std::size_t
769
774 bool
775 empty() const;
776
787 bandwidth() const;
788
792 bool
794
801 max_entries_per_row() const;
802
806 bool
807 operator==(const SparsityPattern &) const;
808
821 bool
823
827 unsigned int
828 row_length(const size_type row) const;
829
834 std::size_t
835 memory_consumption() const;
836
870 operator()(const size_type i, const size_type j) const;
871
875 bool
876 exists(const size_type i, const size_type j) const;
877
889 column_number(const size_type row, const unsigned int index) const;
890
902 std::pair<size_type, size_type>
903 matrix_position(const std::size_t global_index) const;
904
913 row_position(const size_type i, const size_type j) const;
914
931 void
932 print(std::ostream &out) const;
933
947 void
948 print_gnuplot(std::ostream &out) const;
949
957 void
958 print_svg(std::ostream &out) const;
959
970 void
971 block_write(std::ostream &out) const;
972
986 void
987 block_read(std::istream &in);
988
993 template <class Archive>
994 void
995 save(Archive &ar, const unsigned int version) const;
996
1001 template <class Archive>
1002 void
1003 load(Archive &ar, const unsigned int version);
1004
1005#ifdef DOXYGEN
1010 template <class Archive>
1011 void
1012 serialize(Archive &archive, const unsigned int version);
1013#else
1014 // This macro defines the serialize() method that is compatible with
1015 // the templated save() and load() method that have been implemented.
1016 BOOST_SERIALIZATION_SPLIT_MEMBER()
1017#endif
1018
1032 int,
1033 int,
1034 << "The iterators denote a range of " << arg1
1035 << " elements, but the given number of rows was " << arg2);
1040 int,
1041 << "The number of partitions you gave is " << arg1
1042 << ", but must be greater than zero.");
1043
1048 int,
1049 int,
1050 << "Upon entering a new entry to row " << arg1
1051 << ": there was no free entry any more. " << std::endl
1052 << "(Maximum number of entries for this row: " << arg2
1053 << "; maybe the matrix is already compressed?)");
1054
1061 "The operation you attempted changes the structure of the SparsityPattern "
1062 "and is not possible after compress() has been called.");
1063
1070 "The operation you attempted is only allowed after the SparsityPattern "
1071 "has been set up and compress() was called.");
1072
1076private:
1081
1090
1096 std::size_t max_vec_len;
1097
1105 unsigned int max_row_length;
1106
1120 std::unique_ptr<std::size_t[]> rowstart;
1121
1144 std::unique_ptr<size_type[]> colnums;
1145
1150
1151 // Make all sparse matrices friends of this class.
1152 template <typename number>
1153 friend class SparseMatrix;
1154 template <typename number>
1156 template <typename number>
1157 friend class SparseILU;
1158 template <typename number>
1159 friend class ChunkSparseMatrix;
1160
1163
1164 // Also give access to internal details to the iterator/accessor classes.
1168};
1169
1170
1174/*---------------------- Inline functions -----------------------------------*/
1175
1176#ifndef DOXYGEN
1177
1178
1180{
1181 inline Accessor::Accessor(const SparsityPattern *sparsity_pattern,
1182 const std::size_t i)
1183 : container(sparsity_pattern)
1184 , linear_index(i)
1185 {}
1186
1187
1188
1189 inline Accessor::Accessor(const SparsityPattern *sparsity_pattern)
1190 : container(sparsity_pattern)
1191 , linear_index(container->rowstart[container->rows])
1192 {}
1193
1194
1195
1196 inline Accessor::Accessor()
1197 : container(nullptr)
1198 , linear_index(numbers::invalid_size_type)
1199 {}
1200
1201
1202
1203 inline bool
1204 Accessor::is_valid_entry() const
1205 {
1206 Assert(container != nullptr, DummyAccessor());
1207 return (linear_index < container->rowstart[container->rows] &&
1208 container->colnums[linear_index] != SparsityPattern::invalid_entry);
1209 }
1210
1211
1212
1213 inline size_type
1214 Accessor::row() const
1215 {
1216 Assert(is_valid_entry() == true, ExcInvalidIterator());
1217
1218 const std::size_t *insert_point =
1219 std::upper_bound(container->rowstart.get(),
1220 container->rowstart.get() + container->rows + 1,
1221 linear_index);
1222 return insert_point - container->rowstart.get() - 1;
1223 }
1224
1225
1226
1227 inline size_type
1228 Accessor::column() const
1229 {
1230 Assert(is_valid_entry() == true, ExcInvalidIterator());
1231
1232 return (container->colnums[linear_index]);
1233 }
1234
1235
1236
1237 inline size_type
1238 Accessor::index() const
1239 {
1240 Assert(is_valid_entry() == true, ExcInvalidIterator());
1241
1242 return linear_index - container->rowstart[row()];
1243 }
1244
1245
1246
1247 inline size_type
1248 Accessor::global_index() const
1249 {
1250 Assert(is_valid_entry() == true, ExcInvalidIterator());
1251
1252 return linear_index;
1253 }
1254
1255
1256
1257 inline bool
1258 Accessor::operator==(const Accessor &other) const
1259 {
1260 return (container == other.container && linear_index == other.linear_index);
1261 }
1262
1263
1264
1265 inline bool
1266 Accessor::operator<(const Accessor &other) const
1267 {
1268 Assert(container != nullptr, DummyAccessor());
1269 Assert(other.container != nullptr, DummyAccessor());
1270 Assert(container == other.container, ExcInternalError());
1271
1272 return linear_index < other.linear_index;
1273 }
1274
1275
1276
1277 inline void
1278 Accessor::advance()
1279 {
1280 Assert(container != nullptr, DummyAccessor());
1281 Assert(linear_index < container->rowstart[container->rows],
1283 ++linear_index;
1284 }
1285
1286
1287 inline Iterator::Iterator(const SparsityPattern *sp,
1288 const std::size_t linear_index)
1289 : LinearIndexIterator<Iterator, Accessor>(Accessor(sp, linear_index))
1290 {}
1291
1292
1293 inline Iterator::Iterator(const Accessor &accessor)
1294 : LinearIndexIterator<Iterator, Accessor>(accessor)
1295 {}
1296
1297
1298} // namespace SparsityPatternIterators
1299
1300
1301
1302inline std::size_t
1304{
1306
1307 if ((rowstart != nullptr) && (colnums != nullptr))
1308 return rowstart[rows] - rowstart[0];
1309 else
1310 // the object is empty or has zero size
1311 return 0;
1312}
1313
1314
1315
1316inline bool
1318{
1319 return compressed;
1320}
1321
1322
1323
1324inline bool
1326{
1327 return (store_diagonal_first_in_row == false);
1328}
1329
1330
1331
1332inline unsigned int
1333SparsityPattern::row_length(const size_type row) const
1334{
1335 AssertIndexRange(row, rows);
1336 return rowstart[row + 1] - rowstart[row];
1337}
1338
1339
1340
1342SparsityPattern::column_number(const size_type row,
1343 const unsigned int index) const
1344{
1345 AssertIndexRange(row, rows);
1346 AssertIndexRange(index, row_length(row));
1347
1348 return colnums[rowstart[row] + index];
1349}
1350
1351
1352
1355{
1356 if (n_rows() > 0)
1357 return {this, rowstart[0]};
1358 else
1359 return end();
1360}
1361
1362
1363
1366{
1367 if (n_rows() > 0)
1368 return {this, rowstart[rows]};
1369 else
1370 return {nullptr, 0};
1371}
1372
1373
1374
1376SparsityPattern::begin(const size_type r) const
1377{
1379
1380 return {this, rowstart[r]};
1381}
1382
1383
1384
1386SparsityPattern::end(const size_type r) const
1387{
1389
1390 return {this, rowstart[r + 1]};
1391}
1392
1393
1394
1395namespace internal
1396{
1397 namespace SparsityPatternTools
1398 {
1403
1404 inline size_type
1405 get_column_index_from_iterator(const size_type i)
1406 {
1407 return i;
1408 }
1409
1410
1411
1412 template <typename value>
1413 inline size_type
1414 get_column_index_from_iterator(const std::pair<size_type, value> &i)
1415 {
1416 return i.first;
1417 }
1418
1419
1420
1421 template <typename value>
1422 inline size_type
1423 get_column_index_from_iterator(const std::pair<const size_type, value> &i)
1424 {
1425 return i.first;
1426 }
1427 } // namespace SparsityPatternTools
1428} // namespace internal
1429
1430
1431
1432template <typename ForwardIterator>
1433void
1434SparsityPattern::copy_from(const size_type n_rows,
1435 const size_type n_cols,
1436 const ForwardIterator begin,
1437 const ForwardIterator end)
1438{
1439 Assert(static_cast<size_type>(std::distance(begin, end)) == n_rows,
1440 ExcIteratorRange(std::distance(begin, end), n_rows));
1441
1442 // first determine row lengths for each row. if the matrix is quadratic,
1443 // then we might have to add an additional entry for the diagonal, if that
1444 // is not yet present. as we have to call compress anyway later on, don't
1445 // bother to check whether that diagonal entry is in a certain row or not
1446 const bool is_square = (n_rows == n_cols);
1447 std::vector<unsigned int> row_lengths;
1448 row_lengths.reserve(n_rows);
1449 for (ForwardIterator i = begin; i != end; ++i)
1450 row_lengths.push_back(std::distance(i->begin(), i->end()) +
1451 (is_square ? 1 : 0));
1452 reinit(n_rows, n_cols, row_lengths);
1453
1454 // now enter all the elements into the matrix. note that if the matrix is
1455 // quadratic, then we already have the diagonal element preallocated
1456 //
1457 // for use in the inner loop, we define an alias to the type of the inner
1458 // iterators
1459 size_type row = 0;
1460 using inner_iterator =
1461 typename std::iterator_traits<ForwardIterator>::value_type::const_iterator;
1462 for (ForwardIterator i = begin; i != end; ++i, ++row)
1463 {
1464 size_type *cols = &colnums[rowstart[row]] + (is_square ? 1 : 0);
1465 const inner_iterator end_of_row = i->end();
1466 for (inner_iterator j = i->begin(); j != end_of_row; ++j)
1467 {
1468 const size_type col =
1469 internal::SparsityPatternTools::get_column_index_from_iterator(*j);
1471
1472 if ((col != row) || !is_square)
1473 *cols++ = col;
1474 }
1475 }
1476
1477 // finally compress everything. this also sorts the entries within each row
1478 compress();
1479}
1480
1481
1482
1483template <class Archive>
1484inline void
1485SparsityPattern::save(Archive &ar, const unsigned int) const
1486{
1487 // forward to serialization function in the base class.
1488 ar &boost::serialization::base_object<const EnableObserverPointer>(*this);
1489
1491
1492 if (max_dim != 0)
1493 ar &boost::serialization::make_array(rowstart.get(), max_dim + 1);
1494 else
1495 Assert(rowstart.get() == nullptr, ExcInternalError());
1496
1497 if (max_vec_len != 0)
1498 ar &boost::serialization::make_array(colnums.get(), max_vec_len);
1499 else
1500 Assert(colnums.get() == nullptr, ExcInternalError());
1502}
1503
1504
1505
1506template <class Archive>
1507inline void
1508SparsityPattern::load(Archive &ar, const unsigned int)
1509{
1510 // forward to serialization function in the base class.
1511 ar &boost::serialization::base_object<EnableObserverPointer>(*this);
1512
1514
1515 if (max_dim != 0)
1516 {
1517 rowstart = std::make_unique<std::size_t[]>(max_dim + 1);
1518 ar &boost::serialization::make_array(rowstart.get(), max_dim + 1);
1519 }
1520 else
1521 rowstart.reset();
1522
1523 if (max_vec_len != 0)
1524 {
1525 colnums = std::make_unique<size_type[]>(max_vec_len);
1526 ar &boost::serialization::make_array(colnums.get(), max_vec_len);
1527 }
1528 else
1529 colnums.reset();
1531}
1532
1533
1534#endif // DOXYGEN
1535
1537
1538#endif
*  iterator end()
*  *  iterator begin()
size_type n_rows() const
virtual void add_entries(const ArrayView< const std::pair< size_type, size_type > > &entries)
size_type n_cols() const
friend class ChunkSparsityPatternIterators::Accessor
bool operator==(const Accessor &) const
Accessor(const SparsityPattern *matrix)
Accessor(const SparsityPattern *matrix, const std::size_t linear_index)
bool operator<(const Accessor &) const
Iterator(const SparsityPattern *sp, const std::size_t linear_index)
Iterator(const Accessor &accessor)
void load(Archive &ar, const unsigned int version)
std::pair< size_type, size_type > matrix_position(const std::size_t global_index) const
iterator begin(const size_type r) const
void block_write(std::ostream &out) const
void reinit(const size_type m, const size_type n, const ArrayView< const unsigned int > &row_lengths)
void print_svg(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)
size_type bandwidth() const
void print_gnuplot(std::ostream &out) const
virtual void add_row_entries(const size_type &row, const ArrayView< const size_type > &columns, const bool indices_are_sorted=false) override
bool is_compressed() const
SparsityPattern & operator=(const SparsityPattern &)
std::size_t n_nonzero_elements() const
bool exists(const size_type i, const size_type j) const
iterator begin() const
std::unique_ptr< size_type[]> colnums
std::size_t max_vec_len
size_type column_number(const size_type row, const unsigned int index) const
void copy_from(const size_type n_rows, const size_type n_cols, const ForwardIterator begin, const ForwardIterator end)
static constexpr size_type invalid_entry
size_type row_position(const size_type i, const size_type j) const
std::unique_ptr< std::size_t[]> rowstart
void print(std::ostream &out) const
iterator end(const size_type r) const
void add(const size_type i, const size_type j)
size_type max_entries_per_row() const
unsigned int max_row_length
iterator end() const
size_type operator()(const size_type i, const size_type j) const
void save(Archive &ar, const unsigned int version) const
types::global_dof_index size_type
unsigned int row_length(const size_type row) const
std::size_t memory_consumption() const
bool operator==(const SparsityPattern &) const
void block_read(std::istream &in)
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
static ::ExceptionBase & ExcInvalidIterator()
static ::ExceptionBase & DummyAccessor()
#define Assert(cond, exc)
static ::ExceptionBase & ExcNotEnoughSpace(int arg1, int arg2)
static ::ExceptionBase & ExcIteratorPastEnd()
#define DeclException2(Exception2, type1, type2, outsequence)
#define AssertIndexRange(index, range)
#define DeclExceptionMsg(Exception, defaulttext)
static ::ExceptionBase & ExcMatrixIsCompressed()
static ::ExceptionBase & ExcInvalidNumberOfPartitions(int arg1)
static ::ExceptionBase & ExcInternalError()
#define DeclException1(Exception1, type1, outsequence)
static ::ExceptionBase & ExcNotCompressed()
static ::ExceptionBase & ExcIteratorRange(int arg1, int arg2)
types::global_dof_index size_type
size_type get_column_index_from_iterator(const size_type i)
constexpr types::global_dof_index invalid_size_type
Definition types.h:240
unsigned int global_dof_index
Definition types.h:92