Reference documentation for deal.II version 9.0.0
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 at
12 // the top level of the deal.II distribution.
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 #include <deal.II/base/subscriptor.h>
22 #include <deal.II/base/utilities.h>
23 #include <deal.II/lac/exceptions.h>
24 #include <deal.II/base/index_set.h>
25 
26 #include <vector>
27 #include <algorithm>
28 #include <iostream>
29 
30 DEAL_II_NAMESPACE_OPEN
31 
33 
34 
44 {
45  // forward declaration
46  class Iterator;
47 
52 
64  class Accessor
65  {
66  public:
71  const size_type row,
72  const unsigned int index_within_row);
73 
78 
82  size_type row () const;
83 
87  size_type index () const;
88 
92  size_type column () const;
93 
97  bool operator == (const Accessor &) const;
98 
106  bool operator < (const Accessor &) const;
107 
108  protected:
113 
118 
123  std::vector<size_type>::const_iterator current_entry;
124 
131  std::vector<size_type>::const_iterator end_of_row;
132 
136  void advance ();
137 
141  friend class Iterator;
142  };
143 
144 
145 
170  class Iterator
171  {
172  public:
178  Iterator (const DynamicSparsityPattern *sp,
179  const size_type row,
180  const unsigned int index_within_row);
181 
186  Iterator (const DynamicSparsityPattern *sp);
187 
192 
196  Iterator operator++ (int);
197 
201  const Accessor &operator* () const;
202 
206  const Accessor *operator-> () const;
207 
211  bool operator == (const Iterator &) const;
212 
216  bool operator != (const Iterator &) const;
217 
225  bool operator < (const Iterator &) const;
226 
233  int operator - (const Iterator &p) const;
234 
235  private:
240  };
241 }
242 
243 
290 {
291 public:
296 
304  typedef
307 
312  typedef
315 
322 
333 
341  const size_type n,
342  const IndexSet &rowset = IndexSet());
343 
349  DynamicSparsityPattern (const IndexSet &indexset);
350 
355 
362 
369  void reinit (const size_type m,
370  const size_type n,
371  const IndexSet &rowset = IndexSet());
372 
378  void compress ();
379 
384  bool empty () const;
385 
391 
395  void add (const size_type i,
396  const size_type j);
397 
402  template <typename ForwardIterator>
403  void add_entries (const size_type row,
404  ForwardIterator begin,
405  ForwardIterator end,
406  const bool indices_are_unique_and_sorted = false);
407 
411  bool exists (const size_type i,
412  const size_type j) const;
413 
421  void symmetrize ();
422 
427  template <typename SparsityPatternTypeLeft, typename SparsityPatternTypeRight>
428  void compute_mmult_pattern(const SparsityPatternTypeLeft &left,
429  const SparsityPatternTypeRight &right);
430 
436  void print (std::ostream &out) const;
437 
451  void print_gnuplot (std::ostream &out) const;
452 
456  size_type n_rows () const;
457 
462  size_type n_cols () const;
463 
468  size_type row_length (const size_type row) const;
469 
474  size_type column_number (const size_type row,
475  const size_type index) const;
476 
480 // @{
481 
495  iterator begin () const;
496 
500  iterator end () const;
501 
518  iterator begin (const size_type r) const;
519 
528  iterator end (const size_type r) const;
529 
530 // @}
531 
537  size_type bandwidth () const;
538 
543  size_type n_nonzero_elements () const;
544 
550  const IndexSet &row_index_set () const;
551 
562  static
564 
569  size_type memory_consumption () const;
570 
571 private:
576 
581 
586 
592 
593 
600  struct Line
601  {
602  public:
607  std::vector<size_type> entries;
608 
612  void add (const size_type col_num);
613 
617  template <typename ForwardIterator>
618  void add_entries (ForwardIterator begin,
619  ForwardIterator end,
620  const bool indices_are_sorted);
621 
625  size_type memory_consumption () const;
626  };
627 
628 
632  std::vector<Line> lines;
633 
634  // make the accessor class a friend
636 };
637 
639 /*---------------------- Inline functions -----------------------------------*/
640 
641 
643 {
644  inline
645  Accessor::
646  Accessor (const DynamicSparsityPattern *sparsity_pattern,
647  const size_type row,
648  const unsigned int index_within_row)
649  :
650  sparsity_pattern(sparsity_pattern),
651  current_row (row),
652  current_entry(((sparsity_pattern->rowset.size()==0)
653  ?
654  sparsity_pattern->lines[current_row].entries.begin()
655  :
656  sparsity_pattern->lines[sparsity_pattern->rowset.index_within_set(current_row)].entries.begin())
657  +
658  index_within_row),
659  end_of_row((sparsity_pattern->rowset.size()==0)
660  ?
661  sparsity_pattern->lines[current_row].entries.end()
662  :
663  sparsity_pattern->lines[sparsity_pattern->rowset.index_within_set(current_row)].entries.end())
664  {
667  ||
669  ExcMessage ("You can't create an iterator into a "
670  "DynamicSparsityPattern's row that is not "
671  "actually stored by that sparsity pattern "
672  "based on the IndexSet argument to it."));
673  AssertIndexRange(index_within_row,
674  ((sparsity_pattern->rowset.size()==0)
675  ?
676  sparsity_pattern->lines[current_row].entries.size()
677  :
679  }
680 
681 
682  inline
683  Accessor::
684  Accessor (const DynamicSparsityPattern *sparsity_pattern)
685  :
686  sparsity_pattern(sparsity_pattern),
687  current_row(numbers::invalid_size_type),
688  current_entry(),
689  end_of_row()
690  {}
691 
692 
693 
694  inline
695  size_type
697  {
698  Assert (current_row < sparsity_pattern->n_rows(),
699  ExcInternalError());
700 
701  return current_row;
702  }
703 
704 
705  inline
706  size_type
708  {
709  Assert (current_row < sparsity_pattern->n_rows(),
710  ExcInternalError());
711 
712  return *current_entry;
713  }
714 
715 
716  inline
717  size_type
719  {
720  Assert (current_row < sparsity_pattern->n_rows(),
721  ExcInternalError());
722 
723  return (current_entry -
724  ((sparsity_pattern->rowset.size()==0)
725  ?
726  sparsity_pattern->lines[current_row].entries.begin()
727  :
729  }
730 
731 
732 
733 
734  inline
735  bool
736  Accessor::operator == (const Accessor &other) const
737  {
738  // compare the sparsity pattern the iterator points into, the
739  // current row, and the location within this row. ignore the
740  // latter if the row is past-the-end because in that case the
741  // current_entry field may not point to a deterministic location
742  return (sparsity_pattern == other.sparsity_pattern &&
743  current_row == other.current_row &&
745  || (current_entry == other.current_entry)));
746  }
747 
748 
749 
750  inline
751  bool
752  Accessor::operator < (const Accessor &other) const
753  {
755  ExcInternalError());
756 
757  // if *this is past-the-end, then it is less than no one
759  return (false);
760  // now *this should be an valid value
761  Assert (current_row < sparsity_pattern->n_rows(),
762  ExcInternalError());
763 
764  // if other is past-the-end
766  return (true);
767  // now other should be an valid value
769  ExcInternalError());
770 
771  // both iterators are not one-past-the-end
772  return ((current_row < other.current_row) ||
773  ((current_row == other.current_row) &&
774  (current_entry < other.current_entry)));
775  }
776 
777 
778  inline
779  void
781  {
782  Assert (current_row < sparsity_pattern->n_rows(),
783  ExcInternalError());
784 
785  // move to the next element in this row
786  ++current_entry;
787 
788  // if this moves us beyond the end of the row, go to the next row
789  // if possible, or set the iterator to an invalid state if not.
790  //
791  // going to the next row is a bit complicated because we may have
792  // to skip over empty rows, and because we also have to avoid rows
793  // that aren't listed in a possibly passed IndexSet argument of
794  // the sparsity pattern. consequently, rather than trying to
795  // duplicate code here, just call the begin() function of the
796  // sparsity pattern itself
797  if (current_entry == end_of_row)
798  {
800  *this = *sparsity_pattern->begin(current_row+1);
801  else
802  *this = Accessor(sparsity_pattern); // invalid object
803  }
804  }
805 
806 
807 
808  inline
809  Iterator::Iterator (const DynamicSparsityPattern *sparsity_pattern,
810  const size_type row,
811  const unsigned int index_within_row)
812  :
813  accessor(sparsity_pattern, row, index_within_row)
814  {}
815 
816 
817 
818  inline
819  Iterator::Iterator (const DynamicSparsityPattern *sparsity_pattern)
820  :
821  accessor(sparsity_pattern)
822  {}
823 
824 
825 
826  inline
827  Iterator &
829  {
830  accessor.advance ();
831  return *this;
832  }
833 
834 
835 
836  inline
837  Iterator
839  {
840  const Iterator iter = *this;
841  accessor.advance ();
842  return iter;
843  }
844 
845 
846 
847  inline
848  const Accessor &
850  {
851  return accessor;
852  }
853 
854 
855 
856  inline
857  const Accessor *
859  {
860  return &accessor;
861  }
862 
863 
864  inline
865  bool
866  Iterator::operator == (const Iterator &other) const
867  {
868  return (accessor == other.accessor);
869  }
870 
871 
872 
873  inline
874  bool
875  Iterator::operator != (const Iterator &other) const
876  {
877  return ! (*this == other);
878  }
879 
880 
881  inline
882  bool
883  Iterator::operator < (const Iterator &other) const
884  {
885  return accessor < other.accessor;
886  }
887 
888 
889  inline
890  int
891  Iterator::operator - (const Iterator &other) const
892  {
893  (void)other;
895  ExcInternalError());
896  Assert (false, ExcNotImplemented());
897 
898  return 0;
899  }
900 }
901 
902 
903 inline
904 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
916  it = Utilities::lower_bound(entries.begin(),
917  entries.end(),
918  j);
919 
920  // If this entry is a duplicate, exit immediately
921  if (*it == j)
922  return;
923 
924  // Insert at the right place in the vector. Vector grows automatically to
925  // fit elements. Always doubles its size.
926  entries.insert(it, j);
927 }
928 
929 
930 
931 inline
934 {
935  return rows;
936 }
937 
938 
939 
940 inline
943 {
944  return cols;
945 }
946 
947 
948 
949 inline
950 void
952  const size_type j)
953 {
954  Assert (i<rows, ExcIndexRangeType<size_type>(i, 0, rows));
955  Assert (j<cols, ExcIndexRangeType<size_type>(j, 0, cols));
956 
957  if (rowset.size() > 0 && !rowset.is_element(i))
958  return;
959 
960  have_entries = true;
961 
962  const size_type rowindex =
963  rowset.size()==0 ? i : rowset.index_within_set(i);
964  lines[rowindex].add (j);
965 }
966 
967 
968 
969 template <typename ForwardIterator>
970 inline
971 void
973  ForwardIterator begin,
974  ForwardIterator end,
975  const bool indices_are_sorted)
976 {
977  Assert (row < rows, ExcIndexRangeType<size_type> (row, 0, rows));
978 
979  if (rowset.size() > 0 && !rowset.is_element(row))
980  return;
981 
982  if (!have_entries && begin<end)
983  have_entries = true;
984 
985  const size_type rowindex =
986  rowset.size()==0 ? row : rowset.index_within_set(row);
987  lines[rowindex].add_entries (begin, end, indices_are_sorted);
988 }
989 
990 
991 
992 inline
995 {
996  Assert (row < n_rows(), ExcIndexRangeType<size_type> (row, 0, n_rows()));
997 
998  if (!have_entries)
999  return 0;
1000 
1001  if (rowset.size() > 0 && !rowset.is_element(row))
1002  return 0;
1003 
1004  const size_type rowindex =
1005  rowset.size()==0 ? row : rowset.index_within_set(row);
1006  return lines[rowindex].entries.size();
1007 }
1008 
1009 
1010 
1011 inline
1014  const size_type index) const
1015 {
1016  Assert (row < n_rows(), ExcIndexRangeType<size_type> (row, 0, n_rows()));
1017  Assert( rowset.size() == 0 || rowset.is_element(row), ExcInternalError());
1018 
1019  const size_type local_row = rowset.size() ? rowset.index_within_set(row) : row;
1020  Assert (index < lines[local_row].entries.size(),
1021  ExcIndexRangeType<size_type> (index, 0, lines[local_row].entries.size()));
1022  return lines[local_row].entries[index];
1023 }
1024 
1025 
1026 
1027 inline
1030 {
1031  return begin(0);
1032 }
1033 
1034 
1035 inline
1038 {
1039  return iterator(this);
1040 }
1041 
1042 
1043 
1044 inline
1047 {
1048  Assert (r<n_rows(), ExcIndexRangeType<size_type>(r,0,n_rows()));
1049 
1050  if (!have_entries)
1051  return iterator(this);
1052 
1053  if (rowset.size() > 0)
1054  {
1055  // We have an IndexSet that describes the locally owned set. For
1056  // performance reasons we need to make sure that we don't do a
1057  // linear search over 0..n_rows(). Instead, find the first entry
1058  // >= row r in the locally owned set (this is done in log
1059  // n_ranges time inside at()). From there, we move forward until
1060  // we find a non-empty row. By iterating over the IndexSet instead
1061  // of incrementing the row index, we potentially skip over entries
1062  // not in the rowset.
1064  if (it == rowset.end())
1065  return end(); // we don't own any row between r and the end
1066 
1067  // Instead of using row_length(*it)==0 in the while loop below,
1068  // which involves an expensive index_within_set() call, we
1069  // look at the lines vector directly. This works, because we are
1070  // walking over this vector entry by entry anyways.
1071  size_type rowindex = rowset.index_within_set(*it);
1072 
1073  while (it!=rowset.end()
1074  && lines[rowindex].entries.size()==0)
1075  {
1076  ++it;
1077  ++rowindex;
1078  }
1079 
1080  if (it == rowset.end())
1081  return end();
1082  else
1083  return iterator(this, *it, 0);
1084  }
1085 
1086  // Without an index set we have to do a linear search starting at
1087  // row r until we find a non-empty one. We will check the lines vector
1088  // directly instead of going through the slower row_length() function
1089  size_type row = r;
1090 
1091  while (row<n_rows() && lines[row].entries.size()==0)
1092  {
1093  ++row;
1094  }
1095 
1096  if (row == n_rows())
1097  return iterator(this);
1098  else
1099  return iterator(this, row, 0);
1100 }
1101 
1102 
1103 
1104 inline
1107 {
1108  Assert (r<n_rows(), ExcIndexRangeType<size_type>(r,0,n_rows()));
1109 
1110  unsigned int row = r+1;
1111  if (row == n_rows())
1112  return iterator(this);
1113  else
1114  return begin(row);
1115 }
1116 
1117 
1118 
1119 inline
1120 const IndexSet &
1122 {
1123  return rowset;
1124 }
1125 
1126 
1127 
1128 inline
1129 bool
1131 {
1132  return true;
1133 }
1134 
1135 
1136 DEAL_II_NAMESPACE_CLOSE
1137 
1138 #endif
Iterator lower_bound(Iterator first, Iterator last, const T &val)
Definition: utilities.h:891
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
DynamicSparsityPatternIterators::Iterator const_iterator
ElementIterator end() const
Definition: index_set.h:1516
DynamicSparsityPatternIterators::Iterator iterator
Iterator(const DynamicSparsityPattern *sp, const size_type row, const unsigned int index_within_row)
size_type column_number(const size_type row, const size_type index) const
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:1284
types::global_dof_index size_type
size_type size() const
Definition: index_set.h:1575
static ::ExceptionBase & ExcMessage(std::string arg1)
unsigned int global_dof_index
Definition: types.h:88
#define Assert(cond, exc)
Definition: exceptions.h:1142
void add_entries(ForwardIterator begin, ForwardIterator end, const bool indices_are_sorted)
void reinit(const size_type m, const size_type n, const IndexSet &rowset=IndexSet())
size_type index_within_set(const size_type global_index) const
Definition: index_set.h:1811
const IndexSet & row_index_set() const
void print_gnuplot(std::ostream &out) const
void compute_mmult_pattern(const SparsityPatternTypeLeft &left, const SparsityPatternTypeRight &right)
std::vector< size_type >::const_iterator current_entry
size_type row_length(const size_type row) const
DynamicSparsityPattern & operator=(const DynamicSparsityPattern &)
void print(std::ostream &out) const
static ::ExceptionBase & ExcNotImplemented()
bool is_element(const size_type index) const
Definition: index_set.h:1645
void add(const size_type col_num)
ElementIterator at(const size_type global_index) const
Definition: index_set.h:1465
bool exists(const size_type i, const size_type j) const
static ::ExceptionBase & ExcInternalError()