Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
ops/lu.hpp
Go to the documentation of this file.
1#pragma once
2
10#if UNI20_HAS_MPLAPACK_FLOAT80
12#endif
13#include <optional>
14#include <span>
16#include <uni20/tensor/copy.hpp>
19#include <vector>
20
21namespace uni20::linalg
22{
23namespace detail
24{
25struct LuFactorAccess;
26}
27
34template <RealOrComplex S> class LuFactorization {
35 public:
36 using value_type = S;
38 std::size_t order() const noexcept { return std::size_t(factors_.extent(0)); }
40 DenseMatrix<S> const& packed() const& noexcept { return factors_; }
42 std::span<std::size_t const> pivots() const& noexcept { return pivots_; }
44 Precision precision() const { return precision_of(factors_); }
46 std::optional<LuNorms<make_real_t<S>>> const& norms() const& noexcept { return norms_; }
47
48 private:
49 friend struct detail::LuFactorAccess;
50 LuFactorization(DenseMatrix<S>&& factors, std::vector<std::size_t>&& pivots,
51 std::optional<LuNorms<make_real_t<S>>>&& norms)
52 : factors_(std::move(factors)), pivots_(std::move(pivots)), norms_(std::move(norms))
53 {}
54 DenseMatrix<S> factors_;
55 std::vector<std::size_t> pivots_;
56 std::optional<LuNorms<make_real_t<S>>> norms_;
57};
58
60template <RealOrComplex S> struct LuFactorizationResult
61{
63 std::optional<LuFactorization<S>> factor;
64};
65
66namespace detail
67{
68struct LuFactorAccess
69{
70 template <class S>
71 static auto make(DenseMatrix<S>&& factors, std::vector<std::size_t>&& pivots,
72 std::optional<LuNorms<make_real_t<S>>>&& norms)
73 {
74 return LuFactorization<S>(std::move(factors), std::move(pivots), std::move(norms));
75 }
76};
77
78template <KernelBackendSelector Backend, RankedTensorView<2> A>
79auto lu_factor_impl(Backend&& backend, A const& a, LuOptions<make_real_t<tensor_element_t<A>>> const& options,
81{
82 using S = tensor_element_t<A>;
83 ERROR_IF(a.extent(0) != a.extent(1), "LU requires a square matrix");
84 SolveOptions<make_real_t<S>> pivot_options{options.relative_pivot_tolerance};
85 detail::require_solve_options(pivot_options);
86 require_precision<S>(p);
87 (void)p.bit_count();
88 auto work = make_tensor<ColumnMajor>(a);
89 std::vector<std::size_t> pivots(std::size_t(a.extent(0)));
90 LuFactorizationResult<S> result{.info = {}, .factor = {}};
91 std::optional<LuNorms<make_real_t<S>>> norms;
92 if (options.retain_norms) norms.emplace();
93 auto descriptor = mdspec_of(work);
94 dispatch_at_precision<S>(std::forward<Backend>(backend), lu_factor_op{}, p, descriptor, std::span(pivots),
95 norms ? &*norms : nullptr, result.info, pivot_options);
96 if (result.info.succeeded())
97 {
98 uni20::detail::record_output_precision(work, p);
99 result.factor = LuFactorAccess::make(std::move(work), std::move(pivots), std::move(norms));
100 }
101 return result;
102}
103inline void require_lu_success(SolveInfo const& info)
104{
105 ERROR_IF(!info.succeeded(), "LU operation failed", static_cast<int>(info.status));
106}
107} // namespace detail
108
112template <KernelBackendSelector Backend, RankedTensorView<2> A>
113 requires RealOrComplex<tensor_element_t<A>>
114[[nodiscard]] auto lu_factor_with_info(Backend&& backend, A const& a, Precision p,
115 LuOptions<make_real_t<tensor_element_t<A>>> const& options = {})
116{
117 return detail::lu_factor_impl(std::forward<Backend>(backend), a, options, p);
118}
119
124template <KernelBackendSelector Backend, RankedTensorView<2> A>
125 requires RealOrComplex<tensor_element_t<A>>
126[[nodiscard]] auto lu_factor_with_info(Backend&& backend, A const& a,
127 LuOptions<make_real_t<tensor_element_t<A>>> const& options = {})
128{
129 return detail::lu_factor_impl(std::forward<Backend>(backend), a, options, precision_of(a));
130}
131
133template <RankedTensorView<2> A>
134 requires RealOrComplex<tensor_element_t<A>>
135[[nodiscard]] auto lu_factor_with_info(A const& a, LuOptions<make_real_t<tensor_element_t<A>>> const& options = {})
136{
137 auto backend = select_backend_for<DenseMatrix<tensor_element_t<A>>>(lu_factor_op{});
138 return lu_factor_with_info(backend, a, options);
139}
140
142template <RankedTensorView<2> A>
143 requires RealOrComplex<tensor_element_t<A>>
144[[nodiscard]] auto lu_factor_with_info(A const& a, Precision p,
145 LuOptions<make_real_t<tensor_element_t<A>>> const& options = {})
146{
147 auto backend = select_backend_for<DenseMatrix<tensor_element_t<A>>>(lu_factor_op{});
148 return lu_factor_with_info(backend, a, p, options);
149}
150
152template <class... Args>
153 requires requires(Args&&... args) { lu_factor_with_info(std::forward<Args>(args)...); }
154[[nodiscard]] auto lu_factor(Args&&... args)
155{
156 auto result = lu_factor_with_info(std::forward<Args>(args)...);
157 detail::require_lu_success(result.info);
158 return std::move(*result.factor);
159}
160
167template <KernelBackendSelector Backend, RealOrComplex S, MutableRankedTensorView<2> B>
168 requires std::same_as<S, tensor_element_t<B>>
169[[nodiscard]] SolveInfo lu_solve_inplace_with_info(Backend&& backend, LuFactorization<S> const& factor, B&& b)
170{
171 ERROR_IF(factor.order() != std::size_t(b.extent(0)), "LU solve RHS row count mismatch");
172 auto ad = mdspec_of(factor.packed());
173 auto bd = mdspec_of(b);
174 SolveInfo info;
175 auto p = factor.precision();
176 detail::dispatch_at_precision<S>(std::forward<Backend>(backend), lu_solve_op{}, p, ad, factor.pivots(), bd, info);
177 if (info.succeeded() && factor.order() != 0 && b.extent(1) != 0) uni20::detail::record_output_precision(b, p);
178 return info;
179}
180
182template <RealOrComplex S, MutableRankedTensorView<2> B>
183 requires std::same_as<S, tensor_element_t<B>>
184[[nodiscard]] SolveInfo lu_solve_inplace_with_info(LuFactorization<S> const& factor, B&& b)
185{
186 auto backend = select_backend(lu_solve_op{}, factor.packed(), b);
187 return lu_solve_inplace_with_info(backend, factor, std::forward<B>(b));
188}
189
191template <class... Args>
192 requires requires(Args&&... args) { lu_solve_inplace_with_info(std::forward<Args>(args)...); }
193void lu_solve_inplace(Args&&... args)
194{
195 detail::require_lu_success(lu_solve_inplace_with_info(std::forward<Args>(args)...));
196}
197
199template <KernelBackendSelector Backend, RealOrComplex S, RankedTensorView<2> B>
200 requires std::same_as<S, tensor_element_t<B>>
201[[nodiscard]] auto lu_solve(Backend&& backend, LuFactorization<S> const& factor, B const& b)
202{
203 auto result = make_tensor<ColumnMajor>(b);
204 lu_solve_inplace(std::forward<Backend>(backend), factor, result);
205 uni20::detail::record_output_precision(result, factor.precision());
206 return result;
207}
208
210template <RealOrComplex S, RankedTensorView<2> B>
211 requires std::same_as<S, tensor_element_t<B>>
212[[nodiscard]] auto lu_solve(LuFactorization<S> const& factor, B const& b)
213{
214 auto backend = select_backend_for<DenseMatrix<S>, DenseMatrix<S>>(lu_solve_op{});
215 return lu_solve(backend, factor, b);
216}
217} // 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
Immutable owning packed factors satisfying P A = L U.
Definition ops/lu.hpp:34
std::optional< LuNorms< make_real_t< S > > > const & norms() const &noexcept
Original norms at factor precision, absent only when capture was disabled.
Definition ops/lu.hpp:46
std::span< std::size_t const > pivots() const &noexcept
Zero-based swap sequence; at step k exchange rows k and pivots[k].
Definition ops/lu.hpp:42
Precision precision() const
Finite working precision used for these factors and subsequent solves.
Definition ops/lu.hpp:44
DenseMatrix< S > const & packed() const &noexcept
Read-only packed L/U matrix, valid while this object retains its storage.
Definition ops/lu.hpp:40
S value_type
Definition ops/lu.hpp:36
std::size_t order() const noexcept
Matrix order, including zero for a successfully factored empty matrix.
Definition ops/lu.hpp:38
typename make_real< T >::type make_real_t
Alias for the underlying real-valued type of T.
Definition scalar_traits.hpp:168
Definition qnum.hpp:403
void info(checked_format_string< Args... > format, Args &&... args)
Emit an informational display message.
Definition display.hpp:393
Definition linalg/async.hpp:28
void lu_solve_inplace(Args &&... args)
Strict solve in an existing RHS workspace; numerical failure is terminal.
Definition ops/lu.hpp:193
SolveInfo lu_solve_inplace_with_info(Backend &&backend, LuFactorization< S > const &factor, B &&b)
Solve in an existing RHS workspace, preserving the factors on every outcome.
Definition ops/lu.hpp:169
auto lu_factor(Args &&... args)
Return completed owning factors; numerical failure uses the terminal error policy.
Definition ops/lu.hpp:154
auto lu_solve(Backend &&backend, LuFactorization< S > const &factor, B const &b)
Preserve the RHS and return an owning column-major solution at factor precision.
Definition ops/lu.hpp:201
auto lu_factor_with_info(Backend &&backend, A const &a, Precision p, LuOptions< make_real_t< tensor_element_t< A > > > const &options={})
Factor at explicit finite precision, preserving input values and defaults.
Definition ops/lu.hpp:114
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
constexpr Precision precision_of(T const &value)
Read scalar precision without changing any scalar or provider state.
Definition runtime_precision.hpp:53
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
Completed factorization attempt; factor is present exactly on success.
Definition ops/lu.hpp:61
SolveInfo info
Definition ops/lu.hpp:62
std::optional< LuFactorization< S > > factor
Definition ops/lu.hpp:63
Original matrix norms after conversion to factor precision.
Definition lu_info.hpp:20
LU pivot policy and optional capture of original matrix norms.
Definition lu_info.hpp:9
Diagnostics written by a completed numerical attempt, independent of dispatch.
Definition solve_info.hpp:41
Solve using read-only packed LU factors, overwriting an existing RHS.
Definition operation_tags.hpp:171
Backend-dispatched tensor copies and inferred owning materialization.
General-purpose owning tensors with runtime extents.
#define ERROR_IF(cond,...)
Definition trace.hpp:389