Reference documentation for deal.II version 9.1.0-pre
dynamic_sparsity_pattern.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2011 - 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_dynamic_sparsity_pattern_h
17 #define dealii_dynamic_sparsity_pattern_h
18 
19 
20 #include <deal.II/base/config.h>
21 
22 #include <deal.II/base/index_set.h>
23 #include <deal.II/base/subscriptor.h>
24 #include <deal.II/base/utilities.h>
25 
26 #include <deal.II/lac/exceptions.h>
27 
28 #include <algorithm>
29 #include <iostream>
30 #include <vector>
31 
32 DEAL_II_NAMESPACE_OPEN
33 
35 
36 
46 {
47  // forward declaration
48  class Iterator;
49 
54 
66  class Accessor
67  {
68  public:
73  const size_type row,
74  const unsigned int index_within_row);
75 
79  Accessor(const DynamicSparsityPattern *sparsity_pattern);
80 
84  size_type
85  row() const;
86 
90  size_type
91  index() const;
92 
96  size_type
97  column() const;
98 
102  bool
103  operator==(const Accessor &) const;
104 
112  bool
113  operator<(const Accessor &) const;
114 
115  protected:
120 
125 
130  std::vector<size_type>::const_iterator current_entry;
131 
138  std::vector<size_type>::const_iterator end_of_row;
139 
143  void
144  advance();
145 
149  friend class Iterator;
150  };
151 
152 
153 
178  class Iterator
179  {
180  public:
187  const size_type row,
188  const unsigned int index_within_row);
189 
194  Iterator(const DynamicSparsityPattern *sp);
195 
199  Iterator &
200  operator++();
201 
205  Iterator
206  operator++(int);
207 
211  const Accessor &operator*() const;
212 
216  const Accessor *operator->() const;
217 
221  bool
222  operator==(const Iterator &) const;
223 
227  bool
228  operator!=(const Iterator &) const;
229 
237  bool
238  operator<(const Iterator &) const;
239 
246  int
247  operator-(const Iterator &p) const;
248 
249  private:
254  };
255 } // namespace DynamicSparsityPatternIterators
256 
257 
304 {
305 public:
310 
319 
325 
332 
343 
351  const size_type n,
352  const IndexSet &rowset = IndexSet());
353 
359  DynamicSparsityPattern(const IndexSet &indexset);
360 
365 
372  operator=(const DynamicSparsityPattern &);
373 
380  void
381  reinit(const size_type m,
382  const size_type n,
383  const IndexSet &rowset = IndexSet());
384 
390  void
391  compress();
392 
397  bool
398  empty() const;
399 
404  size_type
405  max_entries_per_row() const;
406 
410  void
411  add(const size_type i, const size_type j);
412 
417  template <typename ForwardIterator>
418  void
419  add_entries(const size_type row,
420  ForwardIterator begin,
421  ForwardIterator end,
422  const bool indices_are_unique_and_sorted = false);
423 
427  bool
428  exists(const size_type i, const size_type j) const;
429 
437  void
438  symmetrize();
439 
444  template <typename SparsityPatternTypeLeft, typename SparsityPatternTypeRight>
445  void
446  compute_mmult_pattern(const SparsityPatternTypeLeft & left,
447  const SparsityPatternTypeRight &right);
448 
454  void
455  print(std::ostream &out) const;
456 
470  void
471  print_gnuplot(std::ostream &out) const;
472 
476  size_type
477  n_rows() const;
478 
483  size_type
484  n_cols() const;
485 
490  size_type
491  row_length(const size_type row) const;
492 
497  size_type
498  column_number(const size_type row, const size_type index) const;
499 
503  // @{
504 
518  iterator
519  begin() const;
520 
524  iterator
525  end() const;
526 
543  iterator
544  begin(const size_type r) const;
545 
554  iterator
555  end(const size_type r) const;
556 
557  // @}
558 
564  size_type
565  bandwidth() const;
566 
571  size_type
572  n_nonzero_elements() const;
573 
579  const IndexSet &
580  row_index_set() const;
581 
592  static bool
593  stores_only_added_elements();
594 
599  size_type
600  memory_consumption() const;
601 
602 private:
607 
612 
617 
623 
624 
631  struct Line
632  {
633  public:
638  std::vector<size_type> entries;
639 
643  void
644  add(const size_type col_num);
645 
649  template <typename ForwardIterator>
650  void
651  add_entries(ForwardIterator begin,
652  ForwardIterator end,
653  const bool indices_are_sorted);
654 
658  size_type
659  memory_consumption() const;
660  };
661 
662 
666  std::vector<Line> lines;
667 
668  // make the accessor class a friend
670 };
671 
673 /*---------------------- Inline functions -----------------------------------*/
674 
675 
677 {
679  const size_type row,
680  const unsigned int index_within_row)
681  : sparsity_pattern(sparsity_pattern)
682  , current_row(row)
683  , current_entry(
684  ((sparsity_pattern->rowset.size() == 0) ?
685  sparsity_pattern->lines[current_row].entries.begin() :
686  sparsity_pattern
687  ->lines[sparsity_pattern->rowset.index_within_set(current_row)]
688  .entries.begin()) +
689  index_within_row)
690  , end_of_row(
691  (sparsity_pattern->rowset.size() == 0) ?
692  sparsity_pattern->lines[current_row].entries.end() :
693  sparsity_pattern
694  ->lines[sparsity_pattern->rowset.index_within_set(current_row)]
695  .entries.end())
696  {
697  AssertIndexRange(current_row, sparsity_pattern->n_rows());
698  Assert((sparsity_pattern->rowset.size() == 0) ||
699  sparsity_pattern->rowset.is_element(current_row),
700  ExcMessage("You can't create an iterator into a "
701  "DynamicSparsityPattern's row that is not "
702  "actually stored by that sparsity pattern "
703  "based on the IndexSet argument to it."));
705  index_within_row,
706  ((sparsity_pattern->rowset.size() == 0) ?
707  sparsity_pattern->lines[current_row].entries.size() :
708  sparsity_pattern
709  ->lines[sparsity_pattern->rowset.index_within_set(current_row)]
710  .entries.size()));
711  }
712 
713 
715  : sparsity_pattern(sparsity_pattern)
716  , current_row(numbers::invalid_size_type)
717  , current_entry()
718  , end_of_row()
719  {}
720 
721 
722 
723  inline size_type
725  {
726  Assert(current_row < sparsity_pattern->n_rows(), ExcInternalError());
727 
728  return current_row;
729  }
730 
731 
732  inline size_type
734  {
735  Assert(current_row < sparsity_pattern->n_rows(), ExcInternalError());
736 
737  return *current_entry;
738  }
739 
740 
741  inline size_type
743  {
744  Assert(current_row < sparsity_pattern->n_rows(), ExcInternalError());
745 
746  return (current_entry -
747  ((sparsity_pattern->rowset.size() == 0) ?
748  sparsity_pattern->lines[current_row].entries.begin() :
751  .entries.begin()));
752  }
753 
754 
755 
756  inline bool
757  Accessor::operator==(const Accessor &other) const
758  {
759  // compare the sparsity pattern the iterator points into, the
760  // current row, and the location within this row. ignore the
761  // latter if the row is past-the-end because in that case the
762  // current_entry field may not point to a deterministic location
763  return (sparsity_pattern == other.sparsity_pattern &&
764  current_row == other.current_row &&
766  (current_entry == other.current_entry)));
767  }
768 
769 
770 
771  inline bool
772  Accessor::operator<(const Accessor &other) const
773  {
775 
776  // if *this is past-the-end, then it is less than no one
778  return (false);
779  // now *this should be an valid value
780  Assert(current_row < sparsity_pattern->n_rows(), ExcInternalError());
781 
782  // if other is past-the-end
784  return (true);
785  // now other should be an valid value
787 
788  // both iterators are not one-past-the-end
789  return ((current_row < other.current_row) ||
790  ((current_row == other.current_row) &&
791  (current_entry < other.current_entry)));
792  }
793 
794 
795  inline void
797  {
798  Assert(current_row < sparsity_pattern->n_rows(), ExcInternalError());
799 
800  // move to the next element in this row
801  ++current_entry;
802 
803  // if this moves us beyond the end of the row, go to the next row
804  // if possible, or set the iterator to an invalid state if not.
805  //
806  // going to the next row is a bit complicated because we may have
807  // to skip over empty rows, and because we also have to avoid rows
808  // that aren't listed in a possibly passed IndexSet argument of
809  // the sparsity pattern. consequently, rather than trying to
810  // duplicate code here, just call the begin() function of the
811  // sparsity pattern itself
812  if (current_entry == end_of_row)
813  {
814  if (current_row + 1 < sparsity_pattern->n_rows())
815  *this = *sparsity_pattern->begin(current_row + 1);
816  else
817  *this = Accessor(sparsity_pattern); // invalid object
818  }
819  }
820 
821 
822 
824  const size_type row,
825  const unsigned int index_within_row)
826  : accessor(sparsity_pattern, row, index_within_row)
827  {}
828 
829 
830 
831  inline Iterator::Iterator(const DynamicSparsityPattern *sparsity_pattern)
832  : accessor(sparsity_pattern)
833  {}
834 
835 
836 
837  inline Iterator &
839  {
840  accessor.advance();
841  return *this;
842  }
843 
844 
845 
846  inline Iterator
848  {
849  const Iterator iter = *this;
850  accessor.advance();
851  return iter;
852  }
853 
854 
855 
856  inline const Accessor &Iterator::operator*() const
857  {
858  return accessor;
859  }
860 
861 
862 
863  inline const Accessor *Iterator::operator->() const
864  {
865  return &accessor;
866  }
867 
868 
869  inline bool
870  Iterator::operator==(const Iterator &other) const
871  {
872  return (accessor == other.accessor);
873  }
874 
875 
876 
877  inline bool
878  Iterator::operator!=(const Iterator &other) const
879  {
880  return !(*this == other);
881  }
882 
883 
884  inline bool
885  Iterator::operator<(const Iterator &other) const
886  {
887  return accessor < other.accessor;
888  }
889 
890 
891  inline int
892  Iterator::operator-(const Iterator &other) const
893  {
894  (void)other;
896  ExcInternalError());
897  Assert(false, ExcNotImplemented());
898 
899  return 0;
900  }
901 } // namespace DynamicSparsityPatternIterators
902 
903 
904 inline void
906 {
907  // first check the last element (or if line is still empty)
908  if ((entries.size() == 0) || (entries.back() < j))
909  {
910  entries.push_back(j);
911  return;
912  }
913 
914  // do a binary search to find the place where to insert:
915  std::vector<size_type>::iterator it =
916  Utilities::lower_bound(entries.begin(), entries.end(), j);
917 
918  // If this entry is a duplicate, exit immediately
919  if (*it == j)
920  return;
921 
922  // Insert at the right place in the vector. Vector grows automatically to
923  // fit elements. Always doubles its size.
924  entries.insert(it, j);
925 }
926 
927 
928 
931 {
932  return rows;
933 }
934 
935 
936 
939 {
940  return cols;
941 }
942 
943 
944 
945 inline void
947 {
948  Assert(i < rows, ExcIndexRangeType<size_type>(i, 0, rows));
949  Assert(j < cols, ExcIndexRangeType<size_type>(j, 0, cols));
950 
951  if (rowset.size() > 0 && !rowset.is_element(i))
952  return;
953 
954  have_entries = true;
955 
956  const size_type rowindex =
957  rowset.size() == 0 ? i : rowset.index_within_set(i);
958  lines[rowindex].add(j);
959 }
960 
961 
962 
963 template <typename ForwardIterator>
964 inline void
966  ForwardIterator begin,
967  ForwardIterator end,
968  const bool indices_are_sorted)
969 {
970  Assert(row < rows, ExcIndexRangeType<size_type>(row, 0, rows));
971 
972  if (rowset.size() > 0 && !rowset.is_element(row))
973  return;
974 
975  if (!have_entries && begin < end)
976  have_entries = true;
977 
978  const size_type rowindex =
979  rowset.size() == 0 ? row : rowset.index_within_set(row);
980  lines[rowindex].add_entries(begin, end, indices_are_sorted);
981 }
982 
983 
984 
987 {
988  Assert(row < n_rows(), ExcIndexRangeType<size_type>(row, 0, n_rows()));
989 
990  if (!have_entries)
991  return 0;
992 
993  if (rowset.size() > 0 && !rowset.is_element(row))
994  return 0;
995 
996  const size_type rowindex =
997  rowset.size() == 0 ? row : rowset.index_within_set(row);
998  return lines[rowindex].entries.size();
999 }
1000 
1001 
1002 
1005  const size_type index) const
1006 {
1007  Assert(row < n_rows(), ExcIndexRangeType<size_type>(row, 0, n_rows()));
1008  Assert(rowset.size() == 0 || rowset.is_element(row), ExcInternalError());
1009 
1010  const size_type local_row =
1011  rowset.size() ? rowset.index_within_set(row) : row;
1012  Assert(index < lines[local_row].entries.size(),
1013  ExcIndexRangeType<size_type>(index,
1014  0,
1015  lines[local_row].entries.size()));
1016  return lines[local_row].entries[index];
1017 }
1018 
1019 
1020 
1023 {
1024  return begin(0);
1025 }
1026 
1027 
1030 {
1031  return iterator(this);
1032 }
1033 
1034 
1035 
1038 {
1039  Assert(r < n_rows(), ExcIndexRangeType<size_type>(r, 0, n_rows()));
1040 
1041  if (!have_entries)
1042  return iterator(this);
1043 
1044  if (rowset.size() > 0)
1045  {
1046  // We have an IndexSet that describes the locally owned set. For
1047  // performance reasons we need to make sure that we don't do a
1048  // linear search over 0..n_rows(). Instead, find the first entry
1049  // >= row r in the locally owned set (this is done in log
1050  // n_ranges time inside at()). From there, we move forward until
1051  // we find a non-empty row. By iterating over the IndexSet instead
1052  // of incrementing the row index, we potentially skip over entries
1053  // not in the rowset.
1054  IndexSet::ElementIterator it = rowset.at(r);
1055  if (it == rowset.end())
1056  return end(); // we don't own any row between r and the end
1057 
1058  // Instead of using row_length(*it)==0 in the while loop below,
1059  // which involves an expensive index_within_set() call, we
1060  // look at the lines vector directly. This works, because we are
1061  // walking over this vector entry by entry anyways.
1062  size_type rowindex = rowset.index_within_set(*it);
1063 
1064  while (it != rowset.end() && lines[rowindex].entries.size() == 0)
1065  {
1066  ++it;
1067  ++rowindex;
1068  }
1069 
1070  if (it == rowset.end())
1071  return end();
1072  else
1073  return iterator(this, *it, 0);
1074  }
1075 
1076  // Without an index set we have to do a linear search starting at
1077  // row r until we find a non-empty one. We will check the lines vector
1078  // directly instead of going through the slower row_length() function
1079  size_type row = r;
1080 
1081  while (row < n_rows() && lines[row].entries.size() == 0)
1082  {
1083  ++row;
1084  }
1085 
1086  if (row == n_rows())
1087  return iterator(this);
1088  else
1089  return iterator(this, row, 0);
1090 }
1091 
1092 
1093 
1096 {
1097  Assert(r < n_rows(), ExcIndexRangeType<size_type>(r, 0, n_rows()));
1098 
1099  unsigned int row = r + 1;
1100  if (row == n_rows())
1101  return iterator(this);
1102  else
1103  return begin(row);
1104 }
1105 
1106 
1107 
1108 inline const IndexSet &
1110 {
1111  return rowset;
1112 }
1113 
1114 
1115 
1116 inline bool
1118 {
1119  return true;
1120 }
1121 
1122 
1123 DEAL_II_NAMESPACE_CLOSE
1124 
1125 #endif
size_type row_length(const size_type row) const
Iterator lower_bound(Iterator first, Iterator last, const T &val)
Definition: utilities.h:939
const types::global_dof_index invalid_size_type
Definition: types.h:182
void add_entries(const size_type row, ForwardIterator begin, ForwardIterator end, const bool indices_are_unique_and_sorted=false)
std::vector< size_type >::const_iterator end_of_row
Iterator(const DynamicSparsityPattern *sp, const size_type row, const unsigned int index_within_row)
Accessor(const DynamicSparsityPattern *sparsity_pattern, const size_type row, const unsigned int index_within_row)
void add(const size_type i, const size_type j)
#define AssertIndexRange(index, range)
Definition: exceptions.h:1407
size_type size() const
Definition: index_set.h:1611
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
static::ExceptionBase & ExcMessage(std::string arg1)
const IndexSet & row_index_set() const
#define Assert(cond, exc)
Definition: exceptions.h:1227
SymmetricTensor< 2, dim, Number > symmetrize(const Tensor< 2, dim, Number > &t)
size_type column_number(const size_type row, const size_type index) const
std::vector< size_type >::const_iterator current_entry
types::global_dof_index size_type
size_type index_within_set(const size_type global_index) const
Definition: index_set.h:1834
static::ExceptionBase & ExcNotImplemented()
bool is_element(const size_type index) const
Definition: index_set.h:1676
void add(const size_type col_num)
SymmetricTensor< rank_, dim, typename ProductType< Number, OtherNumber >::type > operator-(const SymmetricTensor< rank_, dim, Number > &left, const SymmetricTensor< rank_, dim, OtherNumber > &right)
static::ExceptionBase & ExcInternalError()