#include <deal.II/base/utilities.h>
#include <deal.II/lac/exceptions.h>
+#include <deal.II/lac/sparsity_pattern_base.h>
#include <algorithm>
#include <iostream>
* sp.copy_from (dynamic_pattern);
* @endcode
*/
-class DynamicSparsityPattern : public Subscriptor
+class DynamicSparsityPattern : public SparsityPatternBase
{
public:
/**
ForwardIterator end,
const bool indices_are_unique_and_sorted = false);
+ virtual void
+ add_row_entries(const size_type & row,
+ const ArrayView<const size_type> &columns,
+ const bool indices_are_sorted = false) override;
+
+ virtual void
+ add_entries(const ArrayView<const size_type> &rows,
+ const ArrayView<const size_type> &columns) override;
+
/**
* Check if a value at a certain position may be non-zero.
*/
void
print_gnuplot(std::ostream &out) const;
- /**
- * Return the number of rows, which equals the dimension of the image space.
- */
- size_type
- n_rows() const;
-
- /**
- * Return the number of columns, which equals the dimension of the range
- * space.
- */
- size_type
- n_cols() const;
-
/**
* Number of entries in a specific row. This function can only be called if
* the given row is a member of the index set of rows that we want to store.
*/
bool have_entries;
- /**
- * Number of rows that this sparsity structure shall represent.
- */
- size_type rows;
-
- /**
- * Number of columns that this sparsity structure shall represent.
- */
- size_type cols;
-
/**
* A set that contains the valid rows.
*/
-inline DynamicSparsityPattern::size_type
-DynamicSparsityPattern::n_rows() const
-{
- return rows;
-}
-
-
-
-inline types::global_dof_index
-DynamicSparsityPattern::n_cols() const
-{
- return cols;
-}
-
-
-
inline void
DynamicSparsityPattern::add(const size_type i, const size_type j)
{
- AssertIndexRange(i, rows);
- AssertIndexRange(j, cols);
+ AssertIndexRange(i, n_rows());
+ AssertIndexRange(j, n_cols());
if (rowset.size() > 0 && !rowset.is_element(i))
return;
#include <deal.II/base/linear_index_iterator.h>
#include <deal.II/base/subscriptor.h>
+#include <deal.II/lac/sparsity_pattern_base.h>
+
// boost::serialization::make_array used to be in array.hpp, but was
// moved to a different file in BOOST 1.64
#include <boost/version.hpp>
* SparsityPatternIterators::Accessor, like <tt>it->column()</tt> and
* <tt>it->row()</tt>.
*/
-class SparsityPattern : public Subscriptor
+class SparsityPattern : public SparsityPatternBase
{
public:
/**
ForwardIterator end,
const bool indices_are_sorted = false);
+ virtual void
+ add_row_entries(const size_type & row,
+ const ArrayView<const size_type> &columns,
+ const bool indices_are_sorted = false) override;
+
+ virtual void
+ add_entries(const ArrayView<const size_type> &rows,
+ const ArrayView<const size_type> &columns) override;
+
+
/**
* Make the sparsity pattern symmetric by adding the sparsity pattern of the
* transpose object.
std::size_t
n_nonzero_elements() const;
- /**
- * Return number of rows of this matrix, which equals the dimension of the
- * image space.
- */
- size_type
- n_rows() const;
-
- /**
- * Return number of columns of this matrix, which equals the dimension of
- * the range space.
- */
- size_type
- n_cols() const;
-
/**
* Return whether the object is empty. It is empty if no memory is
* allocated, which is the same as that both dimensions are zero.
*/
size_type max_dim;
- /**
- * Number of rows that this sparsity structure shall represent.
- */
- size_type rows;
-
- /**
- * Number of columns that this sparsity structure shall represent.
- */
- size_type cols;
-
/**
* Size of the actually allocated array #colnums. Here, the same applies as
* for the #rowstart array, i.e. it may be larger than the actually used
-inline SparsityPattern::size_type
-SparsityPattern::n_rows() const
-{
- return rows;
-}
-
-
-
-inline SparsityPattern::size_type
-SparsityPattern::n_cols() const
-{
- return cols;
-}
-
-
-
inline bool
SparsityPattern::is_compressed() const
{
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2022 - 2022 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+#ifndef dealii_sparsity_pattern_base_h
+#define dealii_sparsity_pattern_base_h
+
+
+#include <deal.II/base/config.h>
+
+#include <deal.II/base/array_view.h>
+#include <deal.II/base/exceptions.h>
+#include <deal.II/base/subscriptor.h>
+
+DEAL_II_NAMESPACE_OPEN
+
+/**
+ * @addtogroup Sparsity
+ * @{
+ */
+
+/**
+ * Base class for all sparsity patterns, defining a common interface by which
+ * new values can be added.
+ */
+class SparsityPatternBase : public Subscriptor
+{
+public:
+ /**
+ * Declare type for container size.
+ */
+ using size_type = types::global_dof_index;
+
+ /**
+ * Constructor. Sets up an empty (zero-by-zero) sparsity pattern.
+ */
+ SparsityPatternBase();
+
+ /**
+ * Constructor. Sets up a @p rows by @p cols sparsity pattern.
+ */
+ SparsityPatternBase(const size_type rows, const size_type cols);
+
+ /**
+ * Copy constructor.
+ */
+ SparsityPatternBase(const SparsityPatternBase &sparsity_pattern) = default;
+
+ /**
+ * Move constructor.
+ */
+ SparsityPatternBase(SparsityPatternBase &&sparsity_pattern) noexcept =
+ default;
+
+ /**
+ * Assignment operator.
+ */
+ SparsityPatternBase &
+ operator=(const SparsityPatternBase &sparsity_pattern) = default;
+
+ /**
+ * Move assignment operator.
+ */
+ SparsityPatternBase &
+ operator=(SparsityPatternBase &&sparsity_pattern) noexcept = default;
+
+ /**
+ * Return number of rows of this matrix, which equals the dimension of the
+ * image space.
+ */
+ size_type
+ n_rows() const;
+
+ /**
+ * Return number of columns of this matrix, which equals the dimension of
+ * the range space.
+ */
+ size_type
+ n_cols() const;
+
+ /**
+ * Optimized function for adding new entries to a given row.
+ */
+ virtual void
+ add_row_entries(const size_type & row,
+ const ArrayView<const size_type> &columns,
+ const bool indices_are_sorted = false) = 0;
+
+ /**
+ * General function for adding new entries. By default this function calls
+ * add_row_entries() for each new entry: inheriting classes may want to add a
+ * more optimized implementation.
+ */
+ virtual void
+ add_entries(const ArrayView<const size_type> &rows,
+ const ArrayView<const size_type> &columns);
+
+protected:
+ /**
+ * Internal function for updating the stored size of the sparsity pattern.
+ */
+ virtual void
+ resize(const size_type rows, const size_type cols);
+
+ /**
+ * Number of rows that this sparsity pattern shall represent.
+ */
+ size_type rows;
+
+ /**
+ * Number of columns that this sparsity pattern shall represent.
+ */
+ size_type cols;
+};
+
+/**
+ * @}
+ */
+
+
+/* ---------------------------- Inline functions ---------------------------- */
+
+#ifndef DOXYGEN
+
+inline SparsityPatternBase::SparsityPatternBase()
+ : rows(0)
+ , cols(0)
+{}
+
+
+
+inline SparsityPatternBase::SparsityPatternBase(const size_type rows,
+ const size_type cols)
+ : rows(rows)
+ , cols(cols)
+{}
+
+
+
+inline SparsityPatternBase::size_type
+SparsityPatternBase::n_rows() const
+{
+ return rows;
+}
+
+
+
+inline SparsityPatternBase::size_type
+SparsityPatternBase::n_cols() const
+{
+ return cols;
+}
+
+
+
+inline void
+SparsityPatternBase::add_entries(const ArrayView<const size_type> &rows,
+ const ArrayView<const size_type> &columns)
+{
+ AssertDimension(rows.size(), columns.size());
+ for (std::size_t i = 0; i < rows.size(); ++i)
+ add_row_entries(rows[i],
+ make_array_view(columns.begin() + i,
+ columns.begin() + i + 1));
+}
+
+
+
+inline void
+SparsityPatternBase::resize(const size_type rows, const size_type cols)
+{
+ this->rows = rows;
+ this->cols = cols;
+}
+#endif
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif
DynamicSparsityPattern::DynamicSparsityPattern()
- : have_entries(false)
- , rows(0)
- , cols(0)
+ : SparsityPatternBase()
+ , have_entries(false)
, rowset(0)
{}
DynamicSparsityPattern::DynamicSparsityPattern(const DynamicSparsityPattern &s)
- : Subscriptor()
+ : SparsityPatternBase()
, have_entries(false)
- , rows(0)
- , cols(0)
, rowset(0)
{
(void)s;
DynamicSparsityPattern::DynamicSparsityPattern(const size_type m,
const size_type n,
const IndexSet &rowset_)
- : have_entries(false)
- , rows(0)
- , cols(0)
+ : SparsityPatternBase()
+ , have_entries(false)
, rowset(0)
{
reinit(m, n, rowset_);
DynamicSparsityPattern::DynamicSparsityPattern(const IndexSet &rowset_)
- : have_entries(false)
- , rows(0)
- , cols(0)
+ : SparsityPatternBase()
+ , have_entries(false)
, rowset(0)
{
reinit(rowset_.size(), rowset_.size(), rowset_);
DynamicSparsityPattern::DynamicSparsityPattern(const size_type n)
- : have_entries(false)
- , rows(0)
- , cols(0)
+ : SparsityPatternBase()
+ , have_entries(false)
, rowset(0)
{
reinit(n, n);
DynamicSparsityPattern::operator=(const DynamicSparsityPattern &s)
{
(void)s;
- Assert(s.rows == 0 && s.cols == 0,
+ Assert(s.n_rows() == 0 && s.n_cols() == 0,
ExcMessage(
"This operator can only be called if the provided argument "
"is the sparsity pattern for an empty matrix. This operator can "
"not be used to copy a non-empty sparsity pattern."));
- Assert(rows == 0 && cols == 0,
+ Assert(n_rows() == 0 && n_cols() == 0,
ExcMessage("This operator can only be called if the current object is "
"empty."));
const size_type n,
const IndexSet &rowset_)
{
+ resize(m, n);
have_entries = false;
- rows = m;
- cols = n;
rowset = rowset_;
Assert(rowset.size() == 0 || rowset.size() == m,
"of indices in this IndexSet may be less than the number "
"of rows, but the *size* of the IndexSet must be equal.)"));
- std::vector<Line> new_lines(rowset.size() == 0 ? rows : rowset.n_elements());
+ std::vector<Line> new_lines(rowset.size() == 0 ? n_rows() :
+ rowset.n_elements());
lines.swap(new_lines);
}
+void
+DynamicSparsityPattern::add_row_entries(
+ const size_type & row,
+ const ArrayView<const size_type> &columns,
+ const bool indices_are_sorted)
+{
+ add_entries(row, columns.begin(), columns.end(), indices_are_sorted);
+}
+
+
+
+void
+DynamicSparsityPattern::add_entries(const ArrayView<const size_type> &rows,
+ const ArrayView<const size_type> &columns)
+{
+ AssertDimension(rows.size(), columns.size());
+ for (std::size_t i = 0; i < rows.size(); ++i)
+ add(rows[i], columns[i]);
+}
+
+
+
bool
DynamicSparsityPattern::exists(const size_type i, const size_type j) const
{
SparsityPattern::SparsityPattern()
- : store_diagonal_first_in_row(false)
+ : SparsityPatternBase()
+ , store_diagonal_first_in_row(false)
, max_dim(0)
- , rows(0)
- , cols(0)
, max_vec_len(0)
, max_row_length(0)
, compressed(false)
const size_type extra_off_diagonals)
: SparsityPattern()
{
- Assert(original.rows == original.cols, ExcNotQuadratic());
+ Assert(original.n_rows() == original.n_cols(), ExcNotQuadratic());
Assert(original.is_compressed(), ExcNotCompressed());
- reinit(original.rows, original.cols, max_per_row);
+ reinit(original.n_rows(), original.n_cols(), max_per_row);
// now copy the entries from the other object
for (size_type row = 0; row < original.rows; ++row)
const ArrayView<const unsigned int> &row_lengths)
{
AssertDimension(row_lengths.size(), m);
-
- rows = m;
- cols = n;
+ resize(m, n);
// delete empty matrices
if ((m == 0) || (n == 0))
rowstart.reset();
colnums.reset();
- max_vec_len = max_dim = rows = cols = 0;
+ max_vec_len = max_dim = 0;
// if dimension is zero: ignore max_per_row
max_row_length = 0;
compressed = false;
// if diagonal elements are special: let the first entry in each row be the
// diagonal value
if (store_diagonal_first_in_row)
- for (size_type i = 0; i < rows; ++i)
+ for (size_type i = 0; i < n_rows(); ++i)
colnums[rowstart[i]] = i;
compressed = false;
std::vector<size_type> tmp_entries(max_row_length);
// Traverse all rows
- for (size_type line = 0; line < rows; ++line)
+ for (size_type line = 0; line < n_rows(); ++line)
{
// copy used entries, break if first unused entry is reached
row_length = 0;
// and freeing memory was not present in the original implementation and I
// don't know at how many places I missed something in adding it, so I try
// to be cautious. wb)
- if ((rowstart == nullptr) || (rows == 0) || (cols == 0))
+ if ((rowstart == nullptr) || (n_rows() == 0) || (n_cols() == 0))
{
Assert(rowstart == nullptr, ExcInternalError());
- Assert(rows == 0, ExcInternalError());
- Assert(cols == 0, ExcInternalError());
+ Assert(n_rows() == 0, ExcInternalError());
+ Assert(n_cols() == 0, ExcInternalError());
Assert(colnums == nullptr, ExcInternalError());
Assert(max_vec_len == 0, ExcInternalError());
SparsityPattern::exists(const size_type i, const size_type j) const
{
Assert((rowstart != nullptr) && (colnums != nullptr), ExcEmptyObject());
- AssertIndexRange(i, rows);
- AssertIndexRange(j, cols);
+ AssertIndexRange(i, n_rows());
+ AssertIndexRange(j, n_cols());
for (size_type k = rowstart[i]; k < rowstart[i + 1]; ++k)
{
{
Assert((rowstart != nullptr) && (colnums != nullptr), ExcEmptyObject());
size_type b = 0;
- for (size_type i = 0; i < rows; ++i)
+ for (size_type i = 0; i < n_rows(); ++i)
for (size_type j = rowstart[i]; j < rowstart[i + 1]; ++j)
if (colnums[j] != invalid_entry)
{
SparsityPattern::operator()(const size_type i, const size_type j) const
{
Assert((rowstart != nullptr) && (colnums != nullptr), ExcEmptyObject());
- AssertIndexRange(i, rows);
- AssertIndexRange(j, cols);
+ AssertIndexRange(i, n_rows());
+ AssertIndexRange(j, n_cols());
Assert(compressed, ExcNotCompressed());
// let's see whether there is something in this line
SparsityPattern::add(const size_type i, const size_type j)
{
Assert((rowstart != nullptr) && (colnums != nullptr), ExcEmptyObject());
- AssertIndexRange(i, rows);
- AssertIndexRange(j, cols);
+ AssertIndexRange(i, n_rows());
+ AssertIndexRange(j, n_cols());
Assert(compressed == false, ExcMatrixIsCompressed());
for (std::size_t k = rowstart[i]; k < rowstart[i + 1]; ++k)
+void
+SparsityPattern::add_row_entries(const size_type & row,
+ const ArrayView<const size_type> &columns,
+ const bool indices_are_sorted)
+{
+ add_entries(row, columns.begin(), columns.end(), indices_are_sorted);
+}
+
+
+
+void
+SparsityPattern::add_entries(const ArrayView<const size_type> &rows,
+ const ArrayView<const size_type> &columns)
+{
+ AssertDimension(rows.size(), columns.size());
+ for (std::size_t i = 0; i < rows.size(); ++i)
+ add(rows[i], columns[i]);
+}
+
+
+
void
SparsityPattern::symmetrize()
{
Assert(compressed == false, ExcMatrixIsCompressed());
// Note that we only require a quadratic matrix here, no special treatment
// of diagonals
- Assert(rows == cols, ExcNotQuadratic());
+ Assert(n_rows() == n_cols(), ExcNotQuadratic());
// loop over all elements presently in the sparsity pattern and add the
// transpose element. note:
//
// 2. that the @p{add} function can be called on elements that already exist
// without any harm
- for (size_type row = 0; row < rows; ++row)
+ for (size_type row = 0; row < n_rows(); ++row)
for (size_type k = rowstart[row]; k < rowstart[row + 1]; ++k)
{
// check whether we are at the end of the entries of this row. if so,
SparsityPattern::row_position(const size_type i, const size_type j) const
{
Assert((rowstart != nullptr) && (colnums != nullptr), ExcEmptyObject());
- AssertIndexRange(i, rows);
- AssertIndexRange(j, cols);
+ AssertIndexRange(i, n_rows());
+ AssertIndexRange(j, n_cols());
for (size_type k = rowstart[i]; k < rowstart[i + 1]; ++k)
{
AssertThrow(out.fail() == false, ExcIO());
- for (size_type i = 0; i < rows; ++i)
+ for (size_type i = 0; i < n_rows(); ++i)
{
out << '[' << i;
for (size_type j = rowstart[i]; j < rowstart[i + 1]; ++j)
AssertThrow(out.fail() == false, ExcIO());
- for (size_type i = 0; i < rows; ++i)
+ for (size_type i = 0; i < n_rows(); ++i)
for (size_type j = rowstart[i]; j < rowstart[i + 1]; ++j)
if (colnums[j] != invalid_entry)
// while matrix entries are usually written (i,j), with i vertical and
AssertThrow(out.fail() == false, ExcIO());
// first the simple objects, bracketed in [...]
- out << '[' << max_dim << ' ' << rows << ' ' << cols << ' ' << max_vec_len
- << ' ' << max_row_length << ' ' << compressed << ' '
+ out << '[' << max_dim << ' ' << n_rows() << ' ' << n_cols() << ' '
+ << max_vec_len << ' ' << max_row_length << ' ' << compressed << ' '
<< store_diagonal_first_in_row << "][";
// then write out real data
out.write(reinterpret_cast<const char *>(rowstart.get()),