Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
ops/svd.hpp
Go to the documentation of this file.
1#pragma once
2
17#include <uni20/tensor/copy.hpp>
20
21#if UNI20_BACKEND_CUSOLVER
23#endif
24
25#include <algorithm>
26#include <array>
27#include <concepts>
28#include <type_traits>
29#include <utility>
30
31namespace uni20::linalg
32{
33namespace detail
34{
35using svd_value_extents = stdex::dextents<uni20::index_type, 1>;
36using svd_matrix_extents = stdex::dextents<uni20::index_type, 2>;
37
38template <uni20::MutableRankedTensorView<1> SingularValueTensor, uni20::MutableRankedTensorView<2> LeftTensor,
39 uni20::MutableRankedTensorView<2> RightAdjointTensor, 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,
42 SvdOptions options)
43{
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);
47 std::size_t const left_cols = options.left == SvdVectorExtent::Full ? rows : rank;
48 std::size_t const right_rows = options.right == SvdVectorExtent::Full ? cols : rank;
49
50 uni20::prepare_output(singular_values, svd_value_extents{static_cast<uni20::index_type>(rank)});
51 uni20::prepare_output(left_singular_vectors, svd_matrix_extents{static_cast<uni20::index_type>(rows),
52 static_cast<uni20::index_type>(left_cols)});
53 uni20::prepare_output(right_singular_vectors_adjoint, svd_matrix_extents{static_cast<uni20::index_type>(right_rows),
54 static_cast<uni20::index_type>(cols)});
55 return {.left = options.left, .right = options.right};
56}
57
58template <KernelBackendSelector BackendSelector, uni20::MutableRankedTensorView<1> SingularValueTensor,
59 uni20::MutableRankedTensorView<2> LeftTensor, uni20::MutableRankedTensorView<2> RightAdjointTensor,
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)
64{
65 auto value_descriptor = uni20::mdspec_of(singular_values);
66 auto left_descriptor = uni20::mdspec_of(left_singular_vectors);
67 auto right_descriptor = uni20::mdspec_of(right_singular_vectors_adjoint);
68 auto matrix_descriptor = uni20::mdspec_of(matrix_work);
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);
72
73 uni20::detail::record_output_precision(singular_values, p);
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);
77}
78
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)
83{
84 auto value_descriptor = uni20::mdspec_of(singular_values);
85 auto matrix_descriptor = uni20::mdspec_of(matrix_work);
86 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(
87 std::forward<BackendSelector>(selector), singular_values_op{}, p, value_descriptor, matrix_descriptor);
88
89 uni20::detail::record_output_precision(singular_values, p);
90 uni20::detail::record_output_precision(matrix_work, p);
91}
92
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)
97{
98 auto value_descriptor = uni20::mdspec_of(singular_values);
99 auto left_descriptor = uni20::mdspec_of(left_singular_vectors);
100 auto matrix_descriptor = uni20::mdspec_of(matrix_work);
101 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(
102 std::forward<BackendSelector>(selector), operation, p, value_descriptor, left_descriptor, matrix_descriptor);
103
104 uni20::detail::record_output_precision(singular_values, p);
105 uni20::detail::record_output_precision(left_singular_vectors, p);
106 uni20::detail::record_output_precision(matrix_work, p);
107}
108
109template <KernelBackendSelector BackendSelector, uni20::MutableRankedTensorView<1> SingularValueTensor,
110 uni20::MutableRankedTensorView<2> RightAdjointTensor, 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)
113{
114 auto value_descriptor = uni20::mdspec_of(singular_values);
115 auto right_descriptor = uni20::mdspec_of(right_singular_vectors_adjoint);
116 auto matrix_descriptor = uni20::mdspec_of(matrix_work);
117 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(
118 std::forward<BackendSelector>(selector), operation, p, value_descriptor, right_descriptor, matrix_descriptor);
119
120 uni20::detail::record_output_precision(singular_values, p);
121 uni20::detail::record_output_precision(right_singular_vectors_adjoint, p);
122 uni20::detail::record_output_precision(matrix_work, p);
123}
124} // namespace detail
125
133template <KernelBackendSelector BackendSelector, uni20::MutableRankedTensorView<1> SingularValueTensor,
134 uni20::MutableRankedTensorView<2> LeftTensor, uni20::MutableRankedTensorView<2> RightAdjointTensor,
135 uni20::MutableRankedTensorView<2> MatrixTensor>
136void singular_value_decomposition(BackendSelector&& selector, SingularValueTensor&& singular_values,
137 LeftTensor&& left_singular_vectors,
138 RightAdjointTensor&& right_singular_vectors_adjoint, MatrixTensor&& matrix_work,
139 SvdOptions options = {}, std::optional<Precision> requested = {})
140{
141 auto const p = detail::decomposition_precision(matrix_work, requested);
142 auto operation =
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);
146}
147
151template <uni20::MutableRankedTensorView<1> SingularValueTensor, uni20::MutableRankedTensorView<2> LeftTensor,
152 uni20::MutableRankedTensorView<2> RightAdjointTensor, uni20::MutableRankedTensorView<2> MatrixTensor>
153void singular_value_decomposition(SingularValueTensor&& singular_values, LeftTensor&& left_singular_vectors,
154 RightAdjointTensor&& right_singular_vectors_adjoint, MatrixTensor&& matrix_work,
155 SvdOptions options = {}, std::optional<Precision> requested = {})
156{
157 auto const p = detail::decomposition_precision(matrix_work, requested);
158 auto operation =
159 detail::prepare_svd(singular_values, left_singular_vectors, right_singular_vectors_adjoint, matrix_work, options);
160 auto selector =
161 select_backend(operation, singular_values, left_singular_vectors, right_singular_vectors_adjoint, matrix_work);
162 detail::dispatch_svd(selector, operation, singular_values, left_singular_vectors, right_singular_vectors_adjoint,
163 matrix_work, p);
164}
165
168template <class LeftTensor, class SingularValueTensor> struct SvdLeftResult
169{
171 using singular_value_tensor_type = SingularValueTensor;
172
174 SingularValueTensor singular_values;
175};
176
179template <class SingularValueTensor, class RightAdjointTensor> struct SvdRightResult
180{
181 using singular_value_tensor_type = SingularValueTensor;
183
184 SingularValueTensor singular_values;
186};
187
190template <class LeftTensor, class SingularValueTensor, class RightAdjointTensor> struct SvdResult
191{
193 using singular_value_tensor_type = SingularValueTensor;
195
197 SingularValueTensor singular_values;
199};
200
201namespace detail
202{
203template <class MatrixTensor> using svd_scalar_t = uni20::tensor_element_t<MatrixTensor>;
204template <class MatrixTensor> using svd_real_t = uni20::make_real_t<svd_scalar_t<MatrixTensor>>;
205template <class MatrixTensor> using svd_value_tensor_t = uni20::Tensor<svd_real_t<MatrixTensor>, 1>;
206template <class MatrixTensor> using svd_matrix_tensor_t = uni20::Tensor<svd_scalar_t<MatrixTensor>, 2>;
207
208template <class MatrixTensor>
209using svd_reuse_factor_t =
210 typename std::remove_cvref_t<MatrixTensor>::template rebind_layout_type<stdex::layout_stride>;
211
212template <class MatrixTensor> consteval bool can_transfer_svd_storage()
213{
214 using matrix_type = std::remove_cvref_t<MatrixTensor>;
216 {
217 return false;
218 }
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>;
226 })
227 {
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>;
237 {
238 std::move(matrix).release_accessor_factory()
239 } -> std::same_as<typename factor_type::accessor_factory_type>;
240 {
241 factor_type::adopt_storage(std::move(mapping), std::move(storage), std::move(accessor_factory))
242 } -> std::same_as<factor_type>;
243 };
244 }
245 else
246 {
247 return false;
248 }
249}
250
251template <class FactorTensor> [[nodiscard]] FactorTensor make_svd_factor(std::size_t rows, std::size_t cols)
252{
253 using index_type = typename FactorTensor::index_type;
254 using extents_type = typename FactorTensor::extents_type;
255 return FactorTensor(uni20::uninitialized, extents_type{static_cast<index_type>(rows), static_cast<index_type>(cols)},
257}
258
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
262{
263 using index_type = typename FactorTensor::index_type;
264 using extents_type = typename FactorTensor::extents_type;
265 extents_type extents{static_cast<index_type>(rows), static_cast<index_type>(cols)};
266 return typename FactorTensor::mapping_type(
267 extents, std::array<index_type, 2>{index_type{1}, static_cast<index_type>(leading_dimension)});
268}
269
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)
273{
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));
278}
279
280template <class MatrixTensor> [[nodiscard]] auto direct_column_major_svd_stage(MatrixTensor& matrix)
281{
282 auto stage = uni20::linalg::blas::try_mdspan_matrix_stage(matrix.mdspan());
283 if (!stage || stage->unit_stride_axis != 0 || stage->needs_conjugation)
284 {
285 return decltype(stage){};
286 }
287 return stage;
288}
289
290template <KernelBackendSelector BackendSelector, uni20::OwningTensor MatrixTensor>
292[[nodiscard]] auto singular_values_from_work_matrix(BackendSelector&& selector, MatrixTensor matrix_work, Precision p)
293{
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);
298 return values;
299}
300
301template <KernelBackendSelector BackendSelector, uni20::OwningTensor MatrixTensor>
303[[nodiscard]] auto svd_left_from_work_matrix(BackendSelector&& selector, MatrixTensor matrix_work,
304 SvdVectorExtent extent, Precision p)
305{
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);
309 std::size_t const left_cols = extent == SvdVectorExtent::Full ? rows : rank;
310 svd_matrix_tensor_t<MatrixTensor> left(uni20::uninitialized, rows, left_cols);
311 svd_value_tensor_t<MatrixTensor> values(uni20::uninitialized, rank);
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)};
315}
316
317template <KernelBackendSelector BackendSelector, uni20::OwningTensor MatrixTensor>
319[[nodiscard]] auto svd_right_from_work_matrix(BackendSelector&& selector, MatrixTensor matrix_work,
320 SvdVectorExtent extent, Precision p)
321{
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);
325 std::size_t const right_rows = extent == SvdVectorExtent::Full ? cols : rank;
326 svd_value_tensor_t<MatrixTensor> values(uni20::uninitialized, rank);
327 svd_matrix_tensor_t<MatrixTensor> right(uni20::uninitialized, right_rows, cols);
328 dispatch_svd_right(std::forward<BackendSelector>(selector), svd_right_op{.right = extent}, values, right, matrix_work,
329 p);
330 return SvdRightResult<decltype(values), decltype(right)>{.singular_values = std::move(values),
331 .right_singular_vectors_adjoint = std::move(right)};
332}
333
334template <KernelBackendSelector BackendSelector, uni20::OwningTensor MatrixTensor>
336[[nodiscard]] auto svd_from_work_matrix(BackendSelector&& selector, MatrixTensor matrix_work, SvdOptions options,
337 Precision p)
338{
339 using scalar_type = uni20::tensor_element_t<MatrixTensor>;
340 using real_type = uni20::make_real_t<scalar_type>;
341 uni20::Tensor<scalar_type, 2> left_singular_vectors;
343 uni20::Tensor<scalar_type, 2> right_singular_vectors_adjoint;
344 singular_value_decomposition(std::forward<BackendSelector>(selector), singular_values, left_singular_vectors,
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),
348 .singular_values = std::move(singular_values),
349 .right_singular_vectors_adjoint =
350 std::move(right_singular_vectors_adjoint)};
351}
352
353template <class MatrixTensor> [[nodiscard]] constexpr auto select_singular_values_backend()
354{
355 return select_backend_for<svd_value_tensor_t<MatrixTensor>, std::remove_cvref_t<MatrixTensor>>(singular_values_op{});
356}
357
358template <class MatrixTensor> [[nodiscard]] constexpr auto select_svd_left_backend(SvdVectorExtent extent)
359{
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});
362}
363
364template <class MatrixTensor> [[nodiscard]] constexpr auto select_svd_right_backend(SvdVectorExtent extent)
365{
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});
368}
369
370template <class MatrixTensor> [[nodiscard]] constexpr auto select_svd_backend(SvdOptions options)
371{
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});
375}
376
377template <KernelBackendSelector BackendSelector, class MatrixTensor>
379[[nodiscard]] auto singular_values_from_consumed_matrix(BackendSelector&& selector, MatrixTensor&& matrix, Precision p)
380{
381 if constexpr (can_transfer_svd_storage<MatrixTensor>())
382 {
383 if (direct_column_major_svd_stage(matrix))
384 {
385 svd_value_tensor_t<MatrixTensor> values(uni20::uninitialized, std::min(matrix.extent(0), matrix.extent(1)));
386 dispatch_singular_values(std::forward<BackendSelector>(selector), values, matrix, p);
387 return values;
388 }
389 }
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);
392}
393
394template <KernelBackendSelector BackendSelector, class MatrixTensor>
396 (can_transfer_svd_storage<MatrixTensor>())
397[[nodiscard]] auto svd_left_from_transferable_matrix(BackendSelector&& selector, MatrixTensor&& matrix,
398 SvdVectorExtent extent, Precision p)
399{
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);
405 std::size_t const left_cols = extent == SvdVectorExtent::Full ? rows : rank;
407
408 auto stage = direct_column_major_svd_stage(matrix);
409 if (stage)
410 {
411 if (extent == SvdVectorExtent::Reduced)
412 {
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);
419 })
420 {
421 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(std::forward<BackendSelector>(selector),
422 operation, p, values_span, matrix_span);
423 auto left =
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)};
429 }
430 }
431
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)};
438 }
439
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)};
447}
448
449template <KernelBackendSelector BackendSelector, class MatrixTensor>
451 (can_transfer_svd_storage<MatrixTensor>())
452[[nodiscard]] auto svd_right_from_transferable_matrix(BackendSelector&& selector, MatrixTensor&& matrix,
453 SvdVectorExtent extent, Precision p)
454{
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);
460 std::size_t const right_rows = extent == SvdVectorExtent::Full ? cols : rank;
462
463 auto stage = direct_column_major_svd_stage(matrix);
464 if (stage)
465 {
466 if (extent == SvdVectorExtent::Reduced)
467 {
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);
474 })
475 {
476 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(std::forward<BackendSelector>(selector),
477 operation, p, values_span, matrix_span);
478 auto right =
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)};
484 }
485 }
486
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,
489 p);
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)};
494 }
495
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,
499 p);
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)};
504}
505
506template <KernelBackendSelector BackendSelector, class MatrixTensor>
508 (can_transfer_svd_storage<MatrixTensor>())
509[[nodiscard]] auto svd_from_transferable_matrix(BackendSelector&& selector, MatrixTensor&& matrix, SvdOptions options,
510 Precision p)
511{
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);
517 std::size_t const left_cols = options.left == SvdVectorExtent::Full ? rows : rank;
518 std::size_t const right_rows = options.right == SvdVectorExtent::Full ? cols : rank;
520 factor_type left;
521 factor_type right;
522
523 auto stage = direct_column_major_svd_stage(matrix);
524 if (!stage)
525 {
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);
536 }
537 else if (options.left == SvdVectorExtent::Reduced && (options.right == SvdVectorExtent::Full || rows >= cols))
538 {
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);
547 })
548 {
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);
552 }
553 else
554 {
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);
561 }
562 }
563 else if (options.right == SvdVectorExtent::Reduced)
564 {
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);
573 })
574 {
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);
578 }
579 else
580 {
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);
587 }
588 }
589 else
590 {
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);
600 }
601
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)};
608}
609} // namespace detail
610
612template <KernelBackendSelector BackendSelector, uni20::RankedTensorView<2> MatrixTensor>
613[[nodiscard]] auto singular_values(BackendSelector&& selector, MatrixTensor const& matrix,
614 std::optional<Precision> requested = {})
615{
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);
619}
620
622template <uni20::RankedTensorView<2> MatrixTensor>
623[[nodiscard]] auto singular_values(MatrixTensor const& matrix, std::optional<Precision> requested = {})
624{
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);
629}
630
634template <KernelBackendSelector BackendSelector, class MatrixTensor>
636 (!std::is_lvalue_reference_v<MatrixTensor>) && (!std::is_const_v<std::remove_reference_t<MatrixTensor>>)
637[[nodiscard]] auto singular_values(BackendSelector&& selector, MatrixTensor&& matrix,
638 std::optional<Precision> requested = {})
639{
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);
643}
644
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 = {})
650{
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);
656}
657
659template <KernelBackendSelector BackendSelector, uni20::RankedTensorView<2> MatrixTensor>
660[[nodiscard]] auto svd_left(BackendSelector&& selector, MatrixTensor const& matrix,
661 SvdVectorExtent extent = SvdVectorExtent::Reduced, std::optional<Precision> requested = {})
662{
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);
666}
667
669template <uni20::RankedTensorView<2> MatrixTensor>
670[[nodiscard]] auto svd_left(MatrixTensor const& matrix, SvdVectorExtent extent = SvdVectorExtent::Reduced,
671 std::optional<Precision> requested = {})
672{
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);
677}
678
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,
686 SvdVectorExtent extent = SvdVectorExtent::Reduced, std::optional<Precision> requested = {})
687{
688 auto const p = detail::decomposition_precision(matrix, requested);
689 if constexpr (detail::can_transfer_svd_storage<MatrixTensor>())
690 {
691 return detail::svd_left_from_transferable_matrix(std::forward<BackendSelector>(selector),
692 std::forward<MatrixTensor>(matrix), extent, p);
693 }
694 else
695 {
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,
698 p);
699 }
700}
701
703template <class MatrixTensor>
705 (!std::is_lvalue_reference_v<MatrixTensor>) && (!std::is_const_v<std::remove_reference_t<MatrixTensor>>)
706[[nodiscard]] auto svd_left(MatrixTensor&& matrix, SvdVectorExtent extent = SvdVectorExtent::Reduced,
707 std::optional<Precision> requested = {})
708{
709 auto const p = detail::decomposition_precision(matrix, requested);
710 if constexpr (detail::can_transfer_svd_storage<MatrixTensor>())
711 {
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,
717 p);
718 }
719 else
720 {
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);
724 }
725}
726
728template <KernelBackendSelector BackendSelector, uni20::RankedTensorView<2> MatrixTensor>
729[[nodiscard]] auto svd_right(BackendSelector&& selector, MatrixTensor const& matrix,
730 SvdVectorExtent extent = SvdVectorExtent::Reduced, std::optional<Precision> requested = {})
731{
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);
735}
736
738template <uni20::RankedTensorView<2> MatrixTensor>
739[[nodiscard]] auto svd_right(MatrixTensor const& matrix, SvdVectorExtent extent = SvdVectorExtent::Reduced,
740 std::optional<Precision> requested = {})
741{
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);
746}
747
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,
755 SvdVectorExtent extent = SvdVectorExtent::Reduced, std::optional<Precision> requested = {})
756{
757 auto const p = detail::decomposition_precision(matrix, requested);
758 if constexpr (detail::can_transfer_svd_storage<MatrixTensor>())
759 {
760 return detail::svd_right_from_transferable_matrix(std::forward<BackendSelector>(selector),
761 std::forward<MatrixTensor>(matrix), extent, p);
762 }
763 else
764 {
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,
767 p);
768 }
769}
770
772template <class MatrixTensor>
774 (!std::is_lvalue_reference_v<MatrixTensor>) && (!std::is_const_v<std::remove_reference_t<MatrixTensor>>)
775[[nodiscard]] auto svd_right(MatrixTensor&& matrix, SvdVectorExtent extent = SvdVectorExtent::Reduced,
776 std::optional<Precision> requested = {})
777{
778 auto const p = detail::decomposition_precision(matrix, requested);
779 if constexpr (detail::can_transfer_svd_storage<MatrixTensor>())
780 {
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,
786 p);
787 }
788 else
789 {
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);
793 }
794}
795
801template <KernelBackendSelector BackendSelector, uni20::RankedTensorView<2> MatrixTensor>
802[[nodiscard]] auto svd(BackendSelector&& selector, MatrixTensor const& matrix, SvdOptions options = {},
803 std::optional<Precision> requested = {})
804{
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);
808}
809
813template <uni20::RankedTensorView<2> MatrixTensor>
814[[nodiscard]] auto svd(MatrixTensor const& matrix, SvdOptions options = {}, std::optional<Precision> requested = {})
815{
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);
820}
821
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 = {})
831{
832 auto const p = detail::decomposition_precision(matrix, requested);
833 if constexpr (detail::can_transfer_svd_storage<MatrixTensor>())
834 {
835 return detail::svd_from_transferable_matrix(std::forward<BackendSelector>(selector),
836 std::forward<MatrixTensor>(matrix), options, p);
837 }
838 else
839 {
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);
842 }
843}
844
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 = {})
859{
860 auto const p = detail::decomposition_precision(matrix, requested);
861 if constexpr (detail::can_transfer_svd_storage<MatrixTensor>())
862 {
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};
866 auto selector =
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);
869 }
870 else
871 {
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);
875 }
876}
877
879template <RankedTensorView<2> Matrix> [[nodiscard]] auto svd(Matrix&& matrix, Precision p, SvdOptions options = {})
880{
881 return uni20::linalg::svd(std::forward<Matrix>(matrix), options, std::optional<Precision>{p});
882}
883
885template <KernelBackendSelector Selector, RankedTensorView<2> Matrix>
886[[nodiscard]] auto svd(Selector&& selector, Matrix&& matrix, Precision p, SvdOptions options = {})
887{
888 return uni20::linalg::svd(std::forward<Selector>(selector), std::forward<Matrix>(matrix), options,
889 std::optional<Precision>{p});
890}
891
893template <RankedTensorView<2> Matrix>
894[[nodiscard]] auto svd_left(Matrix&& matrix, Precision p, SvdVectorExtent extent = SvdVectorExtent::Reduced)
895{
896 return uni20::linalg::svd_left(std::forward<Matrix>(matrix), extent, std::optional<Precision>{p});
897}
898
900template <KernelBackendSelector Selector, RankedTensorView<2> Matrix>
901[[nodiscard]] auto svd_left(Selector&& selector, Matrix&& matrix, Precision p,
903{
904 return uni20::linalg::svd_left(std::forward<Selector>(selector), std::forward<Matrix>(matrix), extent,
905 std::optional<Precision>{p});
906}
907
909template <RankedTensorView<2> Matrix>
910[[nodiscard]] auto svd_right(Matrix&& matrix, Precision p, SvdVectorExtent extent = SvdVectorExtent::Reduced)
911{
912 return uni20::linalg::svd_right(std::forward<Matrix>(matrix), extent, std::optional<Precision>{p});
913}
914
916template <KernelBackendSelector Selector, RankedTensorView<2> Matrix>
917[[nodiscard]] auto svd_right(Selector&& selector, Matrix&& matrix, Precision p,
919{
920 return uni20::linalg::svd_right(std::forward<Selector>(selector), std::forward<Matrix>(matrix), extent,
921 std::optional<Precision>{p});
922}
923
925template <MutableRankedTensorView<1> V, MutableRankedTensorView<2> L, MutableRankedTensorView<2> R,
926 MutableRankedTensorView<2> A>
927void singular_value_decomposition(V&& values, L&& left, R&& right, A&& matrix_work, Precision p,
928 SvdOptions options = {})
929{
930 uni20::linalg::singular_value_decomposition(std::forward<V>(values), std::forward<L>(left), std::forward<R>(right),
931 std::forward<A>(matrix_work), options, std::optional<Precision>{p});
932}
933
935template <KernelBackendSelector Selector, MutableRankedTensorView<1> V, MutableRankedTensorView<2> L,
936 MutableRankedTensorView<2> R, MutableRankedTensorView<2> A>
937void singular_value_decomposition(Selector&& selector, V&& values, L&& left, R&& right, A&& matrix_work, Precision p,
938 SvdOptions options = {})
939{
940 uni20::linalg::singular_value_decomposition(std::forward<Selector>(selector), std::forward<V>(values),
941 std::forward<L>(left), std::forward<R>(right),
942 std::forward<A>(matrix_work), options, std::optional<Precision>{p});
943}
944
945} // namespace uni20::linalg
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
MutableImmediateTensorView whose writable mdspan has a specified static rank.
Definition tensor/concepts.hpp:209
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
Backend-independent operation values used with normalized kernel operands.
Definition layout.hpp:64
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.