Reference documentation for deal.II version 8.5.1
dynamic_sparsity_pattern.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2011 - 2016 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 
428  void print (std::ostream &out) const;
429 
443  void print_gnuplot (std::ostream &out) const;
444 
448  size_type n_rows () const;
449 
454  size_type n_cols () const;
455 
460  size_type row_length (const size_type row) const;
461 
466  size_type column_number (const size_type row,
467  const size_type index) const;
468 
472 // @{
473 
487  iterator begin () const;
488 
492  iterator end () const;
493 
510  iterator begin (const size_type r) const;
511 
520  iterator end (const size_type r) const;
521 
522 // @}
523 
529  size_type bandwidth () const;
530 
535  size_type n_nonzero_elements () const;
536 
542  const IndexSet &row_index_set () const;
543 
554  static
556 
561  size_type memory_consumption () const;
562 
563 private:
568 
573 
578 
584 
585 
592  struct Line
593  {
594  public:
599  std::vector<size_type> entries;
600 
604  Line ();
605 
609  void add (const size_type col_num);
610 
614  template <typename ForwardIterator>
615  void add_entries (ForwardIterator begin,
616  ForwardIterator end,
617  const bool indices_are_sorted);
618 
622  size_type memory_consumption () const;
623  };
624 
625 
629  std::vector<Line> lines;
630 
631  // make the accessor class a friend
633 };
634 
636 /*---------------------- Inline functions -----------------------------------*/
637 
638 
640 {
641  inline
642  Accessor::
643  Accessor (const DynamicSparsityPattern *sparsity_pattern,
644  const size_type row,
645  const unsigned int index_within_row)
646  :
647  sparsity_pattern(sparsity_pattern),
648  current_row (row),
649  current_entry(((sparsity_pattern->rowset.size()==0)
650  ?
651  sparsity_pattern->lines[current_row].entries.begin()
652  :
653  sparsity_pattern->lines[sparsity_pattern->rowset.index_within_set(current_row)].entries.begin())
654  +
655  index_within_row),
656  end_of_row((sparsity_pattern->rowset.size()==0)
657  ?
658  sparsity_pattern->lines[current_row].entries.end()
659  :
660  sparsity_pattern->lines[sparsity_pattern->rowset.index_within_set(current_row)].entries.end())
661  {
664  ||
666  ExcMessage ("You can't create an iterator into a "
667  "DynamicSparsityPattern's row that is not "
668  "actually stored by that sparsity pattern "
669  "based on the IndexSet argument to it."));
670  AssertIndexRange(index_within_row,
671  ((sparsity_pattern->rowset.size()==0)
672  ?
673  sparsity_pattern->lines[current_row].entries.size()
674  :
676  }
677 
678 
679  inline
680  Accessor::
681  Accessor (const DynamicSparsityPattern *sparsity_pattern)
682  :
683  sparsity_pattern(sparsity_pattern),
684  current_row(numbers::invalid_size_type),
685  current_entry(),
686  end_of_row()
687  {}
688 
689 
690 
691  inline
692  size_type
694  {
695  Assert (current_row < sparsity_pattern->n_rows(),
696  ExcInternalError());
697 
698  return current_row;
699  }
700 
701 
702  inline
703  size_type
705  {
706  Assert (current_row < sparsity_pattern->n_rows(),
707  ExcInternalError());
708 
709  return *current_entry;
710  }
711 
712 
713  inline
714  size_type
716  {
717  Assert (current_row < sparsity_pattern->n_rows(),
718  ExcInternalError());
719 
720  return (current_entry -
721  ((sparsity_pattern->rowset.size()==0)
722  ?
723  sparsity_pattern->lines[current_row].entries.begin()
724  :
726  }
727 
728 
729 
730 
731  inline
732  bool
733  Accessor::operator == (const Accessor &other) const
734  {
735  // compare the sparsity pattern the iterator points into, the
736  // current row, and the location within this row. ignore the
737  // latter if the row is past-the-end because in that case the
738  // current_entry field may not point to a deterministic location
739  return (sparsity_pattern == other.sparsity_pattern &&
740  current_row == other.current_row &&
742  || (current_entry == other.current_entry)));
743  }
744 
745 
746 
747  inline
748  bool
749  Accessor::operator < (const Accessor &other) const
750  {
752  ExcInternalError());
753 
754  // if *this is past-the-end, then it is less than no one
756  return (false);
757  // now *this should be an valid value
758  Assert (current_row < sparsity_pattern->n_rows(),
759  ExcInternalError());
760 
761  // if other is past-the-end
763  return (true);
764  // now other should be an valid value
766  ExcInternalError());
767 
768  // both iterators are not one-past-the-end
769  return ((current_row < other.current_row) ||
770  ((current_row == other.current_row) &&
771  (current_entry < other.current_entry)));
772  }
773 
774 
775  inline
776  void
778  {
779  Assert (current_row < sparsity_pattern->n_rows(),
780  ExcInternalError());
781 
782  // move to the next element in this row
783  ++current_entry;
784 
785  // if this moves us beyond the end of the row, go to the next row
786  // if possible, or set the iterator to an invalid state if not.
787  //
788  // going to the next row is a bit complicated because we may have
789  // to skip over empty rows, and because we also have to avoid rows
790  // that aren't listed in a possibly passed IndexSet argument of
791  // the sparsity pattern. consequently, rather than trying to
792  // duplicate code here, just call the begin() function of the
793  // sparsity pattern itself
794  if (current_entry == end_of_row)
795  {
797  *this = *sparsity_pattern->begin(current_row+1);
798  else
799  *this = Accessor(sparsity_pattern); // invalid object
800  }
801  }
802 
803 
804 
805  inline
806  Iterator::Iterator (const DynamicSparsityPattern *sparsity_pattern,
807  const size_type row,
808  const unsigned int index_within_row)
809  :
810  accessor(sparsity_pattern, row, index_within_row)
811  {}
812 
813 
814 
815  inline
816  Iterator::Iterator (const DynamicSparsityPattern *sparsity_pattern)
817  :
818  accessor(sparsity_pattern)
819  {}
820 
821 
822 
823  inline
824  Iterator &
826  {
827  accessor.advance ();
828  return *this;
829  }
830 
831 
832 
833  inline
834  Iterator
836  {
837  const Iterator iter = *this;
838  accessor.advance ();
839  return iter;
840  }
841 
842 
843 
844  inline
845  const Accessor &
847  {
848  return accessor;
849  }
850 
851 
852 
853  inline
854  const Accessor *
856  {
857  return &accessor;
858  }
859 
860 
861  inline
862  bool
863  Iterator::operator == (const Iterator &other) const
864  {
865  return (accessor == other.accessor);
866  }
867 
868 
869 
870  inline
871  bool
872  Iterator::operator != (const Iterator &other) const
873  {
874  return ! (*this == other);
875  }
876 
877 
878  inline
879  bool
880  Iterator::operator < (const Iterator &other) const
881  {
882  return accessor < other.accessor;
883  }
884 
885 
886  inline
887  int
888  Iterator::operator - (const Iterator &other) const
889  {
890  (void)other;
892  ExcInternalError());
893  Assert (false, ExcNotImplemented());
894 
895  return 0;
896  }
897 }
898 
899 
900 inline
901 void
903 {
904  // first check the last element (or if line is still empty)
905  if ( (entries.size()==0) || ( entries.back() < j) )
906  {
907  entries.push_back(j);
908  return;
909  }
910 
911  // do a binary search to find the place where to insert:
912  std::vector<size_type>::iterator
913  it = Utilities::lower_bound(entries.begin(),
914  entries.end(),
915  j);
916 
917  // If this entry is a duplicate, exit immediately
918  if (*it == j)
919  return;
920 
921  // Insert at the right place in the vector. Vector grows automatically to
922  // fit elements. Always doubles its size.
923  entries.insert(it, j);
924 }
925 
926 
927 
928 inline
931 {
932  return rows;
933 }
934 
935 
936 
937 inline
940 {
941  return cols;
942 }
943 
944 
945 
946 inline
947 void
949  const size_type j)
950 {
951  Assert (i<rows, ExcIndexRangeType<size_type>(i, 0, rows));
952  Assert (j<cols, ExcIndexRangeType<size_type>(j, 0, cols));
953 
954  if (rowset.size() > 0 && !rowset.is_element(i))
955  return;
956 
957  have_entries = true;
958 
959  const size_type rowindex =
960  rowset.size()==0 ? i : rowset.index_within_set(i);
961  lines[rowindex].add (j);
962 }
963 
964 
965 
966 template <typename ForwardIterator>
967 inline
968 void
970  ForwardIterator begin,
971  ForwardIterator end,
972  const bool indices_are_sorted)
973 {
974  Assert (row < rows, ExcIndexRangeType<size_type> (row, 0, rows));
975 
976  if (rowset.size() > 0 && !rowset.is_element(row))
977  return;
978 
979  if (!have_entries && begin<end)
980  have_entries = true;
981 
982  const size_type rowindex =
983  rowset.size()==0 ? row : rowset.index_within_set(row);
984  lines[rowindex].add_entries (begin, end, indices_are_sorted);
985 }
986 
987 
988 
989 inline
991 {}
992 
993 
994 
995 inline
998 {
999  Assert (row < n_rows(), ExcIndexRangeType<size_type> (row, 0, n_rows()));
1000 
1001  if (!have_entries)
1002  return 0;
1003 
1004  if (rowset.size() > 0 && !rowset.is_element(row))
1005  return 0;
1006 
1007  const size_type rowindex =
1008  rowset.size()==0 ? row : rowset.index_within_set(row);
1009  return lines[rowindex].entries.size();
1010 }
1011 
1012 
1013 
1014 inline
1017  const size_type index) const
1018 {
1019  Assert (row < n_rows(), ExcIndexRangeType<size_type> (row, 0, n_rows()));
1020  Assert( rowset.size() == 0 || rowset.is_element(row), ExcInternalError());
1021 
1022  const size_type local_row = rowset.size() ? rowset.index_within_set(row) : row;
1023  Assert (index < lines[local_row].entries.size(),
1024  ExcIndexRangeType<size_type> (index, 0, lines[local_row].entries.size()));
1025  return lines[local_row].entries[index];
1026 }
1027 
1028 
1029 
1030 inline
1033 {
1034  return begin(0);
1035 }
1036 
1037 
1038 inline
1041 {
1042  return iterator(this);
1043 }
1044 
1045 
1046 
1047 inline
1050 {
1051  Assert (r<n_rows(), ExcIndexRangeType<size_type>(r,0,n_rows()));
1052 
1053  if (!have_entries)
1054  return iterator(this);
1055 
1056  if (rowset.size() > 0)
1057  {
1058  // We have an IndexSet that describes the locally owned set. For
1059  // performance reasons we need to make sure that we don't do a
1060  // linear search over 0..n_rows(). Instead, find the first entry
1061  // >= row r in the locally owned set (this is done in log
1062  // n_ranges time inside at()). From there, we move forward until
1063  // we find a non-empty row. By iterating over the IndexSet instead
1064  // of incrementing the row index, we potentially skip over entries
1065  // not in the rowset.
1067  if (it == rowset.end())
1068  return end(); // we don't own any row between r and the end
1069 
1070  // Instead of using row_length(*it)==0 in the while loop below,
1071  // which involves an expensive index_within_set() call, we
1072  // look at the lines vector directly. This works, because we are
1073  // walking over this vector entry by entry anyways.
1074  size_type rowindex = rowset.index_within_set(*it);
1075 
1076  while (it!=rowset.end()
1077  && lines[rowindex].entries.size()==0)
1078  {
1079  ++it;
1080  ++rowindex;
1081  }
1082 
1083  if (it == rowset.end())
1084  return end();
1085  else
1086  return iterator(this, *it, 0);
1087  }
1088 
1089  // Without an index set we have to do a linear search starting at
1090  // row r until we find a non-empty one. We will check the lines vector
1091  // directly instead of going through the slower row_length() function
1092  size_type row = r;
1093 
1094  while (row<n_rows() && lines[row].entries.size()==0)
1095  {
1096  ++row;
1097  }
1098 
1099  if (row == n_rows())
1100  return iterator(this);
1101  else
1102  return iterator(this, row, 0);
1103 }
1104 
1105 
1106 
1107 inline
1110 {
1111  Assert (r<n_rows(), ExcIndexRangeType<size_type>(r,0,n_rows()));
1112 
1113  unsigned int row = r+1;
1114  if (row == n_rows())
1115  return iterator(this);
1116  else
1117  return begin(row);
1118 }
1119 
1120 
1121 
1122 inline
1123 const IndexSet &
1125 {
1126  return rowset;
1127 }
1128 
1129 
1130 
1131 inline
1132 bool
1134 {
1135  return true;
1136 }
1137 
1138 
1139 DEAL_II_NAMESPACE_CLOSE
1140 
1141 #endif
Iterator lower_bound(Iterator first, Iterator last, const T &val)
Definition: utilities.h:618
const types::global_dof_index invalid_size_type
Definition: types.h:179
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:1305
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:1170
types::global_dof_index size_type
size_type size() const
Definition: index_set.h:1419
static ::ExceptionBase & ExcMessage(std::string arg1)
unsigned int global_dof_index
Definition: types.h:88
#define Assert(cond, exc)
Definition: exceptions.h:313
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:1653
const IndexSet & row_index_set() const
void print_gnuplot(std::ostream &out) const
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:1489
void add(const size_type col_num)
ElementIterator at(const size_type global_index) const
Definition: index_set.h:1256
bool exists(const size_type i, const size_type j) const
static ::ExceptionBase & ExcInternalError()