21#if UNI20_BACKEND_CUSOLVER
35using svd_value_extents = stdex::dextents<uni20::index_type, 1>;
36using svd_matrix_extents = stdex::dextents<uni20::index_type, 2>;
38template <uni20::MutableRankedTensorView<1> SingularValueTensor, uni20::MutableRankedTensorView<2> LeftTensor,
39 uni20::MutableRankedTensorView<2> RightAdjo
intTensor, uni20::MutableRankedTensorView<2> MatrixTensor>
40[[nodiscard]] svd_op prepare_svd(SingularValueTensor&
singular_values, LeftTensor& left_singular_vectors,
41 RightAdjointTensor& right_singular_vectors_adjoint, MatrixTensor& matrix_work,
44 std::size_t
const rows =
static_cast<std::size_t
>(matrix_work.extent(0));
45 std::size_t
const cols =
static_cast<std::size_t
>(matrix_work.extent(1));
46 std::size_t
const rank = std::min(rows, cols);
55 return {.left = options.left, .right = options.right};
58template <KernelBackendSelector BackendSelector, uni20::MutableRankedTensorView<1> SingularValueTensor,
59 uni20::MutableRankedTensorView<2> LeftTensor, uni20::MutableRankedTensorView<2> RightAdjo
intTensor,
60 uni20::MutableRankedTensorView<2> MatrixTensor>
61void dispatch_svd(BackendSelector&& selector, svd_op operation, SingularValueTensor&
singular_values,
62 LeftTensor& left_singular_vectors, RightAdjointTensor& right_singular_vectors_adjoint,
63 MatrixTensor& matrix_work, Precision
p)
69 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(std::forward<BackendSelector>(selector),
70 operation,
p, value_descriptor, left_descriptor,
71 right_descriptor, matrix_descriptor);
74 uni20::detail::record_output_precision(left_singular_vectors,
p);
75 uni20::detail::record_output_precision(right_singular_vectors_adjoint,
p);
76 uni20::detail::record_output_precision(matrix_work,
p);
79template <KernelBackendSelector BackendSelector, uni20::MutableRankedTensorView<1> SingularValueTensor,
80 uni20::MutableRankedTensorView<2> MatrixTensor>
81void dispatch_singular_values(BackendSelector&& selector, SingularValueTensor&
singular_values,
82 MatrixTensor& matrix_work, Precision
p)
86 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(
87 std::forward<BackendSelector>(selector), singular_values_op{},
p, value_descriptor, matrix_descriptor);
90 uni20::detail::record_output_precision(matrix_work,
p);
93template <KernelBackendSelector BackendSelector, uni20::MutableRankedTensorView<1> SingularValueTensor,
94 uni20::MutableRankedTensorView<2> LeftTensor, uni20::MutableRankedTensorView<2> MatrixTensor>
95void dispatch_svd_left(BackendSelector&& selector, svd_left_op operation, SingularValueTensor&
singular_values,
96 LeftTensor& left_singular_vectors, MatrixTensor& matrix_work, Precision
p)
101 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(
102 std::forward<BackendSelector>(selector), operation,
p, value_descriptor, left_descriptor, matrix_descriptor);
105 uni20::detail::record_output_precision(left_singular_vectors,
p);
106 uni20::detail::record_output_precision(matrix_work,
p);
109template <KernelBackendSelector BackendSelector, uni20::MutableRankedTensorView<1> SingularValueTensor,
110 uni20::MutableRankedTensorView<2> RightAdjo
intTensor, uni20::MutableRankedTensorView<2> MatrixTensor>
111void dispatch_svd_right(BackendSelector&& selector, svd_right_op operation, SingularValueTensor&
singular_values,
112 RightAdjointTensor& right_singular_vectors_adjoint, MatrixTensor& matrix_work, Precision
p)
117 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(
118 std::forward<BackendSelector>(selector), operation,
p, value_descriptor, right_descriptor, matrix_descriptor);
121 uni20::detail::record_output_precision(right_singular_vectors_adjoint,
p);
122 uni20::detail::record_output_precision(matrix_work,
p);
133template <KernelBackendSelector BackendSelector, uni20::MutableRankedTensorView<1> SingularValueTensor,
134 uni20::MutableRankedTensorView<2> LeftTensor, uni20::MutableRankedTensorView<2> RightAdjo
intTensor,
135 uni20::MutableRankedTensorView<2> MatrixTensor>
137 LeftTensor&& left_singular_vectors,
138 RightAdjointTensor&& right_singular_vectors_adjoint, MatrixTensor&& matrix_work,
139 SvdOptions options = {}, std::optional<Precision> requested = {})
141 auto const p = detail::decomposition_precision(matrix_work, requested);
143 detail::prepare_svd(
singular_values, left_singular_vectors, right_singular_vectors_adjoint, matrix_work, options);
144 detail::dispatch_svd(std::forward<BackendSelector>(selector), operation,
singular_values, left_singular_vectors,
145 right_singular_vectors_adjoint, matrix_work,
p);
151template <uni20::MutableRankedTensorView<1> SingularValueTensor, uni20::MutableRankedTensorView<2> LeftTensor,
152 uni20::MutableRankedTensorView<2> RightAdjo
intTensor, uni20::MutableRankedTensorView<2> MatrixTensor>
154 RightAdjointTensor&& right_singular_vectors_adjoint, MatrixTensor&& matrix_work,
155 SvdOptions options = {}, std::optional<Precision> requested = {})
157 auto const p = detail::decomposition_precision(matrix_work, requested);
159 detail::prepare_svd(
singular_values, left_singular_vectors, right_singular_vectors_adjoint, matrix_work, options);
162 detail::dispatch_svd(selector, operation,
singular_values, left_singular_vectors, right_singular_vectors_adjoint,
179template <
class SingularValueTensor,
class RightAdjo
intTensor>
struct SvdRightResult
190template <
class LeftTensor,
class SingularValueTensor,
class RightAdjo
intTensor>
struct SvdResult
208template <
class MatrixTensor>
209using svd_reuse_factor_t =
210 typename std::remove_cvref_t<MatrixTensor>::template rebind_layout_type<stdex::layout_stride>;
212template <
class MatrixTensor>
consteval bool can_transfer_svd_storage()
214 using matrix_type = std::remove_cvref_t<MatrixTensor>;
219 else if constexpr (
requires {
220 typename matrix_type::storage_policy;
221 typename matrix_type::layout_type;
222 typename matrix_type::accessor_factory_type;
223 typename matrix_type::storage_type;
224 typename matrix_type::extents_type;
225 typename matrix_type::template rebind_layout_type<stdex::layout_stride>;
228 using factor_type = svd_reuse_factor_t<matrix_type>;
229 return matrix_type::extents_type::rank_dynamic() == 2 &&
230 std::same_as<typename matrix_type::storage_policy, uni20::HostStorage> &&
231 std::same_as<typename matrix_type::accessor_factory_type, uni20::DefaultAccessorFactory> &&
233 requires(matrix_type& matrix,
typename factor_type::mapping_type mapping,
234 typename factor_type::storage_type storage,
235 typename factor_type::accessor_factory_type accessor_factory) {
236 { std::move(matrix).release_storage() } -> std::same_as<typename factor_type::storage_type>;
238 std::move(matrix).release_accessor_factory()
239 } -> std::same_as<typename factor_type::accessor_factory_type>;
241 factor_type::adopt_storage(std::move(mapping), std::move(storage), std::move(accessor_factory))
242 } -> std::same_as<factor_type>;
251template <
class FactorTensor> [[nodiscard]] FactorTensor make_svd_factor(std::size_t rows, std::size_t cols)
253 using index_type =
typename FactorTensor::index_type;
254 using extents_type =
typename FactorTensor::extents_type;
259template <
class FactorTensor>
260[[nodiscard]]
auto svd_reuse_mapping(std::size_t rows, std::size_t cols, uni20::blas_int leading_dimension) ->
261 typename FactorTensor::mapping_type
263 using index_type =
typename FactorTensor::index_type;
264 using extents_type =
typename FactorTensor::extents_type;
266 return typename FactorTensor::mapping_type(
270template <
class FactorTensor,
class MatrixTensor>
271[[nodiscard]] FactorTensor adopt_svd_factor(MatrixTensor&& matrix, std::size_t rows, std::size_t cols,
272 uni20::blas_int leading_dimension)
274 auto mapping = svd_reuse_mapping<FactorTensor>(rows, cols, leading_dimension);
275 auto accessor_factory = std::move(matrix).release_accessor_factory();
276 auto storage = std::move(matrix).release_storage();
277 return FactorTensor::adopt_storage(std::move(mapping), std::move(storage), std::move(accessor_factory));
280template <
class MatrixTensor> [[nodiscard]]
auto direct_column_major_svd_stage(MatrixTensor& matrix)
283 if (!stage || stage->unit_stride_axis != 0 || stage->needs_conjugation)
285 return decltype(stage){};
290template <KernelBackendSelector BackendSelector, uni20::OwningTensor MatrixTensor>
292[[nodiscard]]
auto singular_values_from_work_matrix(BackendSelector&& selector, MatrixTensor matrix_work, Precision
p)
294 svd_value_tensor_t<MatrixTensor>
values(
296 svd_value_extents{
static_cast<uni20::index_type>(std::min(matrix_work.extent(0), matrix_work.extent(1)))});
297 dispatch_singular_values(std::forward<BackendSelector>(selector), values, matrix_work,
p);
301template <KernelBackendSelector BackendSelector, uni20::OwningTensor MatrixTensor>
303[[nodiscard]]
auto svd_left_from_work_matrix(BackendSelector&& selector, MatrixTensor matrix_work,
306 std::size_t
const rows =
static_cast<std::size_t
>(matrix_work.extent(0));
307 std::size_t
const cols =
static_cast<std::size_t
>(matrix_work.extent(1));
308 std::size_t
const rank = std::min(rows, cols);
312 dispatch_svd_left(std::forward<BackendSelector>(selector), svd_left_op{.left = extent},
values,
left, matrix_work,
p);
313 return SvdLeftResult<
decltype(
left),
decltype(values)>{.left_singular_vectors = std::move(left),
314 .singular_values = std::move(values)};
317template <KernelBackendSelector BackendSelector, uni20::OwningTensor MatrixTensor>
319[[nodiscard]]
auto svd_right_from_work_matrix(BackendSelector&& selector, MatrixTensor matrix_work,
322 std::size_t
const rows =
static_cast<std::size_t
>(matrix_work.extent(0));
323 std::size_t
const cols =
static_cast<std::size_t
>(matrix_work.extent(1));
324 std::size_t
const rank = std::min(rows, cols);
328 dispatch_svd_right(std::forward<BackendSelector>(selector), svd_right_op{.right = extent},
values,
right, matrix_work,
330 return SvdRightResult<
decltype(
values),
decltype(right)>{.singular_values = std::move(values),
331 .right_singular_vectors_adjoint = std::move(right)};
334template <KernelBackendSelector BackendSelector, uni20::OwningTensor MatrixTensor>
336[[nodiscard]]
auto svd_from_work_matrix(BackendSelector&& selector, MatrixTensor matrix_work, SvdOptions options,
345 right_singular_vectors_adjoint, matrix_work, options,
p);
346 return SvdResult<
decltype(left_singular_vectors),
decltype(
singular_values),
347 decltype(right_singular_vectors_adjoint)>{.left_singular_vectors = std::move(left_singular_vectors),
349 .right_singular_vectors_adjoint =
350 std::move(right_singular_vectors_adjoint)};
353template <
class MatrixTensor> [[nodiscard]]
constexpr auto select_singular_values_backend()
355 return select_backend_for<svd_value_tensor_t<MatrixTensor>, std::remove_cvref_t<MatrixTensor>>(singular_values_op{});
358template <
class MatrixTensor> [[nodiscard]]
constexpr auto select_svd_left_backend(
SvdVectorExtent extent)
360 return select_backend_for<svd_value_tensor_t<MatrixTensor>, svd_matrix_tensor_t<MatrixTensor>,
361 std::remove_cvref_t<MatrixTensor>>(svd_left_op{.left = extent});
364template <
class MatrixTensor> [[nodiscard]]
constexpr auto select_svd_right_backend(
SvdVectorExtent extent)
366 return select_backend_for<svd_value_tensor_t<MatrixTensor>, svd_matrix_tensor_t<MatrixTensor>,
367 std::remove_cvref_t<MatrixTensor>>(svd_right_op{.right = extent});
370template <
class MatrixTensor> [[nodiscard]]
constexpr auto select_svd_backend(SvdOptions options)
372 return select_backend_for<svd_value_tensor_t<MatrixTensor>, svd_matrix_tensor_t<MatrixTensor>,
373 svd_matrix_tensor_t<MatrixTensor>, std::remove_cvref_t<MatrixTensor>>(
374 svd_op{.left = options.left, .right = options.right});
377template <KernelBackendSelector BackendSelector,
class MatrixTensor>
379[[nodiscard]]
auto singular_values_from_consumed_matrix(BackendSelector&& selector, MatrixTensor&& matrix, Precision
p)
381 if constexpr (can_transfer_svd_storage<MatrixTensor>())
383 if (direct_column_major_svd_stage(matrix))
386 dispatch_singular_values(std::forward<BackendSelector>(selector), values, matrix,
p);
390 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
391 return singular_values_from_work_matrix(std::forward<BackendSelector>(selector), std::move(matrix_work),
p);
394template <KernelBackendSelector BackendSelector,
class MatrixTensor>
396 (can_transfer_svd_storage<MatrixTensor>())
397[[nodiscard]]
auto svd_left_from_transferable_matrix(BackendSelector&& selector, MatrixTensor&& matrix,
400 using factor_type = svd_reuse_factor_t<MatrixTensor>;
401 using value_type = svd_value_tensor_t<MatrixTensor>;
402 std::size_t
const rows =
static_cast<std::size_t
>(matrix.extent(0));
403 std::size_t
const cols =
static_cast<std::size_t
>(matrix.extent(1));
404 std::size_t
const rank = std::min(rows, cols);
408 auto stage = direct_column_major_svd_stage(matrix);
413 auto values_span =
values.mdspan();
414 auto matrix_span = matrix.mdspan();
415 auto operation = svd_left_op{.left = extent, .overwrite_input =
true};
416 if constexpr (
requires {
417 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(selector, operation,
p,
418 values_span, matrix_span);
421 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(std::forward<BackendSelector>(selector),
422 operation,
p, values_span, matrix_span);
424 adopt_svd_factor<factor_type>(std::forward<MatrixTensor>(matrix), rows, rank, stage->nonunit_stride);
425 uni20::detail::record_output_precision(left,
p);
426 uni20::detail::record_output_precision(values,
p);
427 return SvdLeftResult<factor_type, value_type>{.left_singular_vectors = std::move(left),
428 .singular_values = std::move(values)};
432 auto left = make_svd_factor<factor_type>(rows, left_cols);
433 dispatch_svd_left(std::forward<BackendSelector>(selector), svd_left_op{.left = extent},
values,
left, matrix,
p);
434 uni20::detail::record_output_precision(left,
p);
435 uni20::detail::record_output_precision(values,
p);
436 return SvdLeftResult<factor_type, value_type>{.left_singular_vectors = std::move(left),
437 .singular_values = std::move(values)};
440 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
441 auto left = make_svd_factor<factor_type>(rows, left_cols);
442 dispatch_svd_left(std::forward<BackendSelector>(selector), svd_left_op{.left = extent},
values,
left, matrix_work,
p);
443 uni20::detail::record_output_precision(left,
p);
444 uni20::detail::record_output_precision(values,
p);
445 return SvdLeftResult<factor_type, value_type>{.left_singular_vectors = std::move(left),
446 .singular_values = std::move(values)};
449template <KernelBackendSelector BackendSelector,
class MatrixTensor>
451 (can_transfer_svd_storage<MatrixTensor>())
452[[nodiscard]]
auto svd_right_from_transferable_matrix(BackendSelector&& selector, MatrixTensor&& matrix,
455 using factor_type = svd_reuse_factor_t<MatrixTensor>;
456 using value_type = svd_value_tensor_t<MatrixTensor>;
457 std::size_t
const rows =
static_cast<std::size_t
>(matrix.extent(0));
458 std::size_t
const cols =
static_cast<std::size_t
>(matrix.extent(1));
459 std::size_t
const rank = std::min(rows, cols);
463 auto stage = direct_column_major_svd_stage(matrix);
468 auto values_span =
values.mdspan();
469 auto matrix_span = matrix.mdspan();
470 auto operation = svd_right_op{.right = extent, .overwrite_input =
true};
471 if constexpr (
requires {
472 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(selector, operation,
p,
473 values_span, matrix_span);
476 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(std::forward<BackendSelector>(selector),
477 operation,
p, values_span, matrix_span);
479 adopt_svd_factor<factor_type>(std::forward<MatrixTensor>(matrix), rank, cols, stage->nonunit_stride);
480 uni20::detail::record_output_precision(right,
p);
481 uni20::detail::record_output_precision(values,
p);
482 return SvdRightResult<value_type, factor_type>{.singular_values = std::move(values),
483 .right_singular_vectors_adjoint = std::move(right)};
487 auto right = make_svd_factor<factor_type>(right_rows, cols);
488 dispatch_svd_right(std::forward<BackendSelector>(selector), svd_right_op{.right = extent},
values,
right, matrix,
490 uni20::detail::record_output_precision(right,
p);
491 uni20::detail::record_output_precision(values,
p);
492 return SvdRightResult<value_type, factor_type>{.singular_values = std::move(values),
493 .right_singular_vectors_adjoint = std::move(right)};
496 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
497 auto right = make_svd_factor<factor_type>(right_rows, cols);
498 dispatch_svd_right(std::forward<BackendSelector>(selector), svd_right_op{.right = extent},
values,
right, matrix_work,
500 uni20::detail::record_output_precision(right,
p);
501 uni20::detail::record_output_precision(values,
p);
502 return SvdRightResult<value_type, factor_type>{.singular_values = std::move(values),
503 .right_singular_vectors_adjoint = std::move(right)};
506template <KernelBackendSelector BackendSelector,
class MatrixTensor>
508 (can_transfer_svd_storage<MatrixTensor>())
509[[nodiscard]]
auto svd_from_transferable_matrix(BackendSelector&& selector, MatrixTensor&& matrix, SvdOptions options,
512 using factor_type = svd_reuse_factor_t<MatrixTensor>;
513 using value_type = svd_value_tensor_t<MatrixTensor>;
514 std::size_t
const rows =
static_cast<std::size_t
>(matrix.extent(0));
515 std::size_t
const cols =
static_cast<std::size_t
>(matrix.extent(1));
516 std::size_t
const rank = std::min(rows, cols);
523 auto stage = direct_column_major_svd_stage(matrix);
526 left = make_svd_factor<factor_type>(rows, left_cols);
527 right = make_svd_factor<factor_type>(right_rows, cols);
528 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
529 auto operation = svd_op{.left = options.left, .right = options.right};
530 auto values_span =
values.mdspan();
531 auto left_span =
left.mdspan();
532 auto right_span =
right.mdspan();
533 auto matrix_span = matrix_work.mdspan();
534 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(
535 std::forward<BackendSelector>(selector), operation,
p, values_span, left_span, right_span, matrix_span);
539 right = make_svd_factor<factor_type>(right_rows, cols);
540 auto operation = svd_op{.left = options.left, .right = options.right, .overwrite =
SvdOverwrite::Left};
541 auto values_span =
values.mdspan();
542 auto right_span =
right.mdspan();
543 auto matrix_span = matrix.mdspan();
544 if constexpr (
requires {
545 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(
546 selector, operation,
p, values_span, right_span, matrix_span);
549 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(
550 std::forward<BackendSelector>(selector), operation,
p, values_span, right_span, matrix_span);
551 left = adopt_svd_factor<factor_type>(std::forward<MatrixTensor>(matrix), rows, rank, stage->nonunit_stride);
555 left = make_svd_factor<factor_type>(rows, left_cols);
556 auto normal_operation = svd_op{.left = options.left, .right = options.right};
557 auto left_span =
left.mdspan();
558 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(std::forward<BackendSelector>(selector),
559 normal_operation,
p, values_span, left_span,
560 right_span, matrix_span);
565 left = make_svd_factor<factor_type>(rows, left_cols);
566 auto operation = svd_op{.left = options.left, .right = options.right, .overwrite =
SvdOverwrite::Right};
567 auto values_span =
values.mdspan();
568 auto left_span =
left.mdspan();
569 auto matrix_span = matrix.mdspan();
570 if constexpr (
requires {
571 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(
572 selector, operation,
p, values_span, left_span, matrix_span);
575 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(
576 std::forward<BackendSelector>(selector), operation,
p, values_span, left_span, matrix_span);
577 right = adopt_svd_factor<factor_type>(std::forward<MatrixTensor>(matrix), rank, cols, stage->nonunit_stride);
581 right = make_svd_factor<factor_type>(right_rows, cols);
582 auto normal_operation = svd_op{.left = options.left, .right = options.right};
583 auto right_span =
right.mdspan();
584 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(std::forward<BackendSelector>(selector),
585 normal_operation,
p, values_span, left_span,
586 right_span, matrix_span);
591 left = make_svd_factor<factor_type>(rows, left_cols);
592 right = make_svd_factor<factor_type>(right_rows, cols);
593 auto operation = svd_op{.left = options.left, .right = options.right};
594 auto values_span =
values.mdspan();
595 auto left_span =
left.mdspan();
596 auto right_span =
right.mdspan();
597 auto matrix_span = matrix.mdspan();
598 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(
599 std::forward<BackendSelector>(selector), operation,
p, values_span, left_span, right_span, matrix_span);
602 uni20::detail::record_output_precision(left,
p);
603 uni20::detail::record_output_precision(values,
p);
604 uni20::detail::record_output_precision(right,
p);
605 return SvdResult<factor_type, value_type, factor_type>{.left_singular_vectors = std::move(left),
606 .singular_values = std::move(values),
607 .right_singular_vectors_adjoint = std::move(right)};
612template <KernelBackendSelector BackendSelector, uni20::RankedTensorView<2> MatrixTensor>
613[[nodiscard]]
auto singular_values(BackendSelector&& selector, MatrixTensor
const& matrix,
614 std::optional<Precision> requested = {})
616 auto const p = detail::decomposition_precision(matrix, requested);
617 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
618 return detail::singular_values_from_work_matrix(std::forward<BackendSelector>(selector), std::move(matrix_work),
p);
622template <uni20::RankedTensorView<2> MatrixTensor>
623[[nodiscard]]
auto singular_values(MatrixTensor
const& matrix, std::optional<Precision> requested = {})
625 auto const p = detail::decomposition_precision(matrix, requested);
626 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
627 auto selector = detail::select_singular_values_backend<decltype(matrix_work)>();
628 return detail::singular_values_from_work_matrix(std::move(selector), std::move(matrix_work),
p);
634template <KernelBackendSelector BackendSelector,
class MatrixTensor>
636 (!std::is_lvalue_reference_v<MatrixTensor>) && (!std::is_const_v<std::remove_reference_t<MatrixTensor>>)
638 std::optional<Precision> requested = {})
640 auto const p = detail::decomposition_precision(matrix, requested);
641 return detail::singular_values_from_consumed_matrix(std::forward<BackendSelector>(selector),
642 std::forward<MatrixTensor>(matrix),
p);
646template <
class MatrixTensor>
648 (!std::is_lvalue_reference_v<MatrixTensor>) && (!std::is_const_v<std::remove_reference_t<MatrixTensor>>)
649[[nodiscard]]
auto singular_values(MatrixTensor&& matrix, std::optional<Precision> requested = {})
651 auto const p = detail::decomposition_precision(matrix, requested);
652 using work_type = std::conditional_t<detail::can_transfer_svd_storage<MatrixTensor>(),
653 std::remove_cvref_t<MatrixTensor>, detail::svd_matrix_tensor_t<MatrixTensor>>;
654 auto selector = detail::select_singular_values_backend<work_type>();
655 return detail::singular_values_from_consumed_matrix(std::move(selector), std::forward<MatrixTensor>(matrix),
p);
659template <KernelBackendSelector BackendSelector, uni20::RankedTensorView<2> MatrixTensor>
660[[nodiscard]]
auto svd_left(BackendSelector&& selector, MatrixTensor
const& matrix,
663 auto const p = detail::decomposition_precision(matrix, requested);
664 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
665 return detail::svd_left_from_work_matrix(std::forward<BackendSelector>(selector), std::move(matrix_work), extent,
p);
669template <uni20::RankedTensorView<2> MatrixTensor>
671 std::optional<Precision> requested = {})
673 auto const p = detail::decomposition_precision(matrix, requested);
674 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
675 auto selector = detail::select_svd_left_backend<decltype(matrix_work)>(extent);
676 return detail::svd_left_from_work_matrix(std::move(selector), std::move(matrix_work), extent,
p);
682template <KernelBackendSelector BackendSelector,
class MatrixTensor>
684 (!std::is_lvalue_reference_v<MatrixTensor>) && (!std::is_const_v<std::remove_reference_t<MatrixTensor>>)
685[[nodiscard]]
auto svd_left(BackendSelector&& selector, MatrixTensor&& matrix,
688 auto const p = detail::decomposition_precision(matrix, requested);
689 if constexpr (detail::can_transfer_svd_storage<MatrixTensor>())
691 return detail::svd_left_from_transferable_matrix(std::forward<BackendSelector>(selector),
692 std::forward<MatrixTensor>(matrix), extent,
p);
696 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
697 return detail::svd_left_from_work_matrix(std::forward<BackendSelector>(selector), std::move(matrix_work), extent,
703template <
class MatrixTensor>
705 (!std::is_lvalue_reference_v<MatrixTensor>) && (!std::is_const_v<std::remove_reference_t<MatrixTensor>>)
707 std::optional<Precision> requested = {})
709 auto const p = detail::decomposition_precision(matrix, requested);
710 if constexpr (detail::can_transfer_svd_storage<MatrixTensor>())
712 using factor_type = detail::svd_reuse_factor_t<MatrixTensor>;
713 using value_type = detail::svd_value_tensor_t<MatrixTensor>;
714 auto operation = svd_left_op{.left = extent};
715 auto selector = select_backend_for<value_type, factor_type, std::remove_cvref_t<MatrixTensor>>(operation);
716 return detail::svd_left_from_transferable_matrix(std::move(selector), std::forward<MatrixTensor>(matrix), extent,
721 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
722 auto selector = detail::select_svd_left_backend<decltype(matrix_work)>(extent);
723 return detail::svd_left_from_work_matrix(std::move(selector), std::move(matrix_work), extent,
p);
728template <KernelBackendSelector BackendSelector, uni20::RankedTensorView<2> MatrixTensor>
729[[nodiscard]]
auto svd_right(BackendSelector&& selector, MatrixTensor
const& matrix,
732 auto const p = detail::decomposition_precision(matrix, requested);
733 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
734 return detail::svd_right_from_work_matrix(std::forward<BackendSelector>(selector), std::move(matrix_work), extent,
p);
738template <uni20::RankedTensorView<2> MatrixTensor>
740 std::optional<Precision> requested = {})
742 auto const p = detail::decomposition_precision(matrix, requested);
743 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
744 auto selector = detail::select_svd_right_backend<decltype(matrix_work)>(extent);
745 return detail::svd_right_from_work_matrix(std::move(selector), std::move(matrix_work), extent,
p);
751template <KernelBackendSelector BackendSelector,
class MatrixTensor>
753 (!std::is_lvalue_reference_v<MatrixTensor>) && (!std::is_const_v<std::remove_reference_t<MatrixTensor>>)
754[[nodiscard]]
auto svd_right(BackendSelector&& selector, MatrixTensor&& matrix,
757 auto const p = detail::decomposition_precision(matrix, requested);
758 if constexpr (detail::can_transfer_svd_storage<MatrixTensor>())
760 return detail::svd_right_from_transferable_matrix(std::forward<BackendSelector>(selector),
761 std::forward<MatrixTensor>(matrix), extent,
p);
765 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
766 return detail::svd_right_from_work_matrix(std::forward<BackendSelector>(selector), std::move(matrix_work), extent,
772template <
class MatrixTensor>
774 (!std::is_lvalue_reference_v<MatrixTensor>) && (!std::is_const_v<std::remove_reference_t<MatrixTensor>>)
776 std::optional<Precision> requested = {})
778 auto const p = detail::decomposition_precision(matrix, requested);
779 if constexpr (detail::can_transfer_svd_storage<MatrixTensor>())
781 using factor_type = detail::svd_reuse_factor_t<MatrixTensor>;
782 using value_type = detail::svd_value_tensor_t<MatrixTensor>;
783 auto operation = svd_right_op{.right = extent};
784 auto selector = select_backend_for<value_type, factor_type, std::remove_cvref_t<MatrixTensor>>(operation);
785 return detail::svd_right_from_transferable_matrix(std::move(selector), std::forward<MatrixTensor>(matrix), extent,
790 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
791 auto selector = detail::select_svd_right_backend<decltype(matrix_work)>(extent);
792 return detail::svd_right_from_work_matrix(std::move(selector), std::move(matrix_work), extent,
p);
801template <KernelBackendSelector BackendSelector, uni20::RankedTensorView<2> MatrixTensor>
802[[nodiscard]]
auto svd(BackendSelector&& selector, MatrixTensor
const& matrix,
SvdOptions options = {},
803 std::optional<Precision> requested = {})
805 auto const p = detail::decomposition_precision(matrix, requested);
806 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
807 return detail::svd_from_work_matrix(std::forward<BackendSelector>(selector), std::move(matrix_work), options,
p);
813template <uni20::RankedTensorView<2> MatrixTensor>
814[[nodiscard]]
auto svd(MatrixTensor
const& matrix,
SvdOptions options = {}, std::optional<Precision> requested = {})
816 auto const p = detail::decomposition_precision(matrix, requested);
817 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
818 auto selector = detail::select_svd_backend<decltype(matrix_work)>(options);
819 return detail::svd_from_work_matrix(std::move(selector), std::move(matrix_work), options,
p);
826template <KernelBackendSelector BackendSelector,
class MatrixTensor>
828 (!std::is_lvalue_reference_v<MatrixTensor>) && (!std::is_const_v<std::remove_reference_t<MatrixTensor>>)
829[[nodiscard]]
auto svd(BackendSelector&& selector, MatrixTensor&& matrix,
SvdOptions options = {},
830 std::optional<Precision> requested = {})
832 auto const p = detail::decomposition_precision(matrix, requested);
833 if constexpr (detail::can_transfer_svd_storage<MatrixTensor>())
835 return detail::svd_from_transferable_matrix(std::forward<BackendSelector>(selector),
836 std::forward<MatrixTensor>(matrix), options,
p);
840 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
841 return detail::svd_from_work_matrix(std::forward<BackendSelector>(selector), std::move(matrix_work), options,
p);
855template <
class MatrixTensor>
857 (!std::is_lvalue_reference_v<MatrixTensor>) && (!std::is_const_v<std::remove_reference_t<MatrixTensor>>)
858[[nodiscard]]
auto svd(MatrixTensor&& matrix,
SvdOptions options = {}, std::optional<Precision> requested = {})
860 auto const p = detail::decomposition_precision(matrix, requested);
861 if constexpr (detail::can_transfer_svd_storage<MatrixTensor>())
863 using factor_type = detail::svd_reuse_factor_t<MatrixTensor>;
864 using value_type = detail::svd_value_tensor_t<MatrixTensor>;
865 auto operation = svd_op{.left = options.left, .right = options.right};
867 select_backend_for<value_type, factor_type, factor_type, std::remove_cvref_t<MatrixTensor>>(operation);
868 return detail::svd_from_transferable_matrix(std::move(selector), std::forward<MatrixTensor>(matrix), options,
p);
872 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
873 auto selector = detail::select_svd_backend<decltype(matrix_work)>(options);
874 return detail::svd_from_work_matrix(std::move(selector), std::move(matrix_work), options,
p);
881 return uni20::linalg::svd(std::forward<Matrix>(matrix), options, std::optional<Precision>{
p});
885template <KernelBackendSelector Selector, RankedTensorView<2> Matrix>
888 return uni20::linalg::svd(std::forward<Selector>(selector), std::forward<Matrix>(matrix), options,
889 std::optional<Precision>{
p});
893template <RankedTensorView<2> Matrix>
900template <KernelBackendSelector Selector, RankedTensorView<2> Matrix>
905 std::optional<Precision>{
p});
909template <RankedTensorView<2> Matrix>
916template <KernelBackendSelector Selector, RankedTensorView<2> Matrix>
921 std::optional<Precision>{
p});
925template <MutableRankedTensorView<1> V, MutableRankedTensorView<2> L, MutableRankedTensorView<2> R,
926 MutableRankedTensorView<2> A>
931 std::forward<A>(matrix_work), options, std::optional<Precision>{
p});
935template <KernelBackendSelector Selector, MutableRankedTensorView<1> V, MutableRankedTensorView<2> L,
936 MutableRankedTensorView<2> R, MutableRankedTensorView<2> A>
941 std::forward<L>(left), std::forward<R>(right),
942 std::forward<A>(matrix_work), options, std::optional<Precision>{
p});
Blocking cuSOLVER exact SVD over CUDA-buffer mdspec operands.
LAPACK backend for exact dense singular value decompositions.
Exact arithmetic or an explicit binary working precision.
Definition core/precision.hpp:13
General-purpose owning tensor with immediate or deferred mdspan metadata.
Definition basic_tensor.hpp:109
An mdspan-like type whose accessor is stdex::default_accessor.
Definition mdspan/concepts.hpp:501
Tensor-level object that owns the storage described by its multidimensional view.
Definition tensor/concepts.hpp:116
Operation-tag backend dispatch over tensor-view operands.
typename make_real< T >::type make_real_t
Alias for the underlying real-valued type of T.
Definition scalar_traits.hpp:168
Lower mdspan matrix views to provider-ready BLAS operands.
int rows(std::FILE *stream)
Return the terminal row count associated with a C stream.
Definition terminal.cpp:482
auto try_mdspan_matrix_stage(Mdspan const &span) -> std::optional< MdspanMatrixStage< std::remove_cv_t< typename Mdspan::element_type >, detail::span_data_t< Mdspan > > >
Build a matrix staging descriptor when direct provider lowering is possible.
Definition mdspan_matrix.hpp:202
auto values(Tensor &tensor)
Definition packed_matrix.hpp:29
Definition linalg/async.hpp:28
void singular_value_decomposition(BackendSelector &&selector, SingularValueTensor &&singular_values, LeftTensor &&left_singular_vectors, RightAdjointTensor &&right_singular_vectors_adjoint, MatrixTensor &&matrix_work, SvdOptions options={}, std::optional< Precision > requested={})
Compute a destructive exact SVD through an explicit selector.
Definition ops/svd.hpp:136
SvdVectorExtent
Extent policy for one side of an exact singular value decomposition.
Definition operation_tags.hpp:248
auto svd_right(BackendSelector selector, async::Async< MatrixTensor > const &matrix, SvdVectorExtent extent=SvdVectorExtent::Reduced, std::optional< Precision > requested={})
Schedule preserving right singular vectors through an explicit selector.
Definition async/svd.hpp:490
constexpr auto select_backend(Operation const &operation, FirstTensor const &, RestTensors const &...)
Select the default backend list for an operation on Tensor operands.
Definition backend_selector.hpp:252
auto svd(BackendSelector selector, async::Async< MatrixTensor > const &matrix, SvdOptions options={}, std::optional< Precision > requested={})
Schedule a preserving exact SVD through an explicit selector.
Definition async/svd.hpp:531
auto singular_values(BackendSelector selector, async::Async< MatrixTensor > const &matrix, std::optional< Precision > requested={})
Schedule preserving exact singular values through an explicit selector.
Definition async/svd.hpp:416
auto svd_left(BackendSelector selector, async::Async< MatrixTensor > const &matrix, SvdVectorExtent extent=SvdVectorExtent::Reduced, std::optional< Precision > requested={})
Schedule preserving left singular vectors through an explicit selector.
Definition async/svd.hpp:452
typename optional_traits< T >::value_type value_type
Definition data_table.hpp:42
Definition data_table.cpp:8
constexpr uninitialized_t uninitialized
Explicit allocation tag for overwrite outputs and scratch space.
Definition common/initialization.hpp:22
Output & prepare_output(Output &output, RequiredExtents const &required)
Prepare a mutable tensor output with the specified shape.
Definition tensor/output.hpp:104
constexpr decltype(auto) mdspec_of(Tensor &tensor) noexcept(noexcept(tensor.mdspec()))
Return a tensor's immediate or descriptor-backed multidimensional metadata.
Definition tensor/concepts.hpp:50
std::remove_cv_t< typename tensor_mdspec_t< T >::element_type > tensor_element_t
Scalar value type exposed by a tensor-level object.
Definition tensor/concepts.hpp:126
std::ptrdiff_t index_type
Definition types.hpp:19
Owning left singular vectors and singular values returned by svd_left.
Definition ops/svd.hpp:169
SingularValueTensor singular_value_tensor_type
Definition ops/svd.hpp:171
LeftTensor left_singular_vectors
Definition ops/svd.hpp:173
SingularValueTensor singular_values
Definition ops/svd.hpp:174
LeftTensor left_singular_vector_tensor_type
Definition ops/svd.hpp:170
Output-shape options for an exact singular value decomposition.
Definition operation_tags.hpp:255
Owning factors returned by svd.
Definition ops/svd.hpp:191
RightAdjointTensor right_singular_vectors_adjoint
Definition ops/svd.hpp:198
LeftTensor left_singular_vectors
Definition ops/svd.hpp:196
SingularValueTensor singular_value_tensor_type
Definition ops/svd.hpp:193
LeftTensor left_singular_vector_tensor_type
Definition ops/svd.hpp:192
SingularValueTensor singular_values
Definition ops/svd.hpp:197
RightAdjointTensor right_singular_vector_adjoint_tensor_type
Definition ops/svd.hpp:194
Owning singular values and right singular vectors returned by svd_right.
Definition ops/svd.hpp:180
RightAdjointTensor right_singular_vectors_adjoint
Definition ops/svd.hpp:185
RightAdjointTensor right_singular_vector_adjoint_tensor_type
Definition ops/svd.hpp:182
SingularValueTensor singular_values
Definition ops/svd.hpp:184
SingularValueTensor singular_value_tensor_type
Definition ops/svd.hpp:181
Backend-dispatched tensor copies and inferred owning materialization.
Shape preparation contracts for tensor operation outputs.
General-purpose owning tensors with runtime extents.