21template <
class From,
class To>
39 throw std::invalid_argument(
"Nonsquare matrix cannot be symmetric");
45 if (
to.data() !=
from.data())
50template <Config Conf,
class StorageIndex>
57#if ALPAQA_HAVE_COO_CSC_CONVERSIONS
58 assert(util::check_uniqueness_csc(
from.outer_ptr,
from.inner_idx));
61 throw std::invalid_argument(
"Nonsquare matrix cannot be symmetric");
65 .symmetry =
from.symmetry,
76 auto &&
T =
to.reshaped(sparsity.
rows, sparsity.
cols);
87 throw std::invalid_argument(
88 "Invalid symmetric CSC matrix: upper-triangular matrix should not "
89 "have elements below the diagonal");
90 T(c, r) =
T(r, c) =
from(l);
94 throw std::invalid_argument(
95 "Invalid symmetric CSC matrix: lower-triangular matrix should not "
96 "have elements above the diagonal");
97 T(c, r) =
T(r, c) =
from(l);
99 default:
throw std::invalid_argument(
"Invalid symmetry");
107template <Config Conf,
class StorageIndex>
114#if ALPAQA_HAVE_COO_CSC_CONVERSIONS
115 assert(util::check_uniqueness_triplets(
from.row_indices,
from.col_indices));
118 throw std::invalid_argument(
"Nonsquare matrix cannot be symmetric");
122 .symmetry =
from.symmetry,
133 auto &&
T =
to.reshaped(sparsity.
rows, sparsity.
cols);
134 for (
index_t l = 0; l < from_sparsity.
nnz(); ++l) {
141 throw std::invalid_argument(
142 "Invalid symmetric COO matrix: upper-triangular matrix should not "
143 "have elements below the diagonal");
144 T(c, r) =
T(r, c) =
from(l);
148 throw std::invalid_argument(
149 "Invalid symmetric COO matrix: lower-triangular matrix should not "
150 "have elements above the diagonal");
151 T(c, r) =
T(r, c) =
from(l);
153 default:
throw std::invalid_argument(
"Invalid symmetry");
159template <Config Conf,
class StorageIndex>
162 std::optional<StorageIndex> first_index = std::nullopt;
165template <Config Conf,
class StorageIndex>
177 switch (
from.symmetry) {
180 row_indices.resize(nnz);
181 col_indices.resize(nnz);
193 throw std::invalid_argument(
"Nonsquare matrix cannot be symmetric");
195 row_indices.resize(nnz);
196 col_indices.resize(nnz);
199 for (
index_t r = 0; r <= c; ++r) {
207 throw std::invalid_argument(
"Lower-triangular symmetry currently not supported");
208 default:
throw std::invalid_argument(
"Invalid symmetry");
213 .symmetry =
from.symmetry,
214 .row_indices = row_indices,
215 .col_indices = col_indices,
216 .order = to_sparsity_t::SortedByColsAndRows,
228 if (
to.data() !=
from.data())
234 std::ranges::copy_backward(
F.col(c).topRows(c + 1), t += c + 1);
239template <Config Conf,
class StorageIndexFrom,
class StorageIndexTo>
251 row_indices.resize(
from.nnz());
252 col_indices.resize(
from.nnz());
258 auto r =
from.inner_idx(i);
267 .symmetry =
from.symmetry,
268 .row_indices = row_indices,
269 .col_indices = col_indices,
270 .order =
from.order == from_sparsity_t::SortedRows ? to_sparsity_t::SortedByColsAndRows
271 : to_sparsity_t::SortedByColsOnly,
277#if ALPAQA_HAVE_COO_CSC_CONVERSIONS
278 assert(util::check_uniqueness_triplets(sparsity.row_indices, sparsity.col_indices));
286 if (
to.data() !=
from.data())
291template <Config Conf,
class StorageIndexFrom,
class StorageIndexTo>
304 if constexpr (std::is_same_v<StorageIndexFrom, StorageIndexTo>)
308 row_indices.resize(
from.nnz());
309 col_indices.resize(
from.nnz());
311 std::ranges::transform(
from.row_indices, row_indices.begin(),
cvt_idx);
312 std::ranges::transform(
from.col_indices, col_indices.begin(),
cvt_idx);
316 .symmetry =
from.symmetry,
317 .row_indices = row_indices,
318 .col_indices = col_indices,
326#if ALPAQA_HAVE_COO_CSC_CONVERSIONS
327 assert(util::check_uniqueness_triplets(sparsity.row_indices, sparsity.col_indices));
335 if (
to.data() !=
from.data())
340template <Config Conf,
class StorageIndex>
343 std::optional<typename SparseCSC<Conf, StorageIndex>::Order> order = std::nullopt;
346template <Config Conf,
class StorageIndexFrom,
class StorageIndexFromTo>
356#if ALPAQA_HAVE_COO_CSC_CONVERSIONS
362 std::ranges::transform(
from.row_indices, row_indices.begin(),
cvt_idx);
363 std::ranges::transform(
from.col_indices, col_indices.begin(),
cvt_idx);
366 if (
request.order && *
request.order == to_sparsity_t::SortedRows) {
367 order = to_sparsity_t::SortedRows;
368 switch (
from.order) {
369 case from_sparsity_t::SortedByColsAndRows:
373 case from_sparsity_t::SortedByColsOnly: [[
fallthrough]];
374 case from_sparsity_t::SortedByRowsAndCols: [[
fallthrough]];
375 case from_sparsity_t::SortedByRowsOnly:
376 permutation.resize(
from.nnz());
377 std::iota(permutation.begin(), permutation.end(),
index_t{0});
378 util::sort_triplets(row_indices, col_indices, permutation);
380 default:
throw std::invalid_argument(
"Invalid order");
383 switch (
from.order) {
384 case from_sparsity_t::SortedByColsAndRows:
385 order = to_sparsity_t::SortedRows;
388 case from_sparsity_t::SortedByColsOnly:
389 order = to_sparsity_t::Unsorted;
393 case from_sparsity_t::SortedByRowsAndCols: [[
fallthrough]];
394 case from_sparsity_t::SortedByRowsOnly:
395 order = to_sparsity_t::Unsorted;
396 permutation.resize(
from.nnz());
397 std::iota(permutation.begin(), permutation.end(),
index_t{0});
398 util::sort_triplets_col(row_indices, col_indices, permutation);
400 default:
throw std::invalid_argument(
"Invalid order");
404 if (std::ranges::is_sorted(permutation))
407 inner_idx.resize(
from.nnz());
408 outer_ptr.resize(
from.cols + 1);
409 util::convert_triplets_to_ccs(row_indices, col_indices, inner_idx, outer_ptr,
414 .symmetry =
from.symmetry,
415 .inner_idx = inner_idx,
416 .outer_ptr = outer_ptr,
420 throw std::runtime_error(
421 "This build of alpaqa does not support conversions from sparse COO format to CSC "
422 "format. Please recompile with a C++23-compliant compiler.");
427#if ALPAQA_HAVE_COO_CSC_CONVERSIONS
428 assert(util::check_uniqueness_csc(sparsity.outer_ptr, sparsity.inner_idx));
437 if (permutation.size() > 0) {
441 if (
to.data() !=
from.data())
447template <Config Conf,
class StorageIndexFrom,
class StorageIndexTo>
459 inner_idx.resize(
from.inner_idx.size());
460 std::ranges::transform(
from.inner_idx, inner_idx.begin(),
cvt_idx);
461 outer_ptr.resize(
from.outer_ptr.size());
462 std::ranges::transform(
from.outer_ptr, outer_ptr.begin(),
cvt_idx);
465#if ALPAQA_HAVE_COO_CSC_CONVERSIONS
467 permutation.resize(
from.nnz());
468 std::iota(permutation.begin(), permutation.end(),
index_t{0});
469 util::sort_rows_csc(outer_ptr, inner_idx, permutation);
471 throw std::runtime_error(
472 "This build of alpaqa does not support sorting matrices in CSC format. "
473 "Please recompile with a C++23-compliant compiler.");
478 auto order =
static_cast<Order
>(
from.order);
480 if (
request.order && *
request.order == to_sparsity_t::SortedRows) {
481 order = to_sparsity_t::SortedRows;
482 switch (
from.order) {
483 case from_sparsity_t::Unsorted:
need_sorting =
true;
break;
484 case from_sparsity_t::SortedRows:
need_sorting =
false;
break;
485 default:
throw std::invalid_argument(
"Invalid order");
491 else if (!std::is_same_v<StorageIndexFrom, StorageIndexTo>)
494 if (std::ranges::is_sorted(permutation))
497 if constexpr (std::is_same_v<StorageIndexFrom, StorageIndexTo>)
501 .symmetry =
from.symmetry,
511 .symmetry =
from.symmetry,
512 .inner_idx = inner_idx,
513 .outer_ptr = outer_ptr,
519#if ALPAQA_HAVE_COO_CSC_CONVERSIONS
520 assert(util::check_uniqueness_csc(sparsity.outer_ptr, sparsity.inner_idx));
529 if (permutation.size() > 0) {
533 if (
to.data() !=
from.data())
539template <Config Conf,
class StorageIndex>
550 switch (
from.symmetry) {
552 inner_idx.resize(
from.rows *
from.cols);
553 outer_ptr.resize(
from.cols + 1);
566 throw std::invalid_argument(
"Nonsquare matrix cannot be symmetric");
567 inner_idx.resize(
from.rows * (
from.rows + 1) / 2);
568 outer_ptr.resize(
from.cols + 1);
572 for (
index_t r = 0; r <= c; ++r) {
580 throw std::invalid_argument(
"Lower-triangular symmetry currently not supported");
581 default:
throw std::invalid_argument(
"Invalid symmetry");
586 .symmetry =
from.symmetry,
587 .inner_idx = inner_idx,
588 .outer_ptr = outer_ptr,
589 .order = to_sparsity_t::SortedRows,
600 if (
to.data() !=
from.data())
606 std::ranges::copy_backward(
F.col(c).topRows(c + 1), t += c + 1);
612template <
class To,
class>
615template <
class To,
class...
Froms>
617 using type = std::variant<SparsityConverter<Froms, To>...>;
627template <
class Conf,
class To>
628 requires std::same_as<Conf, typename To::config_t>
638 return std::visit([](
const auto &c) ->
const to_sparsity_t & {
return c; }, converter);
642 std::visit([&](
const auto &c) { c.convert_values(std::move(
from),
to); }, converter);
646 template <
class...
Args>
#define USING_ALPAQA_CONFIG(Conf)
std::variant< SparsityConverter< Froms, To >... > type
@ Unsymmetric
No symmetry.
@ Upper
Symmetric, upper-triangular part is stored.
@ Lower
Symmetric, lower-triangular part is stored.
detail::ConverterVariantHelper< To, SparsityVariant< typename To::config_t > >::type ConverterVariant
Additional options for the conversion performed by SparsityConverter.
Converts one matrix storage format to another.
typename Conf::indexvec indexvec
typename Conf::index_t index_t
typename Conf::length_t length_t
typename Conf::crvec crvec
Sparse coordinate list structure (COO).
index_vector_view_t col_indices
storage_index_t first_index
Zero for C/C++, one for Fortran.
length_t nnz() const
Get the number of structurally nonzero elements.
Eigen::VectorX< storage_index_t > index_vector_t
StorageIndex storage_index_t
index_vector_view_t row_indices
Sparse compressed-column structure (CCS or CSC).
index_vector_view_t outer_ptr
Eigen::Ref< const index_vector_t > index_vector_view_t
Eigen::VectorX< storage_index_t > index_vector_t
StorageIndexFromTo storage_index_t
index_vector_view_t inner_idx
const to_sparsity_t & get_sparsity() const
SparsityConverter(from_sparsity_t from, Request={})
void convert_values(crvec from, rvec to) const
index_vector_t col_indices
const to_sparsity_t & get_sparsity() const
typename to_sparsity_t::storage_index_t storage_index_t
typename to_sparsity_t::index_vector_t index_vector_t
SparsityConverter(from_sparsity_t from, Request request={})
void convert_values(crvec from, rvec to) const
to_sparsity_t convert_sparsity(from_sparsity_t from, Request request)
const to_sparsity_t & get_sparsity() const
typename to_sparsity_t::storage_index_t storage_index_t
to_sparsity_t convert_sparsity(from_sparsity_t from, Request)
typename to_sparsity_t::index_vector_t index_vector_t
SparsityConverter(from_sparsity_t from, Request request={})
typename to_sparsity_t::index_vector_view_t index_vector_view_t
void convert_values(crvec from, rvec to) const
index_vector_t col_indices
const to_sparsity_t & get_sparsity() const
typename to_sparsity_t::storage_index_t storage_index_t
typename to_sparsity_t::index_vector_t index_vector_t
SparsityConverter(from_sparsity_t from, Request request={})
void convert_values(crvec from, rvec to) const
to_sparsity_t convert_sparsity(from_sparsity_t from, Request request)
const to_sparsity_t & get_sparsity() const
typename to_sparsity_t::storage_index_t storage_index_t
typename to_sparsity_t::index_vector_t index_vector_t
SparsityConverter(from_sparsity_t from, Request request={})
void convert_values(crvec from, rvec to) const
to_sparsity_t convert_sparsity(from_sparsity_t from, Request request)
const to_sparsity_t & get_sparsity() const
from_sparsity_t from_sparsity
to_sparsity_t convert_sparsity(from_sparsity_t from, Request)
SparsityConverter(from_sparsity_t from, Request request={})
void convert_values(crvec from, rvec to) const
const to_sparsity_t & get_sparsity() const
typename to_sparsity_t::storage_index_t storage_index_t
typename to_sparsity_t::index_vector_t index_vector_t
SparsityConverter(from_sparsity_t from, Request request={})
typename to_sparsity_t::index_vector_view_t index_vector_view_t
void convert_values(crvec from, rvec to) const
to_sparsity_t convert_sparsity(from_sparsity_t from, Request request)
index_vector_t col_indices
const to_sparsity_t & get_sparsity() const
typename to_sparsity_t::storage_index_t storage_index_t
typename to_sparsity_t::index_vector_t index_vector_t
SparsityConverter(from_sparsity_t from, Request request={})
void convert_values(crvec from, rvec to) const
to_sparsity_t convert_sparsity(from_sparsity_t from, Request request)
const to_sparsity_t & get_sparsity() const
from_sparsity_t from_sparsity
to_sparsity_t convert_sparsity(from_sparsity_t from, Request)
SparsityConverter(from_sparsity_t from, Request request={})
void convert_values(crvec from, rvec to) const
const to_sparsity_t & get_sparsity() const
static auto wrap_converter(Args &&...args)
void convert_values(crvec from, rvec to) const
ConverterVariant< To > converter
SparsityConverter(Sparsity< config_t > from, Request request={})
Stores any of the supported sparsity patterns.