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
dynamic_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) 2011 - 2026 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_dynamic_sparsity_pattern_h
14#define dealii_dynamic_sparsity_pattern_h
15
16
17#include <deal.II/base/config.h>
18
23
26
27#include <algorithm>
28#include <iostream>
29#include <vector>
30
32
33// Forward declaration
34#ifndef DOXYGEN
36#endif
37
48{
49 // forward declaration
50 class Iterator;
51
56
66 {
67 public:
72 const size_type row,
73 const unsigned int index_within_row);
74
79
85 Accessor();
86
91 row() const;
92
97 index() const;
98
103 column() const;
104
108 bool
109 operator==(const Accessor &) const;
110
118 bool
119 operator<(const Accessor &) const;
120
121 protected:
123 "The instance of this class was initialized"
124 " without DynamicSparsityPattern object, which"
125 " means that it is a dummy accessor that can"
126 " not do any operations.");
127
132
137
142 std::vector<size_type>::const_iterator current_entry;
143
150 std::vector<size_type>::const_iterator end_of_row;
151
155 void
156 advance();
157
158 // Grant access to iterator class.
159 friend class Iterator;
160 };
161
162
163
189 {
190 public:
197 const size_type row,
198 const unsigned int index_within_row);
199
205
211 Iterator() = default;
212
216 Iterator &
217 operator++();
218
223 operator++(int);
224
228 const Accessor &
229 operator*() const;
230
234 const Accessor *
235 operator->() const;
236
240 bool
241 operator==(const Iterator &) const;
242
246 bool
247 operator!=(const Iterator &) const;
248
256 bool
257 operator<(const Iterator &) const;
258
265 int
266 operator-(const Iterator &p) const;
267
268 private:
273 };
274} // namespace DynamicSparsityPatternIterators
275
276
321{
322public:
327
336
342
349
360
368 const size_type n,
369 const IndexSet &rowset = IndexSet());
370
376 DynamicSparsityPattern(const IndexSet &indexset);
377
382
390
397 void
398 reinit(const size_type m,
399 const size_type n,
400 const IndexSet &rowset = IndexSet());
401
407 void
408 compress();
409
414 bool
415 empty() const;
416
422 max_entries_per_row() const;
423
427 void
428 add(const size_type i, const size_type j);
429
436 template <typename ForwardIterator>
437 void
438 add_entries(const size_type row,
439 ForwardIterator begin,
440 ForwardIterator end,
441 const bool indices_are_unique_and_sorted = false);
442
443 virtual void
444 add_row_entries(const size_type &row,
445 const ArrayView<const size_type> &columns,
446 const bool indices_are_sorted = false) override;
447
449
453 bool
454 exists(const size_type i, const size_type j) const;
455
463 get_view(const IndexSet &rows) const;
464
472 void
473 symmetrize();
474
479 template <typename SparsityPatternTypeLeft, typename SparsityPatternTypeRight>
480 void
481 compute_mmult_pattern(const SparsityPatternTypeLeft &left,
482 const SparsityPatternTypeRight &right);
483
488 template <typename SparsityPatternTypeLeft, typename SparsityPatternTypeRight>
489 void
490 compute_Tmmult_pattern(const SparsityPatternTypeLeft &left,
491 const SparsityPatternTypeRight &right);
492
498 void
499 print(std::ostream &out) const;
500
514 void
515 print_gnuplot(std::ostream &out) const;
516
522 row_length(const size_type row) const;
523
527 void
528 clear_row(const size_type row);
529
535 column_number(const size_type row, const size_type index) const;
536
543 column_index(const size_type row, const size_type col) const;
544
564 begin() const;
565
570 end() const;
571
589 begin(const size_type r) const;
590
600 end(const size_type r) const;
601
612 bandwidth() const;
613
619 n_nonzero_elements() const;
620
626 const IndexSet &
627 row_index_set() const;
628
636 nonempty_cols() const;
637
645 nonempty_rows() const;
646
657 static bool
659
665 memory_consumption() const;
666
667private:
672
677
682 {
687 std::vector<size_type> indices;
688 };
689
696
703 struct Line
704 {
705 public:
710 std::vector<size_type> entries;
711
715 void
716 add(const size_type col_num);
717
733 template <typename ForwardIterator>
734 void
735 add_entries(ForwardIterator begin,
736 ForwardIterator end,
737 const bool indices_are_sorted,
739
744 memory_consumption() const;
745 };
746
750 std::vector<Line> lines;
751
752 // make the accessor class a friend
754};
755
757/*---------------------- Inline functions -----------------------------------*/
758
759
761{
762 inline Accessor::Accessor(const DynamicSparsityPattern *sparsity_pattern,
763 const size_type row,
764 const unsigned int index_within_row)
765 : sparsity_pattern(sparsity_pattern)
766 , current_row(row)
767 , current_entry(
768 ((sparsity_pattern->rowset.size() == 0) ?
769 sparsity_pattern->lines[current_row].entries.begin() :
770 sparsity_pattern
771 ->lines[sparsity_pattern->rowset.index_within_set(current_row)]
772 .entries.begin()) +
773 index_within_row)
774 , end_of_row(
775 (sparsity_pattern->rowset.size() == 0) ?
776 sparsity_pattern->lines[current_row].entries.end() :
777 sparsity_pattern
778 ->lines[sparsity_pattern->rowset.index_within_set(current_row)]
779 .entries.end())
780 {
784 ExcMessage("You can't create an iterator into a "
785 "DynamicSparsityPattern's row that is not "
786 "actually stored by that sparsity pattern "
787 "based on the IndexSet argument to it."));
789 index_within_row,
790 ((sparsity_pattern->rowset.size() == 0) ?
791 sparsity_pattern->lines[current_row].entries.size() :
794 .entries.size()));
795 }
796
797
798 inline Accessor::Accessor(const DynamicSparsityPattern *sparsity_pattern)
799 : sparsity_pattern(sparsity_pattern)
800 , current_row(numbers::invalid_size_type)
801 , current_entry()
802 , end_of_row()
803 {}
804
805
806
808 : sparsity_pattern(nullptr)
809 , current_row(numbers::invalid_size_type)
810 , current_entry()
811 , end_of_row()
812 {}
813
814
815 inline size_type
817 {
819 Assert(current_row < sparsity_pattern->n_rows(), ExcInternalError());
820
821 return current_row;
822 }
823
824
825 inline size_type
827 {
829 Assert(current_row < sparsity_pattern->n_rows(), ExcInternalError());
830
831 return *current_entry;
832 }
833
834
835 inline size_type
837 {
839 Assert(current_row < sparsity_pattern->n_rows(), ExcInternalError());
840
841 return (current_entry -
842 ((sparsity_pattern->rowset.size() == 0) ?
843 sparsity_pattern->lines[current_row].entries.begin() :
846 .entries.begin()));
847 }
848
849
850
851 inline bool
852 Accessor::operator==(const Accessor &other) const
853 {
855 Assert(other.sparsity_pattern != nullptr, DummyAccessor());
856 // compare the sparsity pattern the iterator points into, the
857 // current row, and the location within this row. ignore the
858 // latter if the row is past-the-end because in that case the
859 // current_entry field may not point to a deterministic location
860 return (sparsity_pattern == other.sparsity_pattern &&
861 current_row == other.current_row &&
863 (current_entry == other.current_entry)));
864 }
865
866
867
868 inline bool
869 Accessor::operator<(const Accessor &other) const
870 {
872 Assert(other.sparsity_pattern != nullptr, DummyAccessor());
874
875 // if *this is past-the-end, then it is less than no one
877 return (false);
878 // now *this should be an valid value
879 Assert(current_row < sparsity_pattern->n_rows(), ExcInternalError());
880
881 // if other is past-the-end
883 return (true);
884 // now other should be an valid value
886
887 // both iterators are not one-past-the-end
888 return ((current_row < other.current_row) ||
889 ((current_row == other.current_row) &&
890 (current_entry < other.current_entry)));
891 }
892
893
894 inline void
896 {
898 Assert(current_row < sparsity_pattern->n_rows(), ExcInternalError());
899
900 // move to the next element in this row
902
903 // if this moves us beyond the end of the row, go to the next row
904 // if possible, or set the iterator to an invalid state if not.
905 //
906 // going to the next row is a bit complicated because we may have
907 // to skip over empty rows, and because we also have to avoid rows
908 // that aren't listed in a possibly passed IndexSet argument of
909 // the sparsity pattern. consequently, rather than trying to
910 // duplicate code here, just call the begin() function of the
911 // sparsity pattern itself
913 {
915 *this = *sparsity_pattern->begin(current_row + 1);
916 else
917 *this = Accessor(sparsity_pattern); // invalid object
918 }
919 }
920
921
922
923 inline Iterator::Iterator(const DynamicSparsityPattern *sparsity_pattern,
924 const size_type row,
925 const unsigned int index_within_row)
926 : accessor(sparsity_pattern, row, index_within_row)
927 {}
928
929
930
931 inline Iterator::Iterator(const DynamicSparsityPattern *sparsity_pattern)
932 : accessor(sparsity_pattern)
933 {}
934
935
936
937 inline Iterator &
939 {
941 return *this;
942 }
943
944
945
946 inline Iterator
948 {
949 const Iterator iter = *this;
951 return iter;
952 }
953
954
955
956 inline const Accessor &
958 {
959 return accessor;
960 }
961
962
963
964 inline const Accessor *
966 {
967 return &accessor;
968 }
969
970
971 inline bool
972 Iterator::operator==(const Iterator &other) const
973 {
974 return (accessor == other.accessor);
975 }
976
977
978
979 inline bool
980 Iterator::operator!=(const Iterator &other) const
981 {
982 return !(*this == other);
983 }
984
985
986 inline bool
987 Iterator::operator<(const Iterator &other) const
988 {
989 return accessor < other.accessor;
990 }
991
992
993 inline int
994 Iterator::operator-(const Iterator &other) const
995 {
999
1000 return 0;
1001 }
1002} // namespace DynamicSparsityPatternIterators
1003
1004
1005inline void
1007{
1008 // first check the last element (or if line is still empty)
1009 if ((entries.empty()) || (entries.back() < j))
1010 {
1011 entries.push_back(j);
1012 return;
1013 }
1014
1015 // do a binary search to find the place where to insert:
1016 std::vector<size_type>::iterator it =
1017 Utilities::lower_bound(entries.begin(), entries.end(), j);
1018
1019 // If this entry is a duplicate, exit immediately
1020 if (*it == j)
1021 return;
1022
1023 // Insert at the right place in the vector. Vector grows automatically to
1024 // fit elements. Always doubles its size.
1025 entries.insert(it, j);
1026}
1027
1028
1029
1030inline void
1032{
1035
1036 if (rowset.size() > 0 && !rowset.is_element(i))
1037 return;
1038
1039 have_entries = true;
1040
1041 const size_type rowindex =
1042 rowset.size() == 0 ? i : rowset.index_within_set(i);
1043 lines[rowindex].add(j);
1044}
1045
1046
1047
1048template <typename ForwardIterator>
1049inline void
1051 ForwardIterator begin,
1052 ForwardIterator end,
1053 const bool indices_are_sorted)
1054{
1055 AssertIndexRange(row, rows);
1056
1057 if (rowset.size() > 0 && !rowset.is_element(row))
1058 return;
1059
1060 if (!have_entries && begin < end)
1061 have_entries = true;
1062
1063 const size_type rowindex =
1064 rowset.size() == 0 ? row : rowset.index_within_set(row);
1065 lines[rowindex].add_entries(begin,
1066 end,
1067 indices_are_sorted,
1068 scratch_data.get());
1069}
1070
1071
1072
1075{
1076 AssertIndexRange(row, n_rows());
1077
1078 if (!have_entries)
1079 return 0;
1080
1081 if (rowset.size() > 0 && !rowset.is_element(row))
1082 return 0;
1083
1084 const size_type rowindex =
1085 rowset.size() == 0 ? row : rowset.index_within_set(row);
1086 return lines[rowindex].entries.size();
1087}
1088
1089
1090
1093 const size_type index) const
1094{
1095 AssertIndexRange(row, n_rows());
1097
1098 const size_type local_row =
1099 rowset.size() != 0u ? rowset.index_within_set(row) : row;
1100 AssertIndexRange(index, lines[local_row].entries.size());
1101 return lines[local_row].entries[index];
1102}
1103
1104
1105
1108{
1109 if (n_rows() > 0)
1110 return begin(0);
1111 else
1112 return end();
1113}
1114
1115
1118{
1119 return {this};
1120}
1121
1122
1123
1126{
1128
1129 if (!have_entries)
1130 return {this};
1131
1132 if (rowset.size() > 0)
1133 {
1134 // We have an IndexSet that describes the locally owned set. For
1135 // performance reasons we need to make sure that we don't do a
1136 // linear search over 0..n_rows(). Instead, find the first entry
1137 // >= row r in the locally owned set (this is done in log
1138 // n_ranges time inside at()). From there, we move forward until
1139 // we find a non-empty row. By iterating over the IndexSet instead
1140 // of incrementing the row index, we potentially skip over entries
1141 // not in the rowset.
1143 if (it == rowset.end())
1144 return end(); // we don't own any row between r and the end
1145
1146 // Instead of using row_length(*it)==0 in the while loop below,
1147 // which involves an expensive index_within_set() call, we
1148 // look at the lines vector directly. This works, because we are
1149 // walking over this vector entry by entry anyways.
1150 size_type rowindex = rowset.index_within_set(*it);
1151
1152 while (it != rowset.end() && lines[rowindex].entries.empty())
1153 {
1154 ++it;
1155 ++rowindex;
1156 }
1157
1158 if (it == rowset.end())
1159 return end();
1160 else
1161 return {this, *it, 0};
1162 }
1163
1164 // Without an index set we have to do a linear search starting at
1165 // row r until we find a non-empty one. We will check the lines vector
1166 // directly instead of going through the slower row_length() function
1167 size_type row = r;
1168
1169 while (row < n_rows() && lines[row].entries.empty())
1170 {
1171 ++row;
1172 }
1173
1174 if (row == n_rows())
1175 return {this};
1176 else
1177 return {this, row, 0};
1178}
1179
1180
1181
1184{
1186
1187 const size_type row = r + 1;
1188 if (row == n_rows())
1189 return {this};
1190 else
1191 return begin(row);
1192}
1193
1194
1195
1196inline const IndexSet &
1198{
1199 return rowset;
1200}
1201
1202
1203
1204inline bool
1209
1210
1212
1213#endif
*  iterator end()
*  *  iterator begin()
std::vector< size_type >::const_iterator end_of_row
std::vector< size_type >::const_iterator current_entry
void add_entries(const size_type row, ForwardIterator begin, ForwardIterator end, const bool indices_are_unique_and_sorted=false)
DynamicSparsityPattern get_view(const IndexSet &rows) const
const IndexSet & row_index_set() const
void compute_mmult_pattern(const SparsityPatternTypeLeft &left, const SparsityPatternTypeRight &right)
size_type row_length(const size_type row) const
virtual void add_row_entries(const size_type &row, const ArrayView< const size_type > &columns, const bool indices_are_sorted=false) override
size_type column_index(const size_type row, const size_type col) const
DynamicSparsityPattern & operator=(const DynamicSparsityPattern &)
Threads::ThreadLocalStorage< ScratchData > scratch_data
size_type column_number(const size_type row, const size_type index) const
void print(std::ostream &out) const
void reinit(const size_type m, const size_type n, const IndexSet &rowset=IndexSet())
void clear_row(const size_type row)
void print_gnuplot(std::ostream &out) const
void compute_Tmmult_pattern(const SparsityPatternTypeLeft &left, const SparsityPatternTypeRight &right)
bool exists(const size_type i, const size_type j) const
void add(const size_type i, const size_type j)
ElementIterator at(const size_type global_index) const
Definition index_set.cc:861
size_type size() const
Definition index_set.h:1759
size_type index_within_set(const size_type global_index) const
Definition index_set.h:1977
bool is_element(const size_type index) const
Definition index_set.h:1877
ElementIterator end() const
Definition index_set.h:1705
size_type n_rows() const
virtual void add_entries(const ArrayView< const std::pair< size_type, size_type > > &entries)
size_type n_cols() const
A class that provides a separate storage location on each thread that accesses the object.
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_NOT_IMPLEMENTED()
#define Assert(cond, exc)
#define AssertIndexRange(index, range)
#define DeclExceptionMsg(Exception, defaulttext)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & DummyAccessor()
static ::ExceptionBase & ExcMessage(std::string arg1)
std::size_t size
Definition mpi.cc:733
Iterator lower_bound(Iterator first, Iterator last, const T &val)
Definition utilities.h:1003
constexpr types::global_dof_index invalid_size_type
Definition types.h:240
unsigned int global_dof_index
Definition types.h:92
void add_entries(ForwardIterator begin, ForwardIterator end, const bool indices_are_sorted, ScratchData &scratch_data)
void add(const size_type col_num)