Reference documentation for deal.II version 9.0.0
dynamic_sparsity_pattern.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2008 - 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 #include <deal.II/lac/dynamic_sparsity_pattern.h>
17 #include <deal.II/lac/sparsity_pattern.h>
18 #include <deal.II/base/memory_consumption.h>
19 
20 #include <algorithm>
21 #include <cmath>
22 #include <numeric>
23 #include <functional>
24 
25 DEAL_II_NAMESPACE_OPEN
26 
27 
28 
29 template <typename ForwardIterator>
30 void
32  ForwardIterator end,
33  const bool indices_are_sorted)
34 {
35  const int n_elements = end - begin;
36  if (n_elements <= 0)
37  return;
38 
39  const size_type stop_size = entries.size() + n_elements;
40 
41  if (indices_are_sorted == true && n_elements > 3)
42  {
43  // in debug mode, check whether the
44  // indices really are sorted.
45 #ifdef DEBUG
46  {
47  ForwardIterator test = begin, test1 = begin;
48  ++test1;
49  for ( ; test1 != end; ++test, ++test1)
50  Assert (*test1 > *test, ExcInternalError());
51  }
52 #endif
53 
54  if (entries.size() == 0 || entries.back() < *begin)
55  {
56  entries.insert(entries.end(), begin, end);
57  return;
58  }
59 
60  // find a possible insertion point for
61  // the first entry. check whether the
62  // first entry is a duplicate before
63  // actually doing something.
64  ForwardIterator my_it = begin;
65  size_type col = *my_it;
66  std::vector<size_type>::iterator it =
67  Utilities::lower_bound(entries.begin(), entries.end(), col);
68  while (*it == col)
69  {
70  ++my_it;
71  if (my_it == end)
72  break;
73  col = *my_it;
74  // check the very next entry in the
75  // current array
76  ++it;
77  if (it == entries.end())
78  break;
79  if (*it > col)
80  break;
81  if (*it == col)
82  continue;
83  // ok, it wasn't the very next one, do a
84  // binary search to find the insert point
85  it = Utilities::lower_bound(it, entries.end(), col);
86  if (it == entries.end())
87  break;
88  }
89  // all input entries were duplicates.
90  if (my_it == end)
91  return;
92 
93  // resize vector by just inserting the
94  // list
95  const size_type pos1 = it - entries.begin();
96  Assert (pos1 <= entries.size(), ExcInternalError());
97  entries.insert (it, my_it, end);
98  it = entries.begin() + pos1;
99  Assert (entries.size() >= (size_type)(it-entries.begin()), ExcInternalError());
100 
101  // now merge the two lists.
102  std::vector<size_type>::iterator it2 = it + (end-my_it);
103 
104  // as long as there are indices both in
105  // the end of the entries list and in the
106  // input list
107  while (my_it != end && it2 != entries.end())
108  {
109  if (*my_it < *it2)
110  *it++ = *my_it++;
111  else if (*my_it == *it2)
112  {
113  *it++ = *it2++;
114  ++my_it;
115  }
116  else
117  *it++ = *it2++;
118  }
119  // in case there are indices left in the
120  // input list
121  while (my_it != end)
122  *it++ = *my_it++;
123 
124  // in case there are indices left in the
125  // end of entries
126  while (it2 != entries.end())
127  *it++ = *it2++;
128 
129  // resize and return
130  const size_type new_size = it - entries.begin();
131  Assert (new_size <= stop_size, ExcInternalError());
132  entries.resize (new_size);
133  return;
134  }
135 
136  // unsorted case or case with too few
137  // elements
138  ForwardIterator my_it = begin;
139 
140  // If necessary, increase the size of the
141  // array.
142  if (stop_size > entries.capacity())
143  entries.reserve (stop_size);
144 
145  size_type col = *my_it;
146  std::vector<size_type>::iterator it, it2;
147  // insert the first element as for one
148  // entry only first check the last
149  // element (or if line is still empty)
150  if ( (entries.size()==0) || ( entries.back() < col) )
151  {
152  entries.push_back(col);
153  it = entries.end()-1;
154  }
155  else
156  {
157  // do a binary search to find the place
158  // where to insert:
159  it2 = Utilities::lower_bound(entries.begin(), entries.end(), col);
160 
161  // If this entry is a duplicate, continue
162  // immediately Insert at the right place
163  // in the vector. Vector grows
164  // automatically to fit elements. Always
165  // doubles its size.
166  if (*it2 != col)
167  it = entries.insert(it2, col);
168  else
169  it = it2;
170  }
171 
172  ++my_it;
173  // Now try to be smart and insert with
174  // bias in the direction we are
175  // walking. This has the advantage that
176  // for sorted lists, we always search in
177  // the right direction, what should
178  // decrease the work needed in here.
179  for ( ; my_it != end; ++my_it)
180  {
181  col = *my_it;
182  // need a special insertion command when
183  // we're at the end of the list
184  if (col > entries.back())
185  {
186  entries.push_back(col);
187  it = entries.end()-1;
188  }
189  // search to the right (preferred search
190  // direction)
191  else if (col > *it)
192  {
193  it2 = Utilities::lower_bound(it++, entries.end(), col);
194  if (*it2 != col)
195  it = entries.insert(it2, col);
196  }
197  // search to the left
198  else if (col < *it)
199  {
200  it2 = Utilities::lower_bound(entries.begin(), it, col);
201  if (*it2 != col)
202  it = entries.insert(it2, col);
203  }
204  // if we're neither larger nor smaller,
205  // then this was a duplicate and we can
206  // just continue.
207  }
208 }
209 
210 
213 {
214  return entries.capacity()*sizeof(size_type)+sizeof(Line);
215 }
216 
217 
219  :
220  have_entries (false),
221  rows (0),
222  cols (0),
223  rowset (0)
224 {}
225 
226 
227 
230  :
231  Subscriptor(),
232  have_entries (false),
233  rows (0),
234  cols (0),
235  rowset (0)
236 {
237  (void)s;
238  Assert (s.rows==0 && s.cols==0,
239  ExcMessage("This constructor can only be called if the provided argument "
240  "is the sparsity pattern for an empty matrix. This constructor can "
241  "not be used to copy-construct a non-empty sparsity pattern."));
242 }
243 
244 
245 
247  const size_type n,
248  const IndexSet &rowset_
249  )
250  :
251  have_entries (false),
252  rows (0),
253  cols (0),
254  rowset (0)
255 {
256  reinit (m,n, rowset_);
257 }
258 
259 
261  :
262  have_entries (false),
263  rows(0),
264  cols(0),
265  rowset(0)
266 {
267  reinit (rowset_.size(), rowset_.size(), rowset_);
268 }
269 
270 
272  :
273  have_entries (false),
274  rows(0),
275  cols(0),
276  rowset(0)
277 {
278  reinit (n,n);
279 }
280 
281 
282 
285 {
286  (void)s;
287  Assert (s.rows==0 && s.cols==0,
288  ExcMessage("This operator can only be called if the provided argument "
289  "is the sparsity pattern for an empty matrix. This operator can "
290  "not be used to copy a non-empty sparsity pattern."));
291 
292  Assert (rows==0 && cols==0,
293  ExcMessage("This operator can only be called if the current object is"
294  "empty."));
295 
296  return *this;
297 }
298 
299 
300 
301 void
303  const size_type n,
304  const IndexSet &rowset_)
305 {
306  have_entries = false;
307  rows = m;
308  cols = n;
309  rowset=rowset_;
310 
311  Assert(rowset.size()==0 || rowset.size() == m,
312  ExcMessage("The IndexSet argument to this function needs to either "
313  "be empty (indicating the complete set of rows), or have size "
314  "equal to the desired number of rows as specified by the "
315  "first argument to this function. (Of course, the number "
316  "of indices in this IndexSet may be less than the number "
317  "of rows, but the *size* of the IndexSet must be equal.)"));
318 
319  std::vector<Line> new_lines (rowset.size()==0 ? rows : rowset.n_elements());
320  lines.swap (new_lines);
321 }
322 
323 
324 
325 void
327 {}
328 
329 
330 
331 bool
333 {
334  return ((rows==0) && (cols==0));
335 }
336 
337 
338 
341 {
342  if (!have_entries)
343  return 0;
344 
345  size_type m = 0;
346  for (size_type i=0; i<lines.size(); ++i)
347  {
348  m = std::max (m, static_cast<size_type>(lines[i].entries.size()));
349  }
350 
351  return m;
352 }
353 
354 
355 
356 bool
358  const size_type j) const
359 {
360  Assert (i<rows, ExcIndexRange(i, 0, rows));
361  Assert (j<cols, ExcIndexRange(j, 0, cols));
363 
364  if (!have_entries)
365  return false;
366 
367  const size_type rowindex =
368  rowset.size()==0 ? i : rowset.index_within_set(i);
369 
370  return std::binary_search (lines[rowindex].entries.begin(),
371  lines[rowindex].entries.end(),
372  j);
373 }
374 
375 
376 
377 void
379 {
381 
382  // loop over all elements presently
383  // in the sparsity pattern and add
384  // the transpose element. note:
385  //
386  // 1. that the sparsity pattern
387  // changes which we work on, but
388  // not the present row
389  //
390  // 2. that the @p{add} function can
391  // be called on elements that
392  // already exist without any harm
393  for (size_type row=0; row<lines.size(); ++row)
394  {
395  const size_type rowindex =
396  rowset.size()==0 ? row : rowset.nth_index_in_set(row);
397 
398  for (std::vector<size_type>::const_iterator
399  j=lines[row].entries.begin();
400  j != lines[row].entries.end();
401  ++j)
402  // add the transpose entry if
403  // this is not the diagonal
404  if (rowindex != *j)
405  add (*j, rowindex);
406  }
407 }
408 
409 
410 
411 template <typename SparsityPatternTypeLeft, typename SparsityPatternTypeRight>
412 void
414  const SparsityPatternTypeLeft &left,
415  const SparsityPatternTypeRight &right)
416 {
417  Assert (left.n_cols() == right.n_rows(),
418  ExcDimensionMismatch(left.n_cols(), right.n_rows()));
419 
420  this->reinit(left.n_rows(),right.n_cols());
421 
422  typename SparsityPatternTypeLeft::iterator
423  it_left = left.begin(),
424  end_left = left.end();
425  for (; it_left!=end_left; ++it_left)
426  {
427  const unsigned int j = it_left->column();
428 
429  // We are sitting on entry (i,j) of the left sparsity pattern. We then need
430  // to add all entries (i,k) to the final sparsity pattern where (j,k) exists
431  // in the right sparsity pattern -- i.e., we need to iterate over row j.
432  typename SparsityPatternTypeRight::iterator
433  it_right = right.begin(j),
434  end_right = right.end(j);
435  for (; it_right!=end_right; ++it_right)
436  this->add(it_left->row(),it_right->column());
437  }
438 }
439 
440 
441 
442 void
443 DynamicSparsityPattern::print (std::ostream &out) const
444 {
445  for (size_type row=0; row<lines.size(); ++row)
446  {
447  out << '[' << (rowset.size()==0 ? row : rowset.nth_index_in_set(row));
448 
449  for (std::vector<size_type >::const_iterator
450  j=lines[row].entries.begin();
451  j != lines[row].entries.end(); ++j)
452  out << ',' << *j;
453 
454  out << ']' << std::endl;
455  }
456 
457  AssertThrow (out, ExcIO());
458 }
459 
460 
461 
462 void
463 DynamicSparsityPattern::print_gnuplot (std::ostream &out) const
464 {
465  for (size_type row=0; row<lines.size(); ++row)
466  {
467  const size_type rowindex =
468  rowset.size()==0 ? row : rowset.nth_index_in_set(row);
469 
470  for (std::vector<size_type >::const_iterator
471  j=lines[row].entries.begin();
472  j != lines[row].entries.end(); ++j)
473  // while matrix entries are usually
474  // written (i,j), with i vertical and
475  // j horizontal, gnuplot output is
476  // x-y, that is we have to exchange
477  // the order of output
478  out << *j << " "
479  << -static_cast<signed int>(rowindex)
480  << std::endl;
481  }
482 
483 
484  AssertThrow (out, ExcIO());
485 }
486 
487 
488 
491 {
492  size_type b=0;
493  for (size_type row=0; row<lines.size(); ++row)
494  {
495  const size_type rowindex =
496  rowset.size()==0 ? row : rowset.nth_index_in_set(row);
497 
498  for (std::vector<size_type>::const_iterator
499  j=lines[row].entries.begin();
500  j != lines[row].entries.end(); ++j)
501  if (static_cast<size_type>(std::abs(static_cast<int>(rowindex-*j))) > b)
502  b = std::abs(static_cast<signed int>(rowindex-*j));
503  }
504 
505  return b;
506 }
507 
508 
509 
512 {
513  if (!have_entries)
514  return 0;
515 
516  size_type n=0;
517  for (size_type i=0; i<lines.size(); ++i)
518  {
519  n += lines[i].entries.size();
520  }
521 
522  return n;
523 }
524 
525 
528 {
529  size_type mem = sizeof(DynamicSparsityPattern)
531  - sizeof(rowset);
532 
533  for (size_type i=0; i<lines.size(); ++i)
535 
536  return mem;
537 }
538 
539 
540 // explicit instantiations
541 template void DynamicSparsityPattern::Line::add_entries(size_type *,
542  size_type *,
543  const bool);
544 template void DynamicSparsityPattern::Line::add_entries(const size_type *,
545  const size_type *,
546  const bool);
547 #ifndef DEAL_II_VECTOR_ITERATOR_IS_POINTER
548 template void DynamicSparsityPattern::Line::
549 add_entries(std::vector<size_type>::iterator,
550  std::vector<size_type>::iterator,
551  const bool);
552 #endif
553 
555  const DynamicSparsityPattern &,
556  const DynamicSparsityPattern &);
558  const DynamicSparsityPattern &,
559  const SparsityPattern &);
561  const SparsityPattern &,
562  const DynamicSparsityPattern &);
564  const SparsityPattern &,
565  const SparsityPattern &);
566 
567 DEAL_II_NAMESPACE_CLOSE
Iterator lower_bound(Iterator first, Iterator last, const T &val)
Definition: utilities.h:891
size_type nth_index_in_set(const unsigned int local_index) const
Definition: index_set.h:1769
static ::ExceptionBase & ExcIO()
void add(const size_type i, const size_type j)
#define AssertThrow(cond, exc)
Definition: exceptions.h:1221
static ::ExceptionBase & ExcIndexRange(int arg1, int arg2, int arg3)
types::global_dof_index size_type
size_type size() const
Definition: index_set.h:1575
static ::ExceptionBase & ExcMessage(std::string arg1)
#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())
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
size_type index_within_set(const size_type global_index) const
Definition: index_set.h:1811
void print_gnuplot(std::ostream &out) const
void compute_mmult_pattern(const SparsityPatternTypeLeft &left, const SparsityPatternTypeRight &right)
static ::ExceptionBase & ExcNotQuadratic()
DynamicSparsityPattern & operator=(const DynamicSparsityPattern &)
void print(std::ostream &out) const
bool is_element(const size_type index) const
Definition: index_set.h:1645
bool exists(const size_type i, const size_type j) const
size_type n_elements() const
Definition: index_set.h:1717
std::enable_if< std::is_fundamental< T >::value, std::size_t >::type memory_consumption(const T &t)
static ::ExceptionBase & ExcInternalError()