Reference documentation for deal.II version 8.4.2
chunk_sparsity_pattern.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2008 - 2015 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/lac/chunk_sparsity_pattern.h>
18 #include <deal.II/lac/dynamic_sparsity_pattern.h>
19 #include <deal.II/lac/full_matrix.h>
20 
21 
22 DEAL_II_NAMESPACE_OPEN
23 
24 
26 {
27  reinit (0,0,0,1);
28 }
29 
30 
31 
33  :
34  Subscriptor(),
37 {
38  Assert (s.rows == 0, ExcInvalidConstructorCall());
39  Assert (s.cols == 0, ExcInvalidConstructorCall());
40 
41  reinit (0,0,0,0);
42 }
43 
44 
45 
47  const size_type n,
48  const size_type max_per_row,
49  const size_type chunk_size)
50 {
51  Assert (chunk_size > 0, ExcInvalidNumber (chunk_size));
52 
53  reinit (m,n,max_per_row, chunk_size);
54 }
55 
56 
57 
59  const size_type m,
60  const size_type n,
61  const std::vector<size_type> &row_lengths,
62  const size_type chunk_size)
63 {
64  Assert (chunk_size > 0, ExcInvalidNumber (chunk_size));
65 
66  reinit (m, n, row_lengths, chunk_size);
67 }
68 
69 
70 
72  const size_type max_per_row,
73  const size_type chunk_size)
74 {
75  reinit (n, n, max_per_row, chunk_size);
76 }
77 
78 
79 
81  const size_type m,
82  const std::vector<size_type > &row_lengths,
83  const size_type chunk_size)
84 {
85  Assert (chunk_size > 0, ExcInvalidNumber (chunk_size));
86 
87  reinit (m, m, row_lengths, chunk_size);
88 }
89 
90 
91 
93 {}
94 
95 
96 
99 {
100  Assert (s.rows == 0, ExcInvalidConstructorCall());
101  Assert (s.cols == 0, ExcInvalidConstructorCall());
102 
103  // perform the checks in the underlying object as well
105 
106  return *this;
107 }
108 
109 
110 
111 void
113  const size_type n,
114  const size_type max_per_row,
115  const size_type chunk_size)
116 {
117  Assert (chunk_size > 0, ExcInvalidNumber (chunk_size));
118 
119  // simply map this function to the other @p{reinit} function
120  const std::vector<size_type> row_lengths (m, max_per_row);
121  reinit (m, n, row_lengths, chunk_size);
122 }
123 
124 
125 
126 void
128  const size_type m,
129  const size_type n,
130  const VectorSlice<const std::vector<size_type> > &row_lengths,
131  const size_type chunk_size)
132 {
133  Assert (row_lengths.size() == m, ExcInvalidNumber (m));
134  Assert (chunk_size > 0, ExcInvalidNumber (chunk_size));
135 
136  rows = m;
137  cols = n;
138 
139  this->chunk_size = chunk_size;
140 
141  // pass down to the necessary information to the underlying object. we need
142  // to calculate how many chunks we need: we need to round up (m/chunk_size)
143  // and (n/chunk_size). rounding up in integer arithmetic equals
144  // ((m+chunk_size-1)/chunk_size):
145  const size_type m_chunks = (m+chunk_size-1) / chunk_size,
146  n_chunks = (n+chunk_size-1) / chunk_size;
147 
148  // compute the maximum number of chunks in each row. the passed array
149  // denotes the number of entries in each row of the big matrix -- in the
150  // worst case, these are all in independent chunks, so we have to calculate
151  // it as follows (as an example: let chunk_size==2, row_lengths={2,2,...},
152  // and entries in row zero at columns {0,2} and for row one at {4,6} -->
153  // we'll need 4 chunks for the first chunk row!) :
154  std::vector<unsigned int> chunk_row_lengths (m_chunks, 0);
155  for (size_type i=0; i<m; ++i)
156  chunk_row_lengths[i/chunk_size] += row_lengths[i];
157 
158  // for the case that the reduced sparsity pattern optimizes the diagonal but
159  // the actual sparsity pattern does not, need to take one more entry in the
160  // row to fit the user-required entry
161  if (m != n && m_chunks == n_chunks)
162  for (unsigned int i=0; i<m_chunks; ++i)
163  ++chunk_row_lengths[i];
164 
165  sparsity_pattern.reinit (m_chunks,
166  n_chunks,
167  chunk_row_lengths);
168 }
169 
170 
171 
172 void
174 {
176 }
177 
178 
179 
180 template <typename SparsityPatternType>
181 void
182 ChunkSparsityPattern::copy_from (const SparsityPatternType &dsp,
183  const size_type chunk_size)
184 {
185  Assert (chunk_size > 0, ExcInvalidNumber (chunk_size));
186  this->chunk_size = chunk_size;
187  rows = dsp.n_rows();
188  cols = dsp.n_cols();
189 
190  // simple case: just use the given sparsity pattern
191  if (chunk_size == 1)
192  {
194  return;
195  }
196 
197  // create a temporary compressed sparsity pattern that collects all entries
198  // from the input sparsity pattern and then initialize the underlying small
199  // sparsity pattern
200  const size_type m_chunks = (dsp.n_rows()+chunk_size-1) / chunk_size,
201  n_chunks = (dsp.n_cols()+chunk_size-1) / chunk_size;
202  DynamicSparsityPattern temporary_sp(m_chunks, n_chunks);
203 
204  for (size_type row = 0; row<dsp.n_rows(); ++row)
205  {
206  const size_type reduced_row = row/chunk_size;
207 
208  // TODO: This could be made more efficient if we cached the
209  // previous column and only called add() if the previous and the
210  // current column lead to different chunk columns
211  for (typename SparsityPatternType::iterator col_num = dsp.begin(row);
212  col_num != dsp.end(row); ++col_num)
213  temporary_sp.add (reduced_row, col_num->column()/chunk_size);
214  }
215 
216  sparsity_pattern.copy_from (temporary_sp);
217 }
218 
219 
220 
221 
222 template <typename number>
224  const size_type chunk_size)
225 {
226  Assert (chunk_size > 0, ExcInvalidNumber (chunk_size));
227 
228  // count number of entries per row, then initialize the underlying sparsity
229  // pattern. remember to also allocate space for the diagonal entry (if that
230  // hasn't happened yet) if m==n since we always allocate that for diagonal
231  // matrices
232  std::vector<size_type> entries_per_row (matrix.m(), 0);
233  for (size_type row=0; row<matrix.m(); ++row)
234  {
235  for (size_type col=0; col<matrix.n(); ++col)
236  if (matrix(row,col) != 0)
237  ++entries_per_row[row];
238 
239  if ((matrix.m() == matrix.n())
240  &&
241  (matrix(row,row) == 0))
242  ++entries_per_row[row];
243  }
244 
245  reinit (matrix.m(), matrix.n(),
246  entries_per_row,
247  chunk_size);
248 
249  // then actually fill it
250  for (size_type row=0; row<matrix.m(); ++row)
251  for (size_type col=0; col<matrix.n(); ++col)
252  if (matrix(row,col) != 0)
253  add (row,col);
254 
255  // finally compress
256  compress ();
257 }
258 
259 
260 
261 void
263  const size_type m,
264  const size_type n,
265  const std::vector<size_type> &row_lengths,
266  const size_type chunk_size)
267 {
268  Assert (chunk_size > 0, ExcInvalidNumber (chunk_size));
269 
270  reinit(m, n, make_slice(row_lengths), chunk_size);
271 }
272 
273 
274 
275 namespace internal
276 {
277  namespace
278  {
279  template <typename SparsityPatternType>
280  void copy_sparsity (const SparsityPatternType &src,
281  SparsityPattern &dst)
282  {
283  dst.copy_from(src);
284  }
285 
286  void copy_sparsity (const SparsityPattern &src,
287  SparsityPattern &dst)
288  {
289  dst = src;
290  }
291  }
292 }
293 
294 
295 
296 template <typename Sparsity>
297 void
299 (const unsigned int m,
300  const unsigned int n,
301  const Sparsity &sparsity_pattern_for_chunks,
302  const unsigned int chunk_size_in,
303  const bool)
304 {
305  Assert (m > (sparsity_pattern_for_chunks.n_rows()-1) * chunk_size_in &&
306  m <= sparsity_pattern_for_chunks.n_rows() * chunk_size_in,
307  ExcMessage("Number of rows m is not compatible with chunk size "
308  "and number of rows in sparsity pattern for the chunks."));
309  Assert (n > (sparsity_pattern_for_chunks.n_cols()-1) * chunk_size_in &&
310  n <= sparsity_pattern_for_chunks.n_cols() * chunk_size_in,
311  ExcMessage("Number of columns m is not compatible with chunk size "
312  "and number of columns in sparsity pattern for the chunks."));
313 
314  internal::copy_sparsity(sparsity_pattern_for_chunks, sparsity_pattern);
315  chunk_size = chunk_size_in;
316  rows = m;
317  cols = n;
318 }
319 
320 
321 
322 bool
324 {
325  return sparsity_pattern.empty();
326 }
327 
328 
329 
332 {
334 }
335 
336 
337 
338 void
340  const size_type j)
341 {
342  Assert (i<rows, ExcInvalidIndex(i,rows));
343  Assert (j<cols, ExcInvalidIndex(j,cols));
344 
346 }
347 
348 
349 bool
351  const size_type j) const
352 {
353  Assert (i<rows, ExcIndexRange(i,0,rows));
354  Assert (j<cols, ExcIndexRange(j,0,cols));
355 
357  j/chunk_size);
358 }
359 
360 
361 
362 void
364 {
365  // matrix must be square. note that the for some matrix sizes, the current
366  // sparsity pattern may not be square even if the underlying sparsity
367  // pattern is (e.g. a 10x11 matrix with chunk_size 4)
368  Assert (rows==cols, ExcNotQuadratic());
369 
371 }
372 
373 
374 
377 {
378  Assert (i<rows, ExcIndexRange(i,0,rows));
379 
380  // find out if we did padding and if this row is affected by it
381  if (n_cols() % chunk_size == 0)
383  else
384  // if columns don't align, then just iterate over all chunks and see
385  // what this leads to
386  {
389  unsigned int n = 0;
390  for ( ; p != end; ++p)
391  if (p->column() != sparsity_pattern.n_cols() - 1)
392  n += chunk_size;
393  else
394  n += (n_cols() % chunk_size);
395  return n;
396  }
397 }
398 
399 
400 
403 {
404  if ((n_rows() % chunk_size == 0)
405  &&
406  (n_cols() % chunk_size == 0))
408  chunk_size *
409  chunk_size);
410  else
411  // some of the chunks reach beyond the extent of this matrix. this
412  // requires a somewhat more complicated computations, in particular if the
413  // columns don't align
414  {
415  if ((n_rows() % chunk_size != 0)
416  &&
417  (n_cols() % chunk_size == 0))
418  {
419  // columns align with chunks, but not rows
421  chunk_size *
422  chunk_size;
423  n -= (sparsity_pattern.n_rows() * chunk_size - n_rows()) *
425  chunk_size;
426  return n;
427  }
428 
429  else
430  {
431  // if columns don't align, then just iterate over all chunks and see
432  // what this leads to. follow the advice in the documentation of the
433  // sparsity pattern iterators to do the loop over individual rows,
434  // rather than all elements
435  size_type n = 0;
436 
437  for (size_type row = 0; row < sparsity_pattern.n_rows(); ++row)
438  {
440  for (; p!=sparsity_pattern.end(row); ++p)
441  if ((row != sparsity_pattern.n_rows() - 1)
442  &&
443  (p->column() != sparsity_pattern.n_cols() - 1))
444  n += chunk_size * chunk_size;
445  else if ((row == sparsity_pattern.n_rows() - 1)
446  &&
447  (p->column() != sparsity_pattern.n_cols() - 1))
448  // last chunk row, but not last chunk column. only a smaller
449  // number (n_rows % chunk_size) of rows actually exist
450  n += (n_rows() % chunk_size) * chunk_size;
451  else if ((row != sparsity_pattern.n_rows() - 1)
452  &&
453  (p->column() == sparsity_pattern.n_cols() - 1))
454  // last chunk column, but not row
455  n += (n_cols() % chunk_size) * chunk_size;
456  else
457  // bottom right chunk
458  n += (n_cols() % chunk_size) *
459  (n_rows() % chunk_size);
460  }
461 
462  return n;
463  }
464  }
465 }
466 
467 
468 
469 void
470 ChunkSparsityPattern::print (std::ostream &out) const
471 {
473  ExcEmptyObject());
474 
475  AssertThrow (out, ExcIO());
476 
477  for (size_type i=0; i<sparsity_pattern.rows; ++i)
478  for (size_type d=0;
479  (d<chunk_size) && (i*chunk_size + d < n_rows());
480  ++d)
481  {
482  out << '[' << i *chunk_size+d;
484  j<sparsity_pattern.rowstart[i+1]; ++j)
486  for (size_type e=0;
487  ((e<chunk_size) &&
489  ++e)
490  out << ',' << sparsity_pattern.colnums[j]*chunk_size+e;
491  out << ']' << std::endl;
492  }
493 
494  AssertThrow (out, ExcIO());
495 }
496 
497 
498 
499 void
500 ChunkSparsityPattern::print_gnuplot (std::ostream &out) const
501 {
503  (sparsity_pattern.colnums!=0), ExcEmptyObject());
504 
505  AssertThrow (out, ExcIO());
506 
507  // for each entry in the underlying sparsity pattern, repeat everything
508  // chunk_size x chunk_size times
509  for (size_type i=0; i<sparsity_pattern.rows; ++i)
511  j<sparsity_pattern.rowstart[i+1]; ++j)
513  for (size_type d=0;
514  ((d<chunk_size) &&
516  ++d)
517  for (size_type e=0;
518  (e<chunk_size) && (i*chunk_size + e < n_rows());
519  ++e)
520  // while matrix entries are usually written (i,j), with i vertical
521  // and j horizontal, gnuplot output is x-y, that is we have to
522  // exchange the order of output
523  out << sparsity_pattern.colnums[j]*chunk_size+d << " "
524  << -static_cast<signed int>(i*chunk_size+e)
525  << std::endl;
526 
527  AssertThrow (out, ExcIO());
528 }
529 
530 
531 
534 {
535  // calculate the bandwidth from that of the underlying sparsity
536  // pattern. note that even if the bandwidth of that is zero, then the
537  // bandwidth of the chunky pattern is chunk_size-1, if it is 1 then the
538  // chunky pattern has chunk_size+(chunk_size-1), etc
539  //
540  // we'll cut it off at max(n(),m())
541  return std::min (sparsity_pattern.bandwidth()*chunk_size
542  + (chunk_size-1),
543  std::max(n_rows(), n_cols()));
544 }
545 
546 
547 
548 bool
550 {
551  if (chunk_size == 1)
553  else
554  return false;
555 }
556 
557 
558 
559 void
560 ChunkSparsityPattern::block_write (std::ostream &out) const
561 {
562  AssertThrow (out, ExcIO());
563 
564  // first the simple objects, bracketed in [...]
565  out << '['
566  << rows << ' '
567  << cols << ' '
568  << chunk_size << ' '
569  << "][";
570  // then the underlying sparsity pattern
572  out << ']';
573 
574  AssertThrow (out, ExcIO());
575 }
576 
577 
578 
579 void
581 {
582  AssertThrow (in, ExcIO());
583 
584  char c;
585 
586  // first read in simple data
587  in >> c;
588  AssertThrow (c == '[', ExcIO());
589  in >> rows
590  >> cols
591  >> chunk_size;
592 
593  in >> c;
594  AssertThrow (c == ']', ExcIO());
595  in >> c;
596  AssertThrow (c == '[', ExcIO());
597 
598  // then read the underlying sparsity pattern
600 
601  in >> c;
602  AssertThrow (c == ']', ExcIO());
603 }
604 
605 
606 
607 std::size_t
609 {
610  return (sizeof(*this) +
612 }
613 
614 
615 
616 // explicit instantiations
617 template
618 void ChunkSparsityPattern::copy_from<DynamicSparsityPattern> (const DynamicSparsityPattern &,
619  const size_type);
620 template
621 void ChunkSparsityPattern::create_from<SparsityPattern>
622 (const unsigned int,
623  const unsigned int,
624  const SparsityPattern &,
625  const unsigned int,
626  const bool);
627 template
628 void ChunkSparsityPattern::create_from<DynamicSparsityPattern>
629 (const unsigned int,
630  const unsigned int,
631  const DynamicSparsityPattern &,
632  const unsigned int,
633  const bool);
634 template
635 void ChunkSparsityPattern::copy_from<float> (const FullMatrix<float> &,
636  const size_type);
637 template
638 void ChunkSparsityPattern::copy_from<double> (const FullMatrix<double> &,
639  const size_type);
640 
641 DEAL_II_NAMESPACE_CLOSE
void block_write(std::ostream &out) const
size_type m() const
void block_write(std::ostream &out) const
void copy_from(const size_type n_rows, const size_type n_cols, const ForwardIterator begin, const ForwardIterator end, const size_type chunk_size)
std::size_t memory_consumption() const
static const size_type invalid_entry
void add(const size_type i, const size_type j)
::ExceptionBase & ExcMessage(std::string arg1)
iterator end() const
std::size_t memory_consumption() const
void block_read(std::istream &in)
iterator end() const
bool exists(const size_type i, const size_type j) const
bool exists(const size_type i, const size_type j) const
bool empty() const
#define AssertThrow(cond, exc)
Definition: exceptions.h:358
void add(const size_type i, const size_type j)
size_type n_cols() const
SparsityPattern sparsity_pattern
size_type n_rows() const
size_type bandwidth() const
size_type n_cols() const
size_type n() const
void add(const size_type i, const size_type j)
#define Assert(cond, exc)
Definition: exceptions.h:294
size_type row_length(const size_type row) const
size_type n_rows() const
size_type max_entries_per_row() const
size_type n_nonzero_elements() const
void copy_from(const size_type n_rows, const size_type n_cols, const ForwardIterator begin, const ForwardIterator end)
size_type n_nonzero_elements() const
ChunkSparsityPattern & operator=(const ChunkSparsityPattern &)
void reinit(const size_type m, const size_type n, const unsigned int max_per_row)
std::size_t * rowstart
types::global_dof_index size_type
bool stores_only_added_elements() const
void block_read(std::istream &in)
iterator begin() const
void print(std::ostream &out) const
void create_from(const unsigned int m, const unsigned int n, const Sparsity &sparsity_pattern_for_chunks, const unsigned int chunk_size, const bool optimize_diagonal=true)
void print_gnuplot(std::ostream &out) const
void reinit(const size_type m, const size_type n, const size_type max_per_row, const size_type chunk_size)
unsigned int row_length(const size_type row) const
size_type max_entries_per_row() const