Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
decompositions_packed.hpp
Go to the documentation of this file.
1#pragma once
2
9#include "common.hpp"
11#include <algorithm>
12#include <span>
15#include <utility>
16#include <vector>
17
18namespace uni20::linalg
19{
20namespace packed_detail
21{
22template <class A>
25template <class V, class A>
27 std::same_as<typename V::value_type, make_real_t<typename A::value_type>>;
28template <class A, class B>
30 DecompositionMatrix<A> && DecompositionMatrix<B> && std::same_as<typename A::value_type, typename B::value_type>;
31
32template <class A> void require_matrix(A const& a, std::size_t rows, std::size_t cols)
33{
34 CHECK_EQUAL(std::size_t(a.extent(0)), rows);
35 CHECK_EQUAL(std::size_t(a.extent(1)), cols);
36}
37inline char vector_job(SvdVectorExtent extent)
38{
39 switch (extent)
40 {
42 return 'A';
44 return 'S';
45 }
46 PANIC("invalid SVD extent");
47}
48
49template <class V, class A> auto compute_svd(V& v, A& a, char jobu, char jobvt, Precision p)
50{
51 (void)p.bit_count();
52 using S = typename A::value_type;
53 std::size_t m = a.extent(0), n = a.extent(1), k = std::min(m, n);
54 CHECK_EQUAL(std::size_t(v.extent(0)), k);
55 auto work = pack(a, p);
56 DenseMatrix<S> u(uninitialized, m, jobu == 'A' ? m : jobu == 'S' ? k : 0, p);
57 DenseMatrix<S> vh(uninitialized, jobvt == 'A' ? n : jobvt == 'S' ? k : 0, n, p);
58 std::vector<make_real_t<typename A::value_type>> w(k);
59 mplapack::svd(m, n, values(work), w, values(u), values(vh), jobu, jobvt, p);
60 unpack(work, a);
61 for (std::size_t i = 0; i < k; ++i)
62 v[i] = w[i];
63 return std::pair(std::move(u), std::move(vh));
64}
65} // namespace packed_detail
66
68template <packed_detail::DecompositionMatrix A, class X, class Y, class... P>
69 requires packed_detail::SameMatrixScalar<A, X> && packed_detail::SameMatrixScalar<A, Y> &&
70 packed_detail::QrScalar<typename A::value_type> &&
71 packed_detail::KernelPrecision<typename A::value_type, P...>
72consteval auto kernel_accepts_types(LapackBackend, qr_op const&, X&, Y&, A&, P... precision)
73{
74 return kernel_types_yes;
75}
76
78template <packed_detail::DecompositionMatrix A, class X, class Y, class... P>
79 requires packed_detail::SameMatrixScalar<A, X> && packed_detail::SameMatrixScalar<A, Y> &&
80 packed_detail::QrScalar<typename A::value_type> &&
81 packed_detail::KernelPrecision<typename A::value_type, P...>
82KernelAttempt try_kernel(LapackBackend, qr_op const&, X& q, Y& r, A& a, P... precision)
83{
84 auto const p = packed_detail::working_precision<typename A::value_type>(precision...);
85 (void)p.bit_count();
87 [&](auto& xs, auto& ys, auto& as) {
88 std::size_t m = as.extent(0), n = as.extent(1), k = std::min(m, n);
91 auto av = packed_detail::pack(as, p);
92 auto xv = packed_detail::pack(xs, p, false);
93 auto yv = packed_detail::pack(ys, p, false);
99 },
100 q, r, a);
101}
102
104template <packed_detail::DecompositionMatrix A, class X, class Y, class... P>
105 requires packed_detail::SameMatrixScalar<A, X> && packed_detail::SameMatrixScalar<A, Y> &&
106 packed_detail::LqScalar<typename A::value_type> &&
107 packed_detail::KernelPrecision<typename A::value_type, P...>
108consteval auto kernel_accepts_types(LapackBackend, lq_op const&, X&, Y&, A&, P... precision)
109{
110 return kernel_types_yes;
111}
112
114template <packed_detail::DecompositionMatrix A, class X, class Y, class... P>
115 requires packed_detail::SameMatrixScalar<A, X> && packed_detail::SameMatrixScalar<A, Y> &&
116 packed_detail::LqScalar<typename A::value_type> &&
117 packed_detail::KernelPrecision<typename A::value_type, P...>
118KernelAttempt try_kernel(LapackBackend, lq_op const&, X& l, Y& q, A& a, P... precision)
119{
120 auto const p = packed_detail::working_precision<typename A::value_type>(precision...);
121 (void)p.bit_count();
123 [&](auto& xs, auto& ys, auto& as) {
124 std::size_t m = as.extent(0), n = as.extent(1), k = std::min(m, n);
127 auto av = packed_detail::pack(as, p);
128 auto xv = packed_detail::pack(xs, p, false);
129 auto yv = packed_detail::pack(ys, p, false);
131 packed_detail::unpack(av, as);
132 packed_detail::unpack(xv, xs);
133 packed_detail::unpack(yv, ys);
135 },
136 l, q, a);
137}
138
140template <class V, packed_detail::DecompositionMatrix A, class... P>
141 requires packed_detail::EighScalar<typename A::value_type> &&
142 packed_detail::KernelPrecision<typename A::value_type, P...> && packed_detail::DecompositionValues<V, A>
143consteval auto kernel_accepts_types(LapackBackend, self_adjoint_eigh_op const&, V&, A&, P... precision)
144{
145 return kernel_types_yes;
146}
147
149template <class V, packed_detail::DecompositionMatrix A, class... P>
150 requires packed_detail::EighScalar<typename A::value_type> &&
151 packed_detail::KernelPrecision<typename A::value_type, P...> && packed_detail::DecompositionValues<V, A>
152KernelAttempt try_kernel(LapackBackend, self_adjoint_eigh_op const& op, V& v, A& a, P... precision)
153{
154 auto const p = packed_detail::working_precision<typename A::value_type>(precision...);
155 (void)p.bit_count();
157 [&](auto& vs, auto& as) {
158 std::size_t n = as.extent(0);
160 CHECK_EQUAL(std::size_t(vs.extent(0)), n);
162 using S = typename A::value_type;
163 DenseMatrix<S> work(n, n, p);
164 for (std::size_t j = 0; j < n; ++j)
165 for (std::size_t i = 0; i < n; ++i)
166 if (op.triangle == MatrixTriangle::Upper ? i <= j : i >= j)
167 work[i, j] = scalar_at_precision<S>(S(as[i, j]), p);
168 std::vector<make_real_t<typename A::value_type>> w(n);
170 op.triangle == MatrixTriangle::Upper ? 'U' : 'L', p);
171 packed_detail::unpack(work, as);
172 for (std::size_t i = 0; i < n; ++i)
173 vs[i] = w[i];
175 },
176 v, a);
177}
178
180template <packed_detail::DecompositionMatrix A, packed_detail::DecompositionMatrix R, class... P>
181 requires std::same_as<typename R::value_type, complex<make_real_t<typename A::value_type>>> &&
182 packed_detail::EigenScalar<typename A::value_type> &&
183 packed_detail::KernelPrecision<typename A::value_type, P...>
184consteval auto kernel_accepts_types(LapackBackend, nonsymmetric_eigen_op const&, A&, std::span<typename R::value_type>,
185 R&, P... precision)
186{
187 return kernel_types_yes;
188}
189
191template <packed_detail::DecompositionMatrix A, packed_detail::DecompositionMatrix R, class... P>
192 requires std::same_as<typename R::value_type, complex<make_real_t<typename A::value_type>>> &&
193 packed_detail::EigenScalar<typename A::value_type> &&
194 packed_detail::KernelPrecision<typename A::value_type, P...>
195KernelAttempt try_kernel(LapackBackend, nonsymmetric_eigen_op const& op, A& a, std::span<typename R::value_type> v,
196 R& r, P... precision)
197{
198 auto const p = packed_detail::working_precision<typename A::value_type>(precision...);
199 (void)p.bit_count();
201 [&](auto& as, auto& rs) {
202 std::size_t n = as.extent(0);
204 CHECK_EQUAL(v.size(), n);
206 auto work = packed_detail::pack(as, p);
209 packed_detail::unpack(work, as);
210 if (op.compute_right_vectors) packed_detail::unpack(vectors, rs);
212 },
213 a, r);
214}
215
217template <class V, packed_detail::DecompositionMatrix A, class... P>
218 requires packed_detail::SvdScalar<typename A::value_type> &&
219 packed_detail::KernelPrecision<typename A::value_type, P...> && packed_detail::DecompositionValues<V, A>
220consteval auto kernel_accepts_types(LapackBackend, singular_values_op const& op, V& v, A& a, P... precision)
221{
222 return kernel_types_yes;
223}
224
226template <class V, packed_detail::DecompositionMatrix A, class... P>
227 requires packed_detail::SvdScalar<typename A::value_type> &&
228 packed_detail::KernelPrecision<typename A::value_type, P...> && packed_detail::DecompositionValues<V, A>
229KernelAttempt try_kernel(LapackBackend, singular_values_op const& op, V& v, A& a, P... precision)
230{
231 auto const p = packed_detail::working_precision<typename A::value_type>(precision...);
233 [&](auto& vs, auto& as) {
234 (void)op;
235 [[maybe_unused]] auto factors = packed_detail::compute_svd(vs, as, 'N', 'N', p);
236
238 },
239 v, a);
240}
241
243template <class V, packed_detail::DecompositionMatrix A, class... P>
244 requires packed_detail::SvdScalar<typename A::value_type> &&
245 packed_detail::KernelPrecision<typename A::value_type, P...> && packed_detail::DecompositionValues<V, A>
246consteval auto kernel_accepts_types(LapackBackend, svd_left_op const& op, V& v, A& a, P... precision)
247{
248 return kernel_types_yes;
249}
250
252template <class V, packed_detail::DecompositionMatrix A, class... P>
253 requires packed_detail::SvdScalar<typename A::value_type> &&
254 packed_detail::KernelPrecision<typename A::value_type, P...> && packed_detail::DecompositionValues<V, A>
255KernelAttempt try_kernel(LapackBackend, svd_left_op const& op, V& v, A& a, P... precision)
256{
257 auto const p = packed_detail::working_precision<typename A::value_type>(precision...);
259 [&](auto& vs, auto& as) {
261 [[maybe_unused]] auto factors = packed_detail::compute_svd(vs, as, 'O', 'N', p);
262
264 },
265 v, a);
266}
267
269template <class V, packed_detail::DecompositionMatrix A, class... P>
270 requires packed_detail::SvdScalar<typename A::value_type> &&
271 packed_detail::KernelPrecision<typename A::value_type, P...> && packed_detail::DecompositionValues<V, A>
272consteval auto kernel_accepts_types(LapackBackend, svd_right_op const& op, V& v, A& a, P... precision)
273{
274 return kernel_types_yes;
275}
276
278template <class V, packed_detail::DecompositionMatrix A, class... P>
279 requires packed_detail::SvdScalar<typename A::value_type> &&
280 packed_detail::KernelPrecision<typename A::value_type, P...> && packed_detail::DecompositionValues<V, A>
281KernelAttempt try_kernel(LapackBackend, svd_right_op const& op, V& v, A& a, P... precision)
282{
283 auto const p = packed_detail::working_precision<typename A::value_type>(precision...);
285 [&](auto& vs, auto& as) {
287 [[maybe_unused]] auto factors = packed_detail::compute_svd(vs, as, 'N', 'O', p);
288
290 },
291 v, a);
292}
293
295template <class V, packed_detail::DecompositionMatrix A, class L, class... P>
296 requires packed_detail::SameMatrixScalar<A, L> && packed_detail::SvdScalar<typename A::value_type> &&
297 packed_detail::KernelPrecision<typename A::value_type, P...> && packed_detail::DecompositionValues<V, A>
298consteval auto kernel_accepts_types(LapackBackend, svd_left_op const& op, V& v, L& l, A& a, P... precision)
299{
300 return kernel_types_yes;
301}
302
304template <class V, packed_detail::DecompositionMatrix A, class L, class... P>
305 requires packed_detail::SameMatrixScalar<A, L> && packed_detail::SvdScalar<typename A::value_type> &&
306 packed_detail::KernelPrecision<typename A::value_type, P...> && packed_detail::DecompositionValues<V, A>
307KernelAttempt try_kernel(LapackBackend, svd_left_op const& op, V& v, L& l, A& a, P... precision)
308{
309 auto const p = packed_detail::working_precision<typename A::value_type>(precision...);
311 [&](auto& vs, auto& ls, auto& as) {
312 std::size_t m = as.extent(0), n = as.extent(1), k = std::min(m, n);
315 [[maybe_unused]] auto factors = packed_detail::compute_svd(vs, as, packed_detail::vector_job(op.left), 'N', p);
316 packed_detail::unpack(factors.first, ls);
318 },
319 v, l, a);
320}
321
323template <class V, packed_detail::DecompositionMatrix A, class R, class... P>
324 requires packed_detail::SameMatrixScalar<A, R> && packed_detail::SvdScalar<typename A::value_type> &&
325 packed_detail::KernelPrecision<typename A::value_type, P...> && packed_detail::DecompositionValues<V, A>
326consteval auto kernel_accepts_types(LapackBackend, svd_right_op const& op, V& v, R& r, A& a, P... precision)
327{
328 return kernel_types_yes;
329}
330
332template <class V, packed_detail::DecompositionMatrix A, class R, class... P>
333 requires packed_detail::SameMatrixScalar<A, R> && packed_detail::SvdScalar<typename A::value_type> &&
334 packed_detail::KernelPrecision<typename A::value_type, P...> && packed_detail::DecompositionValues<V, A>
335KernelAttempt try_kernel(LapackBackend, svd_right_op const& op, V& v, R& r, A& a, P... precision)
336{
337 auto const p = packed_detail::working_precision<typename A::value_type>(precision...);
339 [&](auto& vs, auto& rs, auto& as) {
340 std::size_t m = as.extent(0), n = as.extent(1), k = std::min(m, n);
343 [[maybe_unused]] auto factors = packed_detail::compute_svd(vs, as, 'N', packed_detail::vector_job(op.right), p);
344 packed_detail::unpack(factors.second, rs);
346 },
347 v, r, a);
348}
349
351template <class V, packed_detail::DecompositionMatrix A, class L, class R, class... P>
352 requires packed_detail::SameMatrixScalar<A, L> && packed_detail::SameMatrixScalar<A, R> &&
353 packed_detail::SvdScalar<typename A::value_type> &&
354 packed_detail::KernelPrecision<typename A::value_type, P...> && packed_detail::DecompositionValues<V, A>
355consteval auto kernel_accepts_types(LapackBackend, svd_op const& op, V& v, L& l, R& r, A& a, P... precision)
356{
357 return kernel_types_yes;
358}
359
361template <class V, packed_detail::DecompositionMatrix A, class L, class R, class... P>
362 requires packed_detail::SameMatrixScalar<A, L> && packed_detail::SameMatrixScalar<A, R> &&
363 packed_detail::SvdScalar<typename A::value_type> &&
364 packed_detail::KernelPrecision<typename A::value_type, P...> && packed_detail::DecompositionValues<V, A>
365KernelAttempt try_kernel(LapackBackend, svd_op const& op, V& v, L& l, R& r, A& a, P... precision)
366{
367 auto const p = packed_detail::working_precision<typename A::value_type>(precision...);
369 [&](auto& vs, auto& ls, auto& rs, auto& as) {
370 std::size_t m = as.extent(0), n = as.extent(1), k = std::min(m, n);
374 [[maybe_unused]] auto factors = packed_detail::compute_svd(vs, as, packed_detail::vector_job(op.left),
376 packed_detail::unpack(factors.first, ls);
377 packed_detail::unpack(factors.second, rs);
379 },
380 v, l, r, a);
381}
382
384template <class V, packed_detail::DecompositionMatrix A, class F, class... P>
385 requires packed_detail::SameMatrixScalar<A, F> && packed_detail::SvdScalar<typename A::value_type> &&
386 packed_detail::KernelPrecision<typename A::value_type, P...> && packed_detail::DecompositionValues<V, A>
387consteval auto kernel_accepts_types(LapackBackend, svd_op const& op, V& v, F& f, A& a, P... precision)
388{
389 return kernel_types_yes;
390}
391
393template <class V, packed_detail::DecompositionMatrix A, class F, class... P>
394 requires packed_detail::SameMatrixScalar<A, F> && packed_detail::SvdScalar<typename A::value_type> &&
395 packed_detail::KernelPrecision<typename A::value_type, P...> && packed_detail::DecompositionValues<V, A>
396KernelAttempt try_kernel(LapackBackend, svd_op const& op, V& v, F& f, A& a, P... precision)
397{
398 auto const p = packed_detail::working_precision<typename A::value_type>(precision...);
400 [&](auto& vs, auto& fs, auto& as) {
401 std::size_t m = as.extent(0), n = as.extent(1), k = std::min(m, n);
404 {
407 }
408 else
409 {
412 }
413 [[maybe_unused]] auto factors = packed_detail::compute_svd(
417 packed_detail::unpack(factors.second, fs);
418 else
419 packed_detail::unpack(factors.first, fs);
421 },
422 v, f, a);
423}
424} // namespace uni20::linalg
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
Mutable mdspec metadata supporting host write acquisition.
Definition access.hpp:694
Mutable mdspec-like type with a specified static rank.
Definition mdspan/concepts.hpp:487
Concept for types that are either real or complex.
Definition scalar_concepts.hpp:87
Definition decompositions_packed.hpp:23
Definition decompositions_packed.hpp:26
Definition decompositions_packed.hpp:29
Shared helpers for LAPACK operation-tag backend adapters.
KernelAttempt with_host_write_mdspans(Function &&function, Mdspecs &... mdspecs)
Invoke a LAPACK attempt with host-writable mdspans under simultaneous leases.
Definition linalg/backends/lapack/common.hpp:29
char vector_job(SvdVectorExtent extent)
Definition decompositions_packed.hpp:37
void require_matrix(A const &a, std::size_t rows, std::size_t cols)
Definition decompositions_packed.hpp:32
void unpack(Tensor const &source, Span &target)
Definition packed_matrix.hpp:33
auto compute_svd(V &v, A &a, char jobu, char jobvt, Precision p)
Definition decompositions_packed.hpp:49
auto pack(Span const &span, Precision p, bool read=true)
Definition packed_matrix.hpp:19
auto values(Tensor &tensor)
Definition packed_matrix.hpp:29
Definition linalg/async.hpp:28
KernelAttempt try_kernel(BlasBackend, gemm_op const &, C &c, S const &alpha, A &a, B &b, S const &beta)
Pack logical host values and execute GEMM through value-preserving provider conversion.
Definition linalg/backends/blas/binary80.hpp:30
KernelAttempt
Result of one runtime kernel backend attempt.
Definition kernel_attempt.hpp:27
SvdVectorExtent
Extent policy for one side of an exact singular value decomposition.
Definition operation_tags.hpp:248
consteval auto kernel_accepts_types(BlasBackend, gemm_op const &, C &, S const &, A &, B &, S const &)
Accept host-readable native binary80 operands, including transforming accessors.
Definition linalg/backends/blas/binary80.hpp:19
constexpr KernelAcceptance< KernelTypeAcceptance::yes > kernel_types_yes
Report that a backend accepts every instance of the argument types.
Definition dispatch_error.hpp:40
void eigen(std::size_t n, std::span< float80 > a, std::span< complex160 > values, std::span< complex160 > vectors, bool compute_vectors, Precision p)
Compute unsorted complex eigenvalues and optional right eigenvectors, destroying a.
Definition binary80.cpp:248
void lq(std::size_t m, std::size_t n, std::span< float80 > a, std::span< float80 > q, std::span< float80 > triangular, Precision p)
Overwrite m-by-n input work and return Q (k-by-n) and L (m-by-k), k=min(m,n).
Definition binary80.cpp:231
void eigh(std::size_t n, std::span< float80 > a, std::span< float80 > values, bool vectors, char triangle, Precision p)
Compute ascending eigenvalues and optionally overwrite a with eigenvector columns.
Definition binary80.cpp:237
void svd(std::size_t m, std::size_t n, std::span< float80 > a, std::span< float80 > values, std::span< float80 > u, std::span< float80 > vh, char jobu, char jobvt, Precision p)
Compute descending singular values and requested U/Vh factors, destroying a.
Definition binary80.cpp:242
void qr(std::size_t m, std::size_t n, std::span< float80 > a, std::span< float80 > q, std::span< float80 > triangular, Precision p)
Overwrite m-by-n input work and return Q (m-by-k) and R (k-by-n), k=min(m,n).
Definition binary80.cpp:225
Definition data_table.cpp:8
constexpr uninitialized_t uninitialized
Explicit allocation tag for overwrite outputs and scratch space.
Definition common/initialization.hpp:22
Backend-independent operation values used with normalized kernel operands.
Per-operation eligibility for compiled value-converting provider adapters.
Logical host packing for value-converting BLAS and LAPACK adapters.
Backend family for configured dense LAPACK kernels, including MPLAPACK scalar adapters.
Definition backend_selector.hpp:20
Reduced dense real LQ factorization operation tag.
Definition operation_tags.hpp:187
Dense nonsymmetric eigensystem operation tag.
Definition operation_tags.hpp:308
bool compute_right_vectors
Definition operation_tags.hpp:310
Reduced dense real QR factorization operation tag.
Definition operation_tags.hpp:179
Dense symmetric or Hermitian eigensystem operation tag.
Definition operation_tags.hpp:240
bool compute_vectors
Definition operation_tags.hpp:242
MatrixTriangle triangle
Definition operation_tags.hpp:243
Exact dense singular-values-only operation tag.
Definition operation_tags.hpp:270
Exact dense left singular-vector operation tag.
Definition operation_tags.hpp:276
SvdVectorExtent left
Definition operation_tags.hpp:278
bool overwrite_input
Definition operation_tags.hpp:279
Exact dense singular value decomposition operation tag.
Definition operation_tags.hpp:292
SvdVectorExtent left
Definition operation_tags.hpp:294
SvdVectorExtent right
Definition operation_tags.hpp:295
SvdOverwrite overwrite
Definition operation_tags.hpp:296
Exact dense right singular-vector operation tag.
Definition operation_tags.hpp:284
SvdVectorExtent right
Definition operation_tags.hpp:286
bool overwrite_input
Definition operation_tags.hpp:287
#define CHECK(cond,...)
Definition trace.hpp:299
#define PANIC(...)
Definition trace.hpp:382
#define CHECK_EQUAL(a, b,...)
Definition trace.hpp:309