21template <
class From,
class To>
39 throw std::invalid_argument(
"Nonsquare matrix cannot be symmetric");
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,
70 work(from_sparsity.nnz()) {}
80 auto &&
T =
to.reshaped(sparsity.
rows, sparsity.
cols);
91 throw std::invalid_argument(
92 "Invalid symmetric CSC matrix: upper-triangular matrix should not "
93 "have elements below the diagonal");
94 T(c, r) =
T(r, c) = work(l);
98 throw std::invalid_argument(
99 "Invalid symmetric CSC matrix: lower-triangular matrix should not "
100 "have elements above the diagonal");
101 T(c, r) =
T(r, c) = work(l);
103 default:
throw std::invalid_argument(
"Invalid symmetry");
111template <Config Conf,
class StorageIndex>
118#if ALPAQA_HAVE_COO_CSC_CONVERSIONS
119 assert(util::check_uniqueness_triplets(
from.row_indices,
from.col_indices));
122 throw std::invalid_argument(
"Nonsquare matrix cannot be symmetric");
126 .symmetry =
from.symmetry,
131 work(from_sparsity.nnz()) {}
141 auto &&
T =
to.reshaped(sparsity.
rows, sparsity.
cols);
142 for (
index_t l = 0; l < from_sparsity.
nnz(); ++l) {
149 throw std::invalid_argument(
150 "Invalid symmetric COO matrix: upper-triangular matrix should not "
151 "have elements below the diagonal");
152 T(c, r) =
T(r, c) = work(l);
156 throw std::invalid_argument(
157 "Invalid symmetric COO matrix: lower-triangular matrix should not "
158 "have elements above the diagonal");
159 T(c, r) =
T(r, c) = work(l);
161 default:
throw std::invalid_argument(
"Invalid symmetry");
167template <Config Conf,
class StorageIndex>
170 std::optional<StorageIndex> first_index = std::nullopt;
173template <Config Conf,
class StorageIndex>
185 switch (
from.symmetry) {
188 row_indices.resize(nnz);
189 col_indices.resize(nnz);
201 throw std::invalid_argument(
"Nonsquare matrix cannot be symmetric");
203 row_indices.resize(nnz);
204 col_indices.resize(nnz);
207 for (
index_t r = 0; r <= c; ++r) {
215 throw std::invalid_argument(
"Lower-triangular symmetry currently not supported");
216 default:
throw std::invalid_argument(
"Invalid symmetry");
221 .symmetry =
from.symmetry,
222 .row_indices = row_indices,
223 .col_indices = col_indices,
224 .order = to_sparsity_t::SortedByColsAndRows,
231 work.resize(sparsity.rows * sparsity.cols);
244 auto &&f = work.reshaped(sparsity.
rows, sparsity.
cols);
247 std::ranges::copy_backward(f.col(c).topRows(c + 1), t += c + 1);
252template <Config Conf,
class StorageIndexFrom,
class StorageIndexTo>
264 row_indices.resize(
from.nnz());
265 col_indices.resize(
from.nnz());
271 auto r =
from.inner_idx(i);
280 .symmetry =
from.symmetry,
281 .row_indices = row_indices,
282 .col_indices = col_indices,
283 .order =
from.order == from_sparsity_t::SortedRows ? to_sparsity_t::SortedByColsAndRows
284 : to_sparsity_t::SortedByColsOnly,
290#if ALPAQA_HAVE_COO_CSC_CONVERSIONS
291 assert(util::check_uniqueness_triplets(sparsity.row_indices, sparsity.col_indices));
304template <Config Conf,
class StorageIndexFrom,
class StorageIndexTo>
317 if constexpr (std::is_same_v<StorageIndexFrom, StorageIndexTo>)
321 row_indices.resize(
from.nnz());
322 col_indices.resize(
from.nnz());
324 std::ranges::transform(
from.row_indices, row_indices.begin(),
cvt_idx);
325 std::ranges::transform(
from.col_indices, col_indices.begin(),
cvt_idx);
329 .symmetry =
from.symmetry,
330 .row_indices = row_indices,
331 .col_indices = col_indices,
339#if ALPAQA_HAVE_COO_CSC_CONVERSIONS
340 assert(util::check_uniqueness_triplets(sparsity.row_indices, sparsity.col_indices));
353template <Config Conf,
class StorageIndex>
356 std::optional<typename SparseCSC<Conf, StorageIndex>::Order> order = std::nullopt;
359template <Config Conf,
class StorageIndexFrom,
class StorageIndexFromTo>
369#if ALPAQA_HAVE_COO_CSC_CONVERSIONS
375 std::ranges::transform(
from.row_indices, row_indices.begin(),
cvt_idx);
376 std::ranges::transform(
from.col_indices, col_indices.begin(),
cvt_idx);
379 if (
request.order && *
request.order == to_sparsity_t::SortedRows) {
380 order = to_sparsity_t::SortedRows;
381 switch (
from.order) {
382 case from_sparsity_t::SortedByColsAndRows:
386 case from_sparsity_t::SortedByColsOnly: [[
fallthrough]];
387 case from_sparsity_t::SortedByRowsAndCols: [[
fallthrough]];
388 case from_sparsity_t::SortedByRowsOnly:
389 permutation.resize(
from.nnz());
390 std::iota(permutation.begin(), permutation.end(),
index_t{0});
391 util::sort_triplets(row_indices, col_indices, permutation);
393 default:
throw std::invalid_argument(
"Invalid order");
396 switch (
from.order) {
397 case from_sparsity_t::SortedByColsAndRows:
398 order = to_sparsity_t::SortedRows;
401 case from_sparsity_t::SortedByColsOnly:
402 order = to_sparsity_t::Unsorted;
406 case from_sparsity_t::SortedByRowsAndCols: [[
fallthrough]];
407 case from_sparsity_t::SortedByRowsOnly:
408 order = to_sparsity_t::Unsorted;
409 permutation.resize(
from.nnz());
410 std::iota(permutation.begin(), permutation.end(),
index_t{0});
411 util::sort_triplets_col(row_indices, col_indices, permutation);
413 default:
throw std::invalid_argument(
"Invalid order");
417 if (std::ranges::is_sorted(permutation))
420 inner_idx.resize(
from.nnz());
421 outer_ptr.resize(
from.cols + 1);
422 util::convert_triplets_to_ccs(row_indices, col_indices, inner_idx, outer_ptr,
427 .symmetry =
from.symmetry,
428 .inner_idx = inner_idx,
429 .outer_ptr = outer_ptr,
433 throw std::runtime_error(
434 "This build of alpaqa does not support conversions from sparse COO format to CSC "
435 "format. Please recompile with a C++23-compliant compiler.");
440#if ALPAQA_HAVE_COO_CSC_CONVERSIONS
441 assert(util::check_uniqueness_csc(sparsity.outer_ptr, sparsity.inner_idx));
443 if (permutation.size() > 0)
444 work.resize(sparsity.nnz());
454 if (permutation.size() > 0) {
456 to = work(permutation);
463template <Config Conf,
class StorageIndexFrom,
class StorageIndexTo>
475 inner_idx.resize(
from.inner_idx.size());
476 std::ranges::transform(
from.inner_idx, inner_idx.begin(),
cvt_idx);
477 outer_ptr.resize(
from.outer_ptr.size());
478 std::ranges::transform(
from.outer_ptr, outer_ptr.begin(),
cvt_idx);
481#if ALPAQA_HAVE_COO_CSC_CONVERSIONS
483 permutation.resize(
from.nnz());
484 std::iota(permutation.begin(), permutation.end(),
index_t{0});
485 util::sort_rows_csc(outer_ptr, inner_idx, permutation);
487 throw std::runtime_error(
488 "This build of alpaqa does not support sorting matrices in CSC format. "
489 "Please recompile with a C++23-compliant compiler.");
494 auto order =
static_cast<Order
>(
from.order);
496 if (
request.order && *
request.order == to_sparsity_t::SortedRows) {
497 order = to_sparsity_t::SortedRows;
498 switch (
from.order) {
499 case from_sparsity_t::Unsorted:
need_sorting =
true;
break;
500 case from_sparsity_t::SortedRows:
need_sorting =
false;
break;
501 default:
throw std::invalid_argument(
"Invalid order");
507 else if (!std::is_same_v<StorageIndexFrom, StorageIndexTo>)
510 if (std::ranges::is_sorted(permutation))
513 if constexpr (std::is_same_v<StorageIndexFrom, StorageIndexTo>)
517 .symmetry =
from.symmetry,
527 .symmetry =
from.symmetry,
528 .inner_idx = inner_idx,
529 .outer_ptr = outer_ptr,
535#if ALPAQA_HAVE_COO_CSC_CONVERSIONS
536 assert(util::check_uniqueness_csc(sparsity.outer_ptr, sparsity.inner_idx));
538 if (permutation.size() > 0)
539 work.resize(sparsity.nnz());
549 if (permutation.size() > 0) {
551 to = work(permutation);
558template <Config Conf,
class StorageIndex>
569 switch (
from.symmetry) {
571 inner_idx.resize(
from.rows *
from.cols);
572 outer_ptr.resize(
from.cols + 1);
585 throw std::invalid_argument(
"Nonsquare matrix cannot be symmetric");
586 inner_idx.resize(
from.rows * (
from.rows + 1) / 2);
587 outer_ptr.resize(
from.cols + 1);
591 for (
index_t r = 0; r <= c; ++r) {
599 throw std::invalid_argument(
"Lower-triangular symmetry currently not supported");
600 default:
throw std::invalid_argument(
"Invalid symmetry");
605 .symmetry =
from.symmetry,
606 .inner_idx = inner_idx,
607 .outer_ptr = outer_ptr,
608 .order = to_sparsity_t::SortedRows,
614 work.resize(sparsity.rows * sparsity.cols);
627 auto &&f = work.reshaped(sparsity.
rows, sparsity.
cols);
630 std::ranges::copy_backward(f.col(c).topRows(c + 1), t += c + 1);
636template <
class To,
class>
639template <
class To,
class...
Froms>
641 using type = std::variant<SparsityConverter<Froms, To>...>;
651template <
class Conf,
class To>
652 requires std::same_as<Conf, typename To::config_t>
662 return std::visit([](
const auto &c) ->
const to_sparsity_t & {
return c; }, converter);
667 std::visit([&](
const auto &c) { c.convert_values(
from,
to); }, converter);
#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
void convert_values(const F &from, rvec to) const
SparsityConverter(from_sparsity_t from, Request={})
index_vector_t col_indices
const to_sparsity_t & get_sparsity() const
void convert_values(const F &from, rvec to) 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={})
to_sparsity_t convert_sparsity(from_sparsity_t from, Request request)
const to_sparsity_t & get_sparsity() const
void convert_values(const F &from, rvec to) 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
index_vector_t col_indices
const to_sparsity_t & get_sparsity() const
void convert_values(const F &from, rvec to) 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={})
to_sparsity_t convert_sparsity(from_sparsity_t from, Request request)
const to_sparsity_t & get_sparsity() const
void convert_values(const F &from, rvec to) 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={})
to_sparsity_t convert_sparsity(from_sparsity_t from, Request request)
const to_sparsity_t & get_sparsity() const
void convert_values(const F &from, rvec to) const
from_sparsity_t from_sparsity
to_sparsity_t convert_sparsity(from_sparsity_t from, Request)
SparsityConverter(from_sparsity_t from, Request request={})
const to_sparsity_t & get_sparsity() const
void convert_values(const F &from, rvec to) 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
to_sparsity_t convert_sparsity(from_sparsity_t from, Request request)
index_vector_t col_indices
const to_sparsity_t & get_sparsity() const
void convert_values(const F &from, rvec to) 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={})
to_sparsity_t convert_sparsity(from_sparsity_t from, Request request)
const to_sparsity_t & get_sparsity() const
void convert_values(const F &from, rvec to) const
from_sparsity_t from_sparsity
to_sparsity_t convert_sparsity(from_sparsity_t from, Request)
SparsityConverter(from_sparsity_t from, Request request={})
const to_sparsity_t & get_sparsity() const
void convert_values(const F &from, rvec to) const
void convert_values(crvec from, rvec to) const =delete
ConverterVariant< To > converter
SparsityConverter(Sparsity< config_t > from, Request request={})
static auto wrap_converter(Request request)
Stores any of the supported sparsity patterns.