Reference documentation for deal.II version 8.5.1
sparsity_pattern.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2000 - 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 
17 #include <deal.II/base/vector_slice.h>
18 #include <deal.II/base/utilities.h>
19 #include <deal.II/lac/sparsity_pattern.h>
20 #include <deal.II/lac/sparsity_tools.h>
21 #include <deal.II/lac/full_matrix.h>
22 #include <deal.II/lac/dynamic_sparsity_pattern.h>
23 
24 #include <iostream>
25 #include <iomanip>
26 #include <algorithm>
27 #include <cmath>
28 #include <numeric>
29 #include <functional>
30 
31 DEAL_II_NAMESPACE_OPEN
32 
33 #ifdef DEAL_II_MSVC
34 __declspec(selectany) // Weak extern binding due to multiple link error
35 #endif
37 
38 
39 
41  :
42  max_dim(0),
43  max_vec_len(0),
44  rowstart(0),
45  colnums(0),
46  compressed(false),
47  store_diagonal_first_in_row(false)
48 {
49  reinit (0,0,0);
50 }
51 
52 
53 
55  :
56  Subscriptor(),
57  max_dim(0),
58  max_vec_len(0),
59  rowstart(0),
60  colnums(0),
61  compressed(false),
62  store_diagonal_first_in_row(false)
63 {
64  (void)s;
65  Assert (s.empty(),
66  ExcMessage("This constructor can only be called if the provided argument "
67  "is the sparsity pattern for an empty matrix. This constructor can "
68  "not be used to copy-construct a non-empty sparsity pattern."));
69 
70  reinit (0,0,0);
71 }
72 
73 
74 
76  const size_type n,
77  const unsigned int max_per_row)
78  :
79  max_dim(0),
80  max_vec_len(0),
81  rowstart(0),
82  colnums(0),
83  compressed(false),
84  store_diagonal_first_in_row(m == n)
85 {
86  reinit (m,n,max_per_row);
87 }
88 
89 
90 
92  const size_type n,
93  const std::vector<unsigned int> &row_lengths)
94  :
95  max_dim(0),
96  max_vec_len(0),
97  rowstart(0),
98  colnums(0),
99  store_diagonal_first_in_row(m == n)
100 {
101  reinit (m, n, row_lengths);
102 }
103 
104 
105 
107  const unsigned int max_per_row)
108  :
109  max_dim(0),
110  max_vec_len(0),
111  rowstart(0),
112  colnums(0)
113 {
114  reinit (m, m, max_per_row);
115 }
116 
117 
118 
120  const std::vector<unsigned int> &row_lengths)
121  :
122  max_dim(0),
123  max_vec_len(0),
124  rowstart(0),
125  colnums(0)
126 {
127  reinit (m, m, row_lengths);
128 }
129 
130 
131 
133  const unsigned int max_per_row,
134  const size_type extra_off_diagonals)
135  :
136  max_dim(0),
137  max_vec_len(0),
138  rowstart(0),
139  colnums(0)
140 {
141  Assert (original.rows==original.cols, ExcNotQuadratic());
142  Assert (original.is_compressed(), ExcNotCompressed());
143 
144  reinit (original.rows, original.cols, max_per_row);
145 
146  // now copy the entries from the other object
147  for (size_type row=0; row<original.rows; ++row)
148  {
149  // copy the elements of this row of the other object
150  //
151  // note that the first object actually is the main-diagonal element,
152  // which we need not copy
153  //
154  // we do the copying in two steps: first we note that the elements in
155  // @p{original} are sorted, so we may first copy all the elements up to
156  // the first side-diagonal one which is to be filled in. then we insert
157  // the side-diagonals, finally copy the rest from that element onwards
158  // which is not a side-diagonal any more.
159  const size_type *const
160  original_row_start = &original.colnums[original.rowstart[row]] + 1;
161  // the following requires that @p{original} be compressed since
162  // otherwise there might be invalid_entry's
163  const size_type *const
164  original_row_end = &original.colnums[original.rowstart[row+1]];
165 
166  // find pointers before and after extra off-diagonals. if at top or
167  // bottom of matrix, then set these pointers such that no copying is
168  // necessary (see the @p{copy} commands)
169  const size_type *const
170  original_last_before_side_diagonals
171  = (row > extra_off_diagonals ?
172  Utilities::lower_bound (original_row_start,
173  original_row_end,
174  row-extra_off_diagonals) :
175  original_row_start);
176 
177  const size_type *const
178  original_first_after_side_diagonals
179  = (row < rows-extra_off_diagonals-1 ?
180  std::upper_bound (original_row_start,
181  original_row_end,
182  row+extra_off_diagonals) :
183  original_row_end);
184 
185  // find first free slot. the first slot in each row is the diagonal
186  // element
187  size_type *next_free_slot = &colnums[rowstart[row]] + 1;
188 
189  // copy elements before side-diagonals
190  next_free_slot = std::copy (original_row_start,
191  original_last_before_side_diagonals,
192  next_free_slot);
193 
194  // insert left and right side-diagonals
195  for (size_type i=1; i<=std::min(row,extra_off_diagonals);
196  ++i, ++next_free_slot)
197  *next_free_slot = row-i;
198  for (size_type i=1; i<=std::min(extra_off_diagonals, rows-row-1);
199  ++i, ++next_free_slot)
200  *next_free_slot = row+i;
201 
202  // copy rest
203  next_free_slot = std::copy (original_first_after_side_diagonals,
204  original_row_end,
205  next_free_slot);
206 
207  // this error may happen if the sum of previous elements per row and
208  // those of the new diagonals exceeds the maximum number of elements per
209  // row given to this constructor
210  Assert (next_free_slot <= &colnums[rowstart[row+1]],
211  ExcNotEnoughSpace (0,rowstart[row+1]-rowstart[row]));
212  };
213 }
214 
215 
216 
218 {
219  if (rowstart != 0) delete[] rowstart;
220  if (colnums != 0) delete[] colnums;
221 }
222 
223 
224 
227 {
228  (void)s;
229  Assert (s.empty(),
230  ExcMessage("This operator can only be called if the provided argument "
231  "is the sparsity pattern for an empty matrix. This operator can "
232  "not be used to copy a non-empty sparsity pattern."));
233 
234  Assert (this->empty(),
235  ExcMessage("This operator can only be called if the current object is "
236  "empty."));
237 
238  return *this;
239 }
240 
241 
242 
243 void
245  const size_type n,
246  const unsigned int max_per_row)
247 {
248  // simply map this function to the other @p{reinit} function
249  const std::vector<unsigned int> row_lengths (m, max_per_row);
250  reinit (m, n, row_lengths);
251 }
252 
253 
254 
255 void
257  const size_type n,
258  const VectorSlice<const std::vector<unsigned int> > &row_lengths)
259 {
260  AssertDimension (row_lengths.size(), m);
261 
262  rows = m;
263  cols = n;
264 
265  // delete empty matrices
266  if ((m==0) || (n==0))
267  {
268  if (rowstart) delete[] rowstart;
269  if (colnums) delete[] colnums;
270  rowstart = 0;
271  colnums = 0;
272  max_vec_len = max_dim = rows = cols = 0;
273  // if dimension is zero: ignore max_per_row
274  max_row_length = 0;
275  compressed = false;
276  return;
277  }
278 
279  // first, if the matrix is quadratic, we will have to make sure that each
280  // row has at least one entry for the diagonal element. make this more
281  // obvious by having a variable which we can query
282  store_diagonal_first_in_row = (m == n);
283 
284  // find out how many entries we need in the @p{colnums} array. if this
285  // number is larger than @p{max_vec_len}, then we will need to reallocate
286  // memory
287  //
288  // note that the number of elements per row is bounded by the number of
289  // columns
290  //
291  std::size_t vec_len = 0;
292  for (size_type i=0; i<m; ++i)
293  vec_len += std::min(static_cast<size_type>(store_diagonal_first_in_row ?
294  std::max(row_lengths[i], 1U) :
295  row_lengths[i]),
296  n);
297 
298  // sometimes, no entries are requested in the matrix (this most often
299  // happens when blocks in a block matrix are simply zero). in that case,
300  // allocate exactly one element, to have a valid pointer to some memory
301  if (vec_len == 0)
302  {
303  vec_len = 1;
304  if (colnums)
305  {
306  delete[] colnums;
307  colnums = 0;
308  }
309 
310  max_vec_len = vec_len;
312  }
313 
314  max_row_length = (row_lengths.size() == 0 ?
315  0 :
316  std::min (static_cast<size_type>(*std::max_element(row_lengths.begin(),
317  row_lengths.end())),
318  n));
319 
320  if (store_diagonal_first_in_row && (max_row_length==0) && (m!=0))
321  max_row_length = 1;
322 
323  // allocate memory for the rowstart values, if necessary. even though we
324  // re-set the pointers again immediately after deleting their old content,
325  // set them to zero in between because the allocation might fail, in which
326  // case we get an exception and the destructor of this object will be called
327  // -- where we look at the non-nullness of the (now invalid) pointer again
328  // and try to delete the memory a second time.
329  if (rows > max_dim)
330  {
331  if (rowstart)
332  {
333  delete[] rowstart;
334  rowstart = 0;
335  }
336 
337  max_dim = rows;
338  rowstart = new std::size_t[max_dim+1];
339  }
340 
341  // allocate memory for the column numbers if necessary
342  if (vec_len > max_vec_len)
343  {
344  if (colnums)
345  {
346  delete[] colnums;
347  colnums = 0;
348  }
349 
350  max_vec_len = vec_len;
352  }
353 
354  // set the rowstart array
355  rowstart[0] = 0;
356  for (size_type i=1; i<=rows; ++i)
357  rowstart[i] = rowstart[i-1] +
359  std::max(std::min(static_cast<size_type>(row_lengths[i-1]),n),
360  static_cast<size_type> (1U)) :
361  std::min(static_cast<size_type>(row_lengths[i-1]),n));
362  Assert ((rowstart[rows]==vec_len)
363  ||
364  ((vec_len == 1) && (rowstart[rows] == 0)),
365  ExcInternalError());
366 
367  // preset the column numbers by a value indicating it is not in use
368  std::fill_n (&colnums[0], vec_len, invalid_entry);
369 
370  // if diagonal elements are special: let the first entry in each row be the
371  // diagonal value
373  for (size_type i=0; i<rows; i++)
374  colnums[rowstart[i]] = i;
375 
376  compressed = false;
377 }
378 
379 
380 
381 void
383 {
384  Assert ((rowstart!=0) && (colnums!=0), ExcEmptyObject());
385 
386  // do nothing if already compressed
387  if (compressed)
388  return;
389 
390  size_type next_free_entry = 0,
391  next_row_start = 0,
392  row_length = 0;
393 
394  // first find out how many non-zero elements there are, in order to allocate
395  // the right amount of memory
396  const std::size_t nonzero_elements
397  = std::count_if (&colnums[rowstart[0]],
398  &colnums[rowstart[rows]],
399  std_cxx11::bind(std::not_equal_to<size_type>(), std_cxx11::_1, invalid_entry));
400  // now allocate the respective memory
401  size_type *new_colnums = new size_type[nonzero_elements];
402 
403 
404  // reserve temporary storage to store the entries of one row
405  std::vector<size_type> tmp_entries (max_row_length);
406 
407  // Traverse all rows
408  for (size_type line=0; line<rows; ++line)
409  {
410  // copy used entries, break if first unused entry is reached
411  row_length = 0;
412  for (size_type j=rowstart[line]; j<rowstart[line+1]; ++j,++row_length)
413  if (colnums[j] != invalid_entry)
414  tmp_entries[row_length] = colnums[j];
415  else
416  break;
417  // now @p{rowstart} is the number of entries in this line
418 
419  // Sort only beginning at the second entry, if optimized storage of
420  // diagonal entries is on.
421 
422  // if this line is empty or has only one entry, don't sort
423  if (row_length > 1)
424  std::sort ((store_diagonal_first_in_row)
425  ? tmp_entries.begin()+1
426  : tmp_entries.begin(),
427  tmp_entries.begin()+row_length);
428 
429  // insert column numbers into the new field
430  for (size_type j=0; j<row_length; ++j)
431  new_colnums[next_free_entry++] = tmp_entries[j];
432 
433  // note new start of this and the next row
434  rowstart[line] = next_row_start;
435  next_row_start = next_free_entry;
436 
437  // some internal checks: either the matrix is not quadratic, or if it
438  // is, then the first element of this row must be the diagonal element
439  // (i.e. with column index==line number)
440  // this test only makes sense if we have written to the index
441  // rowstart_line in new_colnums which is the case if row_length is not 0,
442  // so check this first
444  (row_length != 0 && new_colnums[rowstart[line]] == line),
445  ExcInternalError());
446  // assert that the first entry does not show up in the remaining ones
447  // and that the remaining ones are unique among themselves (this handles
448  // both cases, quadratic and rectangular matrices)
449  //
450  // the only exception here is if the row contains no entries at all
451  Assert ((rowstart[line] == next_row_start)
452  ||
453  (std::find (&new_colnums[rowstart[line]+1],
454  &new_colnums[next_row_start],
455  new_colnums[rowstart[line]]) ==
456  &new_colnums[next_row_start]),
457  ExcInternalError());
458  Assert ((rowstart[line] == next_row_start)
459  ||
460  (std::adjacent_find(&new_colnums[rowstart[line]+1],
461  &new_colnums[next_row_start]) ==
462  &new_colnums[next_row_start]),
463  ExcInternalError());
464  };
465 
466  // assert that we have used all allocated space, no more and no less
467  Assert (next_free_entry == nonzero_elements,
468  ExcInternalError());
469 
470  // set iterator-past-the-end
471  rowstart[rows] = next_row_start;
472 
473  // set colnums to the newly allocated array and delete the old one
474  delete[] colnums;
475  colnums = new_colnums;
476 
477  // store the size
478  max_vec_len = nonzero_elements;
479 
480  compressed = true;
481 }
482 
483 
484 
485 template <typename SparsityPatternType>
486 void
487 SparsityPattern::copy_from (const SparsityPatternType &dsp)
488 {
489  // first determine row lengths for each row. if the matrix is quadratic,
490  // then we might have to add an additional entry for the diagonal, if that
491  // is not yet present. as we have to call compress anyway later on, don't
492  // bother to check whether that diagonal entry is in a certain row or not
493  const bool do_diag_optimize = (dsp.n_rows() == dsp.n_cols());
494  std::vector<unsigned int> row_lengths (dsp.n_rows());
495  for (size_type i=0; i<dsp.n_rows(); ++i)
496  {
497  row_lengths[i] = dsp.row_length(i);
498  if (do_diag_optimize && !dsp.exists(i,i))
499  ++row_lengths[i];
500  }
501  reinit (dsp.n_rows(), dsp.n_cols(), row_lengths);
502 
503  // now enter all the elements into the matrix, if there are any. note that
504  // if the matrix is quadratic, then we already have the diagonal element
505  // preallocated
506  if (n_rows() != 0 && n_cols() != 0)
507  for (size_type row = 0; row<dsp.n_rows(); ++row)
508  {
509  size_type *cols = &colnums[rowstart[row]] + (do_diag_optimize ? 1 : 0);
510  typename SparsityPatternType::iterator col_num = dsp.begin (row),
511  end_row = dsp.end (row);
512 
513  for (; col_num != end_row; ++col_num)
514  {
515  const size_type col = col_num->column();
516  if ((col!=row) || !do_diag_optimize)
517  *cols++ = col;
518  }
519  }
520 
521  // do not need to compress the sparsity pattern since we already have
522  // allocated the right amount of data, and the SparsityPatternType data is sorted,
523  // too.
524  compressed = true;
525 }
526 
527 
528 
529 // Use a special implementation for DynamicSparsityPattern where we can use
530 // the column_number method to gain faster access to the
531 // entries. DynamicSparsityPattern::iterator can show quadratic complexity in
532 // case many rows are empty and the begin() method needs to jump to the next
533 // free row. Otherwise, the code is exactly the same as above.
534 template <>
535 void
537 {
538  const bool do_diag_optimize = (dsp.n_rows() == dsp.n_cols());
539  std::vector<unsigned int> row_lengths (dsp.n_rows());
540  for (size_type i=0; i<dsp.n_rows(); ++i)
541  {
542  row_lengths[i] = dsp.row_length(i);
543  if (do_diag_optimize && !dsp.exists(i,i))
544  ++row_lengths[i];
545  }
546  reinit (dsp.n_rows(), dsp.n_cols(), row_lengths);
547 
548  if (n_rows() != 0 && n_cols() != 0)
549  for (size_type row = 0; row<dsp.n_rows(); ++row)
550  {
551  size_type *cols = &colnums[rowstart[row]] + (do_diag_optimize ? 1 : 0);
552  const unsigned int row_length = dsp.row_length(row);
553  for (unsigned int index=0; index < row_length; ++index)
554  {
555  const size_type col = dsp.column_number(row, index);
556  if ((col!=row) || !do_diag_optimize)
557  *cols++ = col;
558  }
559  }
560 
561  // do not need to compress the sparsity pattern since we already have
562  // allocated the right amount of data, and the SparsityPatternType data is sorted,
563  // too.
564  compressed = true;
565 }
566 
567 
568 
569 template <typename number>
571 {
572  // first init with the number of entries per row. if this matrix is square
573  // then we also have to allocate memory for the diagonal entry, unless we
574  // have already counted it
575  std::vector<unsigned int> entries_per_row (matrix.m(), 0);
576  for (size_type row=0; row<matrix.m(); ++row)
577  {
578  for (size_type col=0; col<matrix.n(); ++col)
579  if (matrix(row,col) != 0)
580  ++entries_per_row[row];
581  if ((matrix.m() == matrix.n())
582  &&
583  (matrix(row,row) == 0))
584  ++entries_per_row[row];
585  }
586 
587  reinit (matrix.m(), matrix.n(), entries_per_row);
588 
589  // now set entries
590  for (size_type row=0; row<matrix.m(); ++row)
591  for (size_type col=0; col<matrix.n(); ++col)
592  if (matrix(row,col) != 0)
593  add (row,col);
594 
595  // finally compress
596  compress ();
597 }
598 
599 
600 void
602  const size_type n,
603  const std::vector<unsigned int> &row_lengths)
604 {
605  reinit(m, n, make_slice(row_lengths));
606 }
607 
608 
609 
610 
611 bool
613 {
614  // let's try to be on the safe side of life by using multiple possibilities
615  // in the check for emptiness... (sorry for this kludge -- emptying matrices
616  // and freeing memory was not present in the original implementation and I
617  // don't know at how many places I missed something in adding it, so I try
618  // to be cautious. wb)
619  if ((rowstart==0) || (rows==0) || (cols==0))
620  {
622  Assert (rows==0, ExcInternalError());
623  Assert (cols==0, ExcInternalError());
626 
627  return true;
628  };
629  return false;
630 }
631 
632 
633 
636 {
637  // if compress() has not yet been called, we can get the maximum number of
638  // elements per row using the stored value
639  if (!compressed)
640  return max_row_length;
641 
642  // if compress() was called, we use a better algorithm which gives us a
643  // sharp bound
644  size_type m = 0;
645  for (size_type i=1; i<=rows; ++i)
646  m = std::max (m, static_cast<size_type>(rowstart[i]-rowstart[i-1]));
647 
648  return m;
649 }
650 
651 
652 
655  const size_type j) const
656 {
657  Assert ((rowstart!=0) && (colnums!=0), ExcEmptyObject());
658  Assert (i<rows, ExcIndexRange(i,0,rows));
659  Assert (j<cols, ExcIndexRange(j,0,cols));
661 
662  // let's see whether there is something in this line
663  if (rowstart[i] == rowstart[i+1])
664  return invalid_entry;
665 
666  // If special storage of diagonals was requested, we can get the diagonal
667  // element faster by this query.
668  if (store_diagonal_first_in_row && (i==j))
669  return rowstart[i];
670 
671  // all other entries are sorted, so we can use a binary search algorithm
672  //
673  // note that the entries are only sorted upon compression, so this would
674  // fail for non-compressed sparsity patterns; however, that is why the
675  // Assertion is at the top of this function, so it may not be called for
676  // noncompressed structures.
677  const size_type *sorted_region_start = (store_diagonal_first_in_row ?
678  &colnums[rowstart[i]+1] :
679  &colnums[rowstart[i]]);
680  const size_type *const p
681  = Utilities::lower_bound<const size_type *> (sorted_region_start,
682  &colnums[rowstart[i+1]],
683  j);
684  if ((p != &colnums[rowstart[i+1]]) && (*p == j))
685  return (p - &colnums[0]);
686  else
687  return invalid_entry;
688 }
689 
690 
691 
692 void
694  const size_type j)
695 {
696  Assert ((rowstart!=0) && (colnums!=0), ExcEmptyObject());
697  Assert (i<rows, ExcIndexRange(i,0,rows));
698  Assert (j<cols, ExcIndexRange(j,0,cols));
700 
701  for (std::size_t k=rowstart[i]; k<rowstart[i+1]; k++)
702  {
703  // entry already exists
704  if (colnums[k] == j) return;
705  // empty entry found, put new entry here
706  if (colnums[k] == invalid_entry)
707  {
708  colnums[k] = j;
709  return;
710  };
711  };
712 
713  // if we came thus far, something went wrong: there was not enough space in
714  // this line
715  Assert (false, ExcNotEnoughSpace(i, rowstart[i+1]-rowstart[i]));
716 }
717 
718 
719 
720 template <typename ForwardIterator>
721 void
723  ForwardIterator begin,
724  ForwardIterator end,
725  const bool indices_are_sorted)
726 {
727  if (indices_are_sorted == true)
728  {
729  if (begin != end)
730  {
731  ForwardIterator it = begin;
732  bool has_larger_entries = false;
733  // skip diagonal
734  std::size_t k=rowstart[row]+store_diagonal_first_in_row;
735  for ( ; k<rowstart[row+1]; k++)
736  if (colnums[k] == invalid_entry)
737  break;
738  else if (colnums[k] >= *it)
739  {
740  has_larger_entries = true;
741  break;
742  }
743  if (has_larger_entries == false)
744  for ( ; it != end; ++it)
745  {
746  if (store_diagonal_first_in_row && *it == row)
747  continue;
748  Assert (k <= rowstart[row+1],
749  ExcNotEnoughSpace(row, rowstart[row+1]-rowstart[row]));
750  colnums[k++] = *it;
751  }
752  else
753  // cannot just append the new range at the end, forward to the
754  // other function
755  for (ForwardIterator p = begin; p != end; ++p)
756  add (row, *p);
757  }
758  }
759  else
760  {
761  // forward to the other function.
762  for (ForwardIterator it = begin; it != end; ++it)
763  add (row, *it);
764  }
765 }
766 
767 
768 bool
770 {
771  Assert ((rowstart!=0) && (colnums!=0), ExcEmptyObject());
772  Assert (i<rows, ExcIndexRange(i,0,rows));
773  Assert (j<cols, ExcIndexRange(j,0,cols));
774 
775  for (size_type k=rowstart[i]; k<rowstart[i+1]; k++)
776  {
777  // entry already exists
778  if (colnums[k] == j) return true;
779  }
780  return false;
781 }
782 
783 
784 
787 {
788  Assert ((rowstart!=0) && (colnums!=0), ExcEmptyObject());
789  Assert (i<rows, ExcIndexRange(i,0,rows));
790  Assert (j<cols, ExcIndexRange(j,0,cols));
791 
792  for (size_type k=rowstart[i]; k<rowstart[i+1]; k++)
793  {
794  // entry exists
795  if (colnums[k] == j) return k-rowstart[i];
796  }
798 }
799 
800 
801 
802 std::pair<SparsityPattern::size_type, SparsityPattern::size_type>
803 SparsityPattern::matrix_position (const std::size_t global_index) const
804 {
805  Assert (compressed == true, ExcNotCompressed());
806  Assert (global_index < n_nonzero_elements(),
807  ExcIndexRange (global_index, 0, n_nonzero_elements()));
808 
809  // first find the row in which the entry is located. for this note that the
810  // rowstart array indexes the global indices at which each row starts. since
811  // it is sorted, and since there is an element for the one-past-last row, we
812  // can simply use a bisection search on it
813  const size_type row
814  = (std::upper_bound (&rowstart[0], &rowstart[rows], global_index)
815  - &rowstart[0] - 1);
816 
817  // now, the column index is simple since that is what the colnums array
818  // stores:
819  const size_type col = colnums[global_index];
820 
821  // so return the respective pair
822  return std::make_pair (row,col);
823 }
824 
825 
826 
827 void
829 {
830  Assert ((rowstart!=0) && (colnums!=0), ExcEmptyObject());
832  // Note that we only require a quadratic matrix here, no special treatment
833  // of diagonals
835 
836  // loop over all elements presently in the sparsity pattern and add the
837  // transpose element. note:
838  //
839  // 1. that the sparsity pattern changes which we work on, but not the
840  // present row
841  //
842  // 2. that the @p{add} function can be called on elements that already exist
843  // without any harm
844  for (size_type row=0; row<rows; ++row)
845  for (size_type k=rowstart[row]; k<rowstart[row+1]; k++)
846  {
847  // check whether we are at the end of the entries of this row. if so,
848  // go to next row
849  if (colnums[k] == invalid_entry)
850  break;
851 
852  // otherwise add the transpose entry if this is not the diagonal (that
853  // would not harm, only take time to check up)
854  if (colnums[k] != row)
855  add (colnums[k], row);
856  };
857 }
858 
859 
860 
861 void
862 SparsityPattern::print (std::ostream &out) const
863 {
864  Assert ((rowstart!=0) && (colnums!=0), ExcEmptyObject());
865 
866  AssertThrow (out, ExcIO());
867 
868  for (size_type i=0; i<rows; ++i)
869  {
870  out << '[' << i;
871  for (size_type j=rowstart[i]; j<rowstart[i+1]; ++j)
872  if (colnums[j] != invalid_entry)
873  out << ',' << colnums[j];
874  out << ']' << std::endl;
875  }
876 
877  AssertThrow (out, ExcIO());
878 }
879 
880 
881 
882 void
883 SparsityPattern::print_gnuplot (std::ostream &out) const
884 {
885  Assert ((rowstart!=0) && (colnums!=0), ExcEmptyObject());
886 
887  AssertThrow (out, ExcIO());
888 
889  for (size_type i=0; i<rows; ++i)
890  for (size_type j=rowstart[i]; j<rowstart[i+1]; ++j)
891  if (colnums[j] != invalid_entry)
892  // while matrix entries are usually written (i,j), with i vertical and
893  // j horizontal, gnuplot output is x-y, that is we have to exchange
894  // the order of output
895  out << colnums[j] << " " << -static_cast<signed int>(i) << std::endl;
896 
897  AssertThrow (out, ExcIO());
898 }
899 
900 void
901 SparsityPattern::print_svg (std::ostream &out) const
902 {
903  unsigned int m = this->n_rows();
904  unsigned int n = this->n_cols();
905  out << "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 " << n+2
906  << " " << m+2 << " \">\n"
907  "<style type=\"text/css\" >\n"
908  " <![CDATA[\n"
909  " rect.pixel {\n"
910  " fill: #ff0000;\n"
911  " }\n"
912  " ]]>\n"
913  " </style>\n\n"
914  " <rect width=\"" << n+2 << "\" height=\"" << m+2 << "\" fill=\"rgb(128, 128, 128)\"/>\n"
915  " <rect x=\"1\" y=\"1\" width=\"" << n << "\" height=\"" << m
916  << "\" fill=\"rgb(255, 255, 255)\"/>\n\n";
917 
919  it = this->begin(),
920  end = this->end();
921  for (; it!=end; ++it)
922  {
923  out << " <rect class=\"pixel\" x=\"" << it->column()+1
924  << "\" y=\"" << it->row()+1
925  << "\" width=\".9\" height=\".9\"/>\n";
926  }
927  out << "</svg>" << std::endl;
928 
929 }
930 
931 
932 
933 
936 {
937  Assert ((rowstart!=0) && (colnums!=0), ExcEmptyObject());
938  size_type b=0;
939  for (size_type i=0; i<rows; ++i)
940  for (size_type j=rowstart[i]; j<rowstart[i+1]; ++j)
941  if (colnums[j] != invalid_entry)
942  {
943  if (static_cast<size_type>(std::abs(static_cast<int>(i-colnums[j]))) > b)
944  b = std::abs(static_cast<signed int>(i-colnums[j]));
945  }
946  else
947  // leave if at the end of the entries of this line
948  break;
949  return b;
950 }
951 
952 
953 void
954 SparsityPattern::block_write (std::ostream &out) const
955 {
956  AssertThrow (out, ExcIO());
957 
958  // first the simple objects, bracketed in [...]
959  out << '[' << max_dim << ' '
960  << rows << ' '
961  << cols << ' '
962  << max_vec_len << ' '
963  << max_row_length << ' '
964  << compressed << ' '
965  << store_diagonal_first_in_row << "][";
966  // then write out real data
967  out.write (reinterpret_cast<const char *>(&rowstart[0]),
968  reinterpret_cast<const char *>(&rowstart[max_dim+1])
969  - reinterpret_cast<const char *>(&rowstart[0]));
970  out << "][";
971  out.write (reinterpret_cast<const char *>(&colnums[0]),
972  reinterpret_cast<const char *>(&colnums[max_vec_len])
973  - reinterpret_cast<const char *>(&colnums[0]));
974  out << ']';
975 
976  AssertThrow (out, ExcIO());
977 }
978 
979 
980 
981 void
982 SparsityPattern::block_read (std::istream &in)
983 {
984  AssertThrow (in, ExcIO());
985 
986  char c;
987 
988  // first read in simple data
989  in >> c;
990  AssertThrow (c == '[', ExcIO());
991  in >> max_dim
992  >> rows
993  >> cols
994  >> max_vec_len
995  >> max_row_length
996  >> compressed
998 
999  in >> c;
1000  AssertThrow (c == ']', ExcIO());
1001  in >> c;
1002  AssertThrow (c == '[', ExcIO());
1003 
1004  // reallocate space
1005  if (rowstart)
1006  delete[] rowstart;
1007  if (colnums)
1008  delete[] colnums;
1009 
1010  rowstart = new std::size_t[max_dim+1];
1011  colnums = new size_type[max_vec_len];
1012 
1013  // then read data
1014  in.read (reinterpret_cast<char *>(&rowstart[0]),
1015  reinterpret_cast<char *>(&rowstart[max_dim+1])
1016  - reinterpret_cast<char *>(&rowstart[0]));
1017  in >> c;
1018  AssertThrow (c == ']', ExcIO());
1019  in >> c;
1020  AssertThrow (c == '[', ExcIO());
1021  in.read (reinterpret_cast<char *>(&colnums[0]),
1022  reinterpret_cast<char *>(&colnums[max_vec_len])
1023  - reinterpret_cast<char *>(&colnums[0]));
1024  in >> c;
1025  AssertThrow (c == ']', ExcIO());
1026 }
1027 
1028 
1029 
1030 std::size_t
1032 {
1033  return (max_dim * sizeof(size_type) +
1034  sizeof(*this) +
1035  max_vec_len * sizeof(size_type));
1036 }
1037 
1038 
1039 
1040 // explicit instantiations
1041 template void SparsityPattern::copy_from<SparsityPattern> (const SparsityPattern &);
1042 template void SparsityPattern::copy_from<float> (const FullMatrix<float> &);
1043 template void SparsityPattern::copy_from<double> (const FullMatrix<double> &);
1044 
1045 template void SparsityPattern::add_entries<const SparsityPattern::size_type *> (const size_type ,
1046  const size_type *,
1047  const size_type *,
1048  const bool);
1049 #ifndef DEAL_II_VECTOR_ITERATOR_IS_POINTER
1050 template void SparsityPattern::add_entries<std::vector<SparsityPattern::size_type>::const_iterator>
1051 (const size_type,
1052  std::vector<size_type>::const_iterator,
1053  std::vector<size_type>::const_iterator,
1054  const bool);
1055 #endif
1056 template void SparsityPattern::add_entries<std::vector<SparsityPattern::size_type>::iterator>
1057 (const size_type,
1058  std::vector<size_type>::iterator,
1059  std::vector<size_type>::iterator,
1060  const bool);
1061 
1062 DEAL_II_NAMESPACE_CLOSE
Iterator lower_bound(Iterator first, Iterator last, const T &val)
Definition: utilities.h:618
void block_write(std::ostream &out) const
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_sorted=false)
static ::ExceptionBase & ExcMatrixIsCompressed()
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1146
std::size_t n_nonzero_elements() const
size_type operator()(const size_type i, const size_type j) const
static ::ExceptionBase & ExcIO()
size_type column_number(const size_type row, const size_type index) const
static const size_type invalid_entry
std::size_t memory_consumption() const
std::pair< size_type, size_type > matrix_position(const std::size_t global_index) const
void print_gnuplot(std::ostream &out) const
iterator end() const
bool exists(const size_type i, const size_type j) const
bool empty() const
#define AssertThrow(cond, exc)
Definition: exceptions.h:369
static ::ExceptionBase & ExcIndexRange(int arg1, int arg2, int arg3)
size_type n_cols() const
bool is_compressed() const
std::size_t max_vec_len
size_type n_rows() const
size_type bandwidth() const
static ::ExceptionBase & ExcNotCompressed()
static ::ExceptionBase & ExcMessage(std::string arg1)
void add(const size_type i, const size_type j)
#define Assert(cond, exc)
Definition: exceptions.h:313
void print_svg(std::ostream &out) const
void print(std::ostream &out) const
SparsityPattern & operator=(const SparsityPattern &)
size_type max_entries_per_row() const
void copy_from(const size_type n_rows, const size_type n_cols, const ForwardIterator begin, const ForwardIterator end)
void reinit(const size_type m, const size_type n, const unsigned int max_per_row)
std::size_t * rowstart
unsigned int max_row_length
static ::ExceptionBase & ExcNotQuadratic()
types::global_dof_index size_type
static ::ExceptionBase & ExcNotEnoughSpace(int arg1, int arg2)
size_type row_length(const size_type row) const
static ::ExceptionBase & ExcEmptyObject()
void block_read(std::istream &in)
iterator begin() const
bool exists(const size_type i, const size_type j) const
unsigned int row_length(const size_type row) const
size_type row_position(const size_type i, const size_type j) const
static ::ExceptionBase & ExcInternalError()