32using self_adjoint_eigenvalue_extents = stdex::dextents<uni20::index_type, 1>;
34template <uni20::MutableRankedTensorView<1> EigenvalueTensor, uni20::MutableRankedTensorView<2> MatrixTensor>
35[[nodiscard]] self_adjoint_eigh_op prepare_self_adjoint_eigh(EigenvalueTensor& eigenvalues, MatrixTensor& matrix_work,
36 SelfAdjointEighOptions options)
38 ERROR_IF(matrix_work.extent(0) != matrix_work.extent(1),
"self-adjoint eigensystem requires a square matrix");
40 self_adjoint_eigenvalue_extents{
static_cast<uni20::index_type>(matrix_work.extent(0))});
41 return {.compute_vectors = options.compute_vectors, .triangle = options.triangle};
44template <KernelBackendSelector BackendSelector, uni20::MutableRankedTensorView<1> EigenvalueTensor,
45 uni20::MutableRankedTensorView<2> MatrixTensor>
46void dispatch_self_adjoint_eigh(BackendSelector&& selector, self_adjoint_eigh_op operation,
47 EigenvalueTensor& eigenvalues, MatrixTensor& matrix_work, Precision
p)
51 detail::dispatch_at_precision<uni20::tensor_element_t<MatrixTensor>>(
52 std::forward<BackendSelector>(selector), operation,
p, eigenvalue_descriptor, matrix_descriptor);
54 uni20::detail::record_output_precision(eigenvalues,
p);
55 uni20::detail::record_output_precision(matrix_work,
p);
65template <KernelBackendSelector BackendSelector, uni20::MutableRankedTensorView<1> EigenvalueTensor,
66 uni20::MutableRankedTensorView<2> MatrixTensor>
67void self_adjoint_eigh(BackendSelector&& selector, EigenvalueTensor&& eigenvalues, MatrixTensor&& matrix_work,
70 auto const p = detail::decomposition_precision(matrix_work, requested);
71 auto operation = detail::prepare_self_adjoint_eigh(eigenvalues, matrix_work, options);
72 detail::dispatch_self_adjoint_eigh(std::forward<BackendSelector>(selector), operation, eigenvalues, matrix_work,
p);
76template <uni20::MutableRankedTensorView<1> EigenvalueTensor, uni20::MutableRankedTensorView<2> MatrixTensor>
78 std::optional<Precision> requested = {})
80 auto const p = detail::decomposition_precision(matrix_work, requested);
81 auto operation = detail::prepare_self_adjoint_eigh(eigenvalues, matrix_work, options);
82 auto selector =
select_backend(operation, eigenvalues, matrix_work);
83 detail::dispatch_self_adjoint_eigh(selector, operation, eigenvalues, matrix_work,
p);
98template <
class MatrixTensor>
99using self_adjoint_eigh_reuse_matrix_t =
100 std::conditional_t<std::same_as<typename std::remove_cvref_t<MatrixTensor>::layout_type,
uni20::ColumnMajor>,
101 std::remove_cvref_t<MatrixTensor>,
102 typename std::remove_cvref_t<MatrixTensor>::template rebind_layout_type<stdex::layout_stride>>;
104template <
class MatrixTensor>
consteval bool can_transfer_self_adjoint_eigh_storage()
106 using matrix_type = std::remove_cvref_t<MatrixTensor>;
107 if constexpr (
requires {
108 typename matrix_type::storage_policy;
109 typename matrix_type::layout_type;
110 typename matrix_type::accessor_factory_type;
111 typename matrix_type::storage_type;
112 typename matrix_type::template rebind_layout_type<stdex::layout_stride>;
115 using work_type = self_adjoint_eigh_reuse_matrix_t<matrix_type>;
116 return std::same_as<typename matrix_type::storage_policy, uni20::HostStorage> &&
117 std::same_as<typename matrix_type::accessor_factory_type, uni20::DefaultAccessorFactory> &&
119 requires(matrix_type& matrix,
typename work_type::mapping_type mapping,
120 typename work_type::storage_type storage) {
121 { std::move(matrix).release_storage() } -> std::same_as<typename work_type::storage_type>;
122 { work_type::adopt_storage(std::move(mapping), std::move(storage)) } -> std::same_as<work_type>;
140 PANIC(
"invalid MatrixTriangle", std::to_underlying(triangle));
143template <
class WorkMatrix, uni20::RankedTensorView<2> MatrixTensor>
144[[nodiscard]] WorkMatrix materialize_self_adjoint_eigh_work_matrix(MatrixTensor
const& matrix)
146 WorkMatrix result = [&] {
147 if constexpr (std::same_as<typename WorkMatrix::layout_type, uni20::ColumnMajor>)
149 return WorkMatrix(matrix.extents());
160template <
class WorkMatrix, uni20::RankedImmediateTensorView<2> MatrixTensor>
161[[nodiscard]]
auto column_major_reuse_mapping(MatrixTensor
const& matrix, uni20::blas_int leading_dimension) ->
162 typename WorkMatrix::mapping_type
164 if constexpr (std::same_as<typename WorkMatrix::layout_type, uni20::ColumnMajor>)
166 return typename WorkMatrix::mapping_type(matrix.extents());
170 using index_type =
typename WorkMatrix::index_type;
171 return typename WorkMatrix::mapping_type(
172 matrix.extents(), std::array<index_type, 2>{index_type{1},
static_cast<index_type>(leading_dimension)});
176template <
class MatrixTensor>
178[[nodiscard]]
constexpr auto select_self_adjoint_eigh_backend(
MatrixTriangle triangle)
182 return select_backend_for<eigenvalue_tensor, std::remove_cvref_t<MatrixTensor>>(
183 self_adjoint_eigh_op{.compute_vectors =
true, .triangle = triangle});
186template <KernelBackendSelector BackendSelector, uni20::OwningTensor MatrixTensor>
188[[nodiscard]]
auto eigh_from_work_matrix(BackendSelector&& selector, MatrixTensor matrix_work,
MatrixTriangle triangle,
193 self_adjoint_eigh(std::forward<BackendSelector>(selector), eigenvalues, matrix_work,
194 SelfAdjointEighOptions{.compute_vectors =
true, .triangle = triangle},
p);
195 return SelfAdjointEighResult<
decltype(eigenvalues), MatrixTensor>{.eigenvalues = std::move(eigenvalues),
196 .eigenvectors = std::move(matrix_work)};
199template <KernelBackendSelector BackendSelector, uni20::OwningTensor MatrixTensor>
201[[nodiscard]]
auto eigh_from_consumed_matrix(BackendSelector&& selector, MatrixTensor&& matrix,
MatrixTriangle triangle,
204 using matrix_type = std::remove_cvref_t<MatrixTensor>;
205 using work_type = self_adjoint_eigh_reuse_matrix_t<matrix_type>;
207 auto const matrix_span = matrix.mdspan();
209 if (stage && !stage->needs_conjugation)
211 bool const transpose_storage = stage->unit_stride_axis == 1;
212 MatrixTriangle const work_triangle = transpose_storage ? transposed_triangle(triangle) : triangle;
213 auto work_mapping = column_major_reuse_mapping<work_type>(matrix, stage->nonunit_stride);
214 auto storage = std::move(matrix).release_storage();
215 auto work_matrix = work_type::adopt_storage(std::move(work_mapping), std::move(storage));
217 eigh_from_work_matrix(std::forward<BackendSelector>(selector), std::move(work_matrix), work_triangle,
p);
225 auto work_matrix = materialize_self_adjoint_eigh_work_matrix<work_type>(matrix);
226 return eigh_from_work_matrix(std::forward<BackendSelector>(selector), std::move(work_matrix), triangle,
p);
233template <KernelBackendSelector BackendSelector, uni20::RankedTensorView<2> MatrixTensor>
234[[nodiscard]]
auto eigh(BackendSelector&& selector, MatrixTensor
const& matrix,
235 MatrixTriangle triangle = MatrixTriangle::Upper, std::optional<Precision> requested = {})
237 auto const p = detail::decomposition_precision(matrix, requested);
238 ERROR_IF(matrix.extent(0) != matrix.extent(1),
"self-adjoint eigensystem requires a square matrix");
239 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
240 return detail::eigh_from_work_matrix(std::forward<BackendSelector>(selector), std::move(matrix_work), triangle,
p);
247template <uni20::RankedTensorView<2> MatrixTensor>
248[[nodiscard]]
auto eigh(MatrixTensor
const& matrix,
MatrixTriangle triangle = MatrixTriangle::Upper,
249 std::optional<Precision> requested = {})
251 auto const p = detail::decomposition_precision(matrix, requested);
252 ERROR_IF(matrix.extent(0) != matrix.extent(1),
"self-adjoint eigensystem requires a square matrix");
253 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
254 auto selector = detail::select_self_adjoint_eigh_backend<decltype(matrix_work)>(triangle);
255 return detail::eigh_from_work_matrix(std::move(selector), std::move(matrix_work), triangle,
p);
262template <KernelBackendSelector BackendSelector,
class MatrixTensor>
264 (!std::is_lvalue_reference_v<MatrixTensor>) && (!std::is_const_v<std::remove_reference_t<MatrixTensor>>)
265[[nodiscard]]
auto eigh(BackendSelector&& selector, MatrixTensor&& matrix,
266 MatrixTriangle triangle = MatrixTriangle::Upper, std::optional<Precision> requested = {})
268 auto const p = detail::decomposition_precision(matrix, requested);
269 ERROR_IF(matrix.extent(0) != matrix.extent(1),
"self-adjoint eigensystem requires a square matrix");
270 if constexpr (detail::can_transfer_self_adjoint_eigh_storage<MatrixTensor>())
272 return detail::eigh_from_consumed_matrix(std::forward<BackendSelector>(selector),
273 std::forward<MatrixTensor>(matrix), triangle,
p);
277 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
278 return detail::eigh_from_work_matrix(std::forward<BackendSelector>(selector), std::move(matrix_work), triangle,
p);
293template <
class MatrixTensor>
295 (!std::is_lvalue_reference_v<MatrixTensor>) && (!std::is_const_v<std::remove_reference_t<MatrixTensor>>)
296[[nodiscard]]
auto eigh(MatrixTensor&& matrix,
MatrixTriangle triangle = MatrixTriangle::Upper,
297 std::optional<Precision> requested = {})
299 auto const p = detail::decomposition_precision(matrix, requested);
300 ERROR_IF(matrix.extent(0) != matrix.extent(1),
"self-adjoint eigensystem requires a square matrix");
301 if constexpr (detail::can_transfer_self_adjoint_eigh_storage<MatrixTensor>())
303 using work_type = detail::self_adjoint_eigh_reuse_matrix_t<std::remove_cvref_t<MatrixTensor>>;
304 auto selector = detail::select_self_adjoint_eigh_backend<work_type>(triangle);
305 return detail::eigh_from_consumed_matrix(std::move(selector), std::forward<MatrixTensor>(matrix), triangle,
p);
309 auto matrix_work = uni20::make_tensor<uni20::ColumnMajor>(matrix);
310 auto selector = detail::select_self_adjoint_eigh_backend<decltype(matrix_work)>(triangle);
311 return detail::eigh_from_work_matrix(std::move(selector), std::move(matrix_work), triangle,
p);
316template <RankedTensorView<2> Matrix>
319 return uni20::linalg::eigh(std::forward<Matrix>(matrix), triangle, std::optional<Precision>{
p});
323template <KernelBackendSelector Selector, RankedTensorView<2> Matrix>
324[[nodiscard]]
auto eigh(Selector&& selector, Matrix&& matrix,
Precision p,
327 return uni20::linalg::eigh(std::forward<Selector>(selector), std::forward<Matrix>(matrix), triangle,
328 std::optional<Precision>{
p});
332template <MutableRankedTensorView<1> V, MutableRankedTensorView<2> A>
336 std::optional<Precision>{
p});
340template <KernelBackendSelector Selector, MutableRankedTensorView<1> V, MutableRankedTensorView<2> A>
345 std::forward<A>(matrix_work), options, std::optional<Precision>{
p});
LAPACK backend for dense symmetric and Hermitian eigensystems.
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
Concept for complex scalar types.
Definition scalar_concepts.hpp:75
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
TensorView whose readable mdspec has a specified static rank.
Definition tensor/concepts.hpp:149
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.
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
Definition linalg/async.hpp:28
auto eigh(BackendSelector selector, async::Async< MatrixTensor > const &matrix, MatrixTriangle triangle=MatrixTriangle::Upper, std::optional< Precision > requested={})
Schedule a preserving self-adjoint eigensystem through an explicit selector.
Definition async/self_adjoint_eigh.hpp:122
MatrixTriangle
Triangle of a symmetric or Hermitian matrix supplied to an operation.
Definition operation_tags.hpp:226
void self_adjoint_eigh(BackendSelector &&selector, EigenvalueTensor &&eigenvalues, MatrixTensor &&matrix_work, SelfAdjointEighOptions options={}, std::optional< Precision > requested={})
Compute an in-place self-adjoint eigensystem through an explicit selector.
Definition ops/self_adjoint_eigh.hpp:67
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
Definition data_table.cpp:8
Output & prepare_output(Output &output, RequiredExtents const &required)
Prepare a mutable tensor output with the specified shape.
Definition tensor/output.hpp:104
stdex::layout_left ColumnMajor
Conventional column-major contiguous mdspan layout.
Definition tensor.hpp:33
void conjugate_inplace(BackendSelector selector, async::Async< Tensor > &tensor)
Schedule eager in-place conjugation through an explicit selector.
Definition linalg/async/conjugate_inplace.hpp:44
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
void copy(BackendSelector selector, async::Async< OutputTensor > &output, async::Async< InputTensor > const &input)
Schedule a Tensor copy through an explicit backend selector.
Definition linalg/async/copy.hpp:174
std::ptrdiff_t index_type
Definition types.hpp:19
Options for a dense symmetric or Hermitian eigensystem.
Definition operation_tags.hpp:233
Owning eigenvalues and eigenvectors returned by eigh.
Definition ops/self_adjoint_eigh.hpp:88
EigenvalueTensor eigenvalues
Definition ops/self_adjoint_eigh.hpp:92
EigenvalueTensor eigenvalue_tensor_type
Definition ops/self_adjoint_eigh.hpp:89
EigenvectorTensor eigenvector_tensor_type
Definition ops/self_adjoint_eigh.hpp:90
EigenvectorTensor eigenvectors
Definition ops/self_adjoint_eigh.hpp:93
Backend-dispatched in-place conjugation of tensor elements.
Backend-dispatched tensor copies and inferred owning materialization.
Shape preparation contracts for tensor operation outputs.
General-purpose owning tensors with runtime extents.
#define PANIC(...)
Definition trace.hpp:382
#define ERROR_IF(cond,...)
Definition trace.hpp:389