Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
backends/lapack/svd_least_squares.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "common.hpp"
8#if UNI20_HAS_MPLAPACK_MPREAL
10#endif
11#if UNI20_HAS_MPLAPACK_FLOAT80
13#endif
14
15namespace uni20::linalg
16{
17namespace least_squares_detail
18{
19template <class S>
20concept PackedGelss =
21#if UNI20_HAS_MPLAPACK_MPREAL || UNI20_HAS_MPLAPACK_FLOAT80
22 requires(std::size_t n, std::span<S> a, std::span<make_real_t<S>> values, make_real_t<S> const& cutoff,
23 Precision p) { mplapack::gelss(n, n, n, a, a, values, cutoff, n, p); };
24#else
25 false;
26#endif
27
28template <Real R> void require_svd_options(SvdLeastSquaresOptions<R> const& options)
29{
30 ERROR_IF(options.relative_cutoff && (!uni20::isfinite(*options.relative_cutoff) || *options.relative_cutoff < 0),
31 "SVD least squares requires a finite nonnegative relative cutoff");
32}
33
34template <LapackScalar S>
36 make_real_t<S> const& cutoff, std::size_t& rank)
37{
40 S dummy{}, query{};
41 S* rhs = nrhs ? b.storage().data() : &dummy;
42 blas_int provider_rank = 0;
43 std::vector<make_real_t<S>> rwork;
44 if constexpr (Complex<S>) rwork.resize(*lapack_detail::try_size_product(5, singular.size()));
45 auto call = [&](S* work, blas_int length) {
46 if constexpr (Real<S>)
47 return lapack::unchecked::gelss(m, n, nrhs, a.storage().data(), m, rhs, ldb, singular.data(), cutoff,
48 provider_rank, work, length);
49 else
50 return lapack::unchecked::gelss(m, n, nrhs, a.storage().data(), m, rhs, ldb, singular.data(), cutoff,
51 provider_rank, work, length, rwork.data());
52 };
53 auto code = call(&query, -1);
54 lapack::detail::check_invalid_argument("gelss", code);
55 if (code > 0) return std::size_t(code);
56 auto length = lapack_detail::workspace_size(query);
57 std::vector<S> work(std::size_t(length), S{});
58 code = call(work.data(), length);
59 lapack::detail::check_invalid_argument("gelss", code);
60 if (!code) rank = std::size_t(provider_rank);
61 return std::size_t(code);
62}
63} // namespace least_squares_detail
64
66template <class X, class A, class B, class... P>
67 requires least_squares_detail::Operands<X, A, B> &&
68 least_squares_detail::PrecisionArgs<typename A::value_type, P...> &&
69 (LapackScalar<typename A::value_type> || least_squares_detail::PackedGelss<typename A::value_type>)
77
79template <class X, class A, class B, class... P>
80 requires least_squares_detail::Operands<X, A, B> &&
81 least_squares_detail::PrecisionArgs<typename A::value_type, P...> &&
82 (LapackScalar<typename A::value_type> || least_squares_detail::PackedGelss<typename A::value_type>)
84 std::span<make_real_t<typename A::value_type>> residuals, LeastSquaresInfo& info,
86 SvdLeastSquaresOptions<make_real_t<typename A::value_type>> const& options, P... precision)
87{
88 using S = typename A::value_type;
89 using R = make_real_t<S>;
90 auto p = least_squares_detail::working_precision<S>(precision...);
91 require_precision<S>(p);
92 (void)p.bit_count();
94 std::size_t m = a.extent(0), n = a.extent(1), nrhs = b.extent(1), k = std::min(m, n);
95 ERROR_IF(std::size_t(b.extent(0)) != m || std::size_t(x.extent(0)) != n || std::size_t(x.extent(1)) != nrhs ||
96 residuals.size() != nrhs,
97 "incompatible SVD least-squares shapes");
98 for (auto extent : {m, n, nrhs})
101 info = {};
104 auto as = aa.mdspan();
105 auto bs = ba.mdspan();
107 {
110 }
111 auto av = packed_detail::pack(as, p), bv = packed_detail::pack(bs, p);
112 R cutoff =
113 options.relative_cutoff ? scalar_at_precision<R>(*options.relative_cutoff, p) : numeric_limits<R>::epsilon(p);
114 if (!least_squares_detail::finite(av.mdspan()) || !least_squares_detail::finite(bv.mdspan()) ||
115 !uni20::isfinite(cutoff))
116 {
119 }
120 DenseMatrix<S> solution(n, nrhs, p);
121 std::vector<R> singular(k, scalar_at_precision<R>(0, p));
122 std::size_t rank = 0;
123 if (k)
124 {
125 auto work = av;
126 DenseMatrix<S> rhs(std::max(m, n), nrhs, p);
127 for (std::size_t j = 0; j < nrhs; ++j)
128 for (std::size_t i = 0; i < m; ++i)
129 rhs[i, j] = bv[i, j];
130 std::size_t code = 0;
131 if constexpr (LapackScalar<S>) code = least_squares_detail::native_gelss(work, rhs, singular, cutoff, rank);
132#if UNI20_HAS_MPLAPACK_MPREAL || UNI20_HAS_MPLAPACK_FLOAT80
133 else
134 code = mplapack::gelss(m, n, nrhs, packed_detail::values(work), packed_detail::values(rhs), std::span(singular),
135 cutoff, rank, p);
136#endif
137 if (code)
138 {
139 info = {.status = LeastSquaresStatus::nonconvergence, .unconverged = code};
141 }
142 for (std::size_t j = 0; j < nrhs; ++j)
143 for (std::size_t i = 0; i < n; ++i)
144 solution[i, j] = rhs[i, j];
145 }
146 std::vector<R> norms;
147 if (!least_squares_detail::finite(solution.mdspan()) ||
148 !std::all_of(singular.begin(), singular.end(), [](R const& s) { return uni20::isfinite(s); }) ||
149 !least_squares_detail::residual_norms(av, bv, solution, norms, p))
150 {
153 }
155 auto xs = xa.mdspan();
156 packed_detail::unpack(solution, xs);
157 std::copy_n(norms.begin(), nrhs, residuals.begin());
158 diagnostics = {.rank = rank,
159 .relative_cutoff = std::move(cutoff),
160 .singular_values = options.return_singular_values ? std::move(singular) : std::vector<R>{}};
162}
163} // namespace uni20::linalg
Synchronous packed-array boundary to the serial MPFR/MPC provider.
Safe conversion helpers for the configured signed BLAS integer ABI.
General-purpose owning tensor with immediate or deferred mdspan metadata.
Definition basic_tensor.hpp:109
auto extent(size_type axis) const noexcept
Return one tensor extent.
Definition basic_tensor.hpp:720
storage_type & storage() noexcept
Access the owned storage container.
Definition basic_tensor.hpp:542
auto mdspan() noexcept -> mdspan_type
Resolve a writable mdspan over the owned storage.
Definition basic_tensor.hpp:609
Concept for complex scalar types.
Definition scalar_concepts.hpp:75
Concept for scalar types with a configured dense LAPACK backend.
Definition scalar_concepts.hpp:147
Concept for real scalar types (float, double, etc.).
Definition scalar_concepts.hpp:69
Definition backends/lapack/svd_least_squares.hpp:20
typename make_real< T >::type make_real_t
Alias for the underlying real-valued type of T.
Definition scalar_traits.hpp:168
constexpr bool isfinite(I const &x) noexcept
Returns whether an integer scalar is finite.
Definition math.hpp:121
Checked LAPACK wrappers over provider-specific unchecked overloads.
Shared helpers for LAPACK operation-tag backend adapters.
constexpr blas_int try_blas_int(Value value) noexcept
Convert a non-negative integer to blas_int, or return the negative invalid sentinel.
Definition blas_int.hpp:28
constexpr bool is_valid_blas_int(blas_int value) noexcept
Return whether a non-throwing BLAS integer conversion succeeded.
Definition blas_int.hpp:25
blas_int gelss(blas_int m, blas_int n, blas_int nrhs, uni20::float128 *a, blas_int lda, uni20::float128 *b, blas_int ldb, uni20::float128 *s, uni20::float128 rcond, blas_int &rank, uni20::float128 *work, blas_int lwork)
Definition mplapack/general.hpp:206
blas_int workspace_size(Scalar const &query)
Convert a provider workspace query result to the configured LAPACK integer type.
Definition linalg/backends/lapack/common.hpp:43
constexpr std::optional< std::size_t > try_size_product(std::size_t left, std::size_t right) noexcept
Multiply allocation extents without wrapping std::size_t.
Definition linalg/backends/lapack/common.hpp:69
void require_svd_options(SvdLeastSquaresOptions< R > const &options)
Definition backends/lapack/svd_least_squares.hpp:28
bool residual_norms(DenseMatrix< S > const &av, DenseMatrix< S > const &bv, DenseMatrix< S > const &solution, std::vector< make_real_t< S > > &norms, Precision p)
Definition least_squares_common.hpp:58
bool finite(Matrix const &a)
Definition least_squares_common.hpp:31
std::size_t native_gelss(DenseMatrix< S > &a, DenseMatrix< S > &b, std::vector< make_real_t< S > > &singular, make_real_t< S > const &cutoff, std::size_t &rank)
Definition backends/lapack/svd_least_squares.hpp:35
void unpack(Tensor const &source, Span &target)
Definition packed_matrix.hpp:33
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
@ singular
An exactly zero elimination pivot was found.
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::maybe > kernel_types_maybe
Report that runtime operand values determine backend acceptance.
Definition dispatch_error.hpp:37
std::size_t gelss(std::size_t m, std::size_t n, std::size_t nrhs, std::span< float80 > a, std::span< float80 > b, std::span< float80 > values, float80 const &cutoff, std::size_t &rank, Precision p)
Packed GELSS; B has max(m,n) rows, values has min(m,n) entries.
Definition binary80.cpp:285
Definition data_table.cpp:8
auto acquire_host_read_access_sync(Mdspan const &mdspan)
Acquire a directly host-accessible read-only mdspan.
Definition access.hpp:616
auto acquire_host_write_access_sync(Mdspan &mdspan)
Acquire a directly host-accessible writable mdspan.
Definition access.hpp:626
Backend family for configured dense LAPACK kernels, including MPLAPACK scalar adapters.
Definition backend_selector.hpp:20
Completed numerical attempt; success does not certify rank or conditioning.
Definition least_squares_info.hpp:26
Rank diagnostics for a successful truncated-SVD solution.
Definition svd_least_squares_info.hpp:20
Singular-value truncation policy for minimum-norm least squares.
Definition svd_least_squares_info.hpp:10
std::optional< R > relative_cutoff
Relative cutoff; absent selects epsilon at working precision.
Definition svd_least_squares_info.hpp:14
Preserving minimum-norm SVD least squares with explicit rank diagnostics.
Definition operation_tags.hpp:27
Project-level numeric limits customization point.
Definition numeric_limits.hpp:16
#define ERROR_IF(cond,...)
Definition trace.hpp:389