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