Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
ops/linear_solve.hpp
Go to the documentation of this file.
1#pragma once
2
18#include <uni20/tensor/copy.hpp>
21#if UNI20_HAS_MPLAPACK_FLOAT80
23#endif
24
25#include <concepts>
26#include <type_traits>
27#include <utility>
28
29namespace uni20::linalg
30{
31namespace detail
32{
33template <class CoefficientTensor, class RhsTensor>
34concept CompatibleLinearSolveTensors =
37 std::same_as<uni20::tensor_element_t<CoefficientTensor>, uni20::tensor_element_t<RhsTensor>>;
38
39template <uni20::RankedTensorView<2> CoefficientTensor, uni20::RankedTensorView<2> RhsTensor>
40void require_linear_solve_shape(CoefficientTensor const& coefficients, RhsTensor const& right_hand_sides)
41{
42 ERROR_IF(coefficients.extent(0) != coefficients.extent(1), "solve requires a square coefficient matrix");
43 ERROR_IF(coefficients.extent(0) != right_hand_sides.extent(0),
44 "solve coefficient and right-hand-side row counts do not agree");
45}
46
47inline void require_solve_success(SolveInfo const& info)
48{
49 ERROR_IF(info.status == SolveStatus::singular, "found a singular matrix in solve");
50 ERROR_IF(info.status == SolveStatus::nonfinite_input, "nonfinite input in solve");
51 ERROR_IF(!info.succeeded(), "nonfinite result or rejected pivot in solve");
52}
53} // namespace detail
54
59template <KernelBackendSelector BackendSelector, class A, class B>
60 requires detail::CompatibleLinearSolveTensors<A, B>
61[[nodiscard]] SolveInfo solve_inplace_with_info(BackendSelector&& selector, A&& a, B&& b, Precision p,
62 SolveOptions<make_real_t<tensor_element_t<A>>> const& options = {})
63{
64 require_precision<tensor_element_t<A>>(p);
65 (void)p.bit_count();
66 detail::require_linear_solve_shape(a, b);
67 detail::require_solve_options(options);
68 auto ad = mdspec_of(a);
69 auto bd = mdspec_of(b);
70 SolveInfo info;
71 detail::dispatch_at_precision<tensor_element_t<A>>(std::forward<BackendSelector>(selector), linear_solve_op{}, p, ad,
72 bd, info, options);
73 if (info.succeeded() && a.extent(0) != 0 && b.extent(1) != 0)
74 {
75 uni20::detail::record_output_precision(a, p);
76 uni20::detail::record_output_precision(b, p);
77 }
78 return info;
79}
80
95template <KernelBackendSelector BackendSelector, class CoefficientTensor, class RhsTensor>
96 requires detail::CompatibleLinearSolveTensors<CoefficientTensor, RhsTensor>
98 BackendSelector&& selector, CoefficientTensor&& coefficients, RhsTensor&& right_hand_sides,
100{
101 return solve_inplace_with_info(std::forward<BackendSelector>(selector), std::forward<CoefficientTensor>(coefficients),
102 std::forward<RhsTensor>(right_hand_sides),
103 common_default_precision(coefficients, right_hand_sides), options);
104}
105
110template <class CoefficientTensor, class RhsTensor>
111 requires detail::CompatibleLinearSolveTensors<CoefficientTensor, RhsTensor>
113 CoefficientTensor&& coefficients, RhsTensor&& right_hand_sides,
115{
116 auto selector = select_backend(linear_solve_op{}, coefficients, right_hand_sides);
117 return solve_inplace_with_info(selector, std::forward<CoefficientTensor>(coefficients),
118 std::forward<RhsTensor>(right_hand_sides), options);
119}
120
128template <KernelBackendSelector BackendSelector, class CoefficientTensor, class RhsTensor>
129 requires detail::CompatibleLinearSolveTensors<CoefficientTensor, RhsTensor>
130void solve_inplace(BackendSelector&& selector, CoefficientTensor&& coefficients, RhsTensor&& right_hand_sides,
131 std::optional<Precision> requested = {})
132{
133 auto const info =
134 solve_inplace_with_info(std::forward<BackendSelector>(selector), std::forward<CoefficientTensor>(coefficients),
135 std::forward<RhsTensor>(right_hand_sides),
136 requested ? *requested : common_default_precision(coefficients, right_hand_sides));
137 detail::require_solve_success(info);
138}
139
141template <class CoefficientTensor, class RhsTensor>
142 requires detail::CompatibleLinearSolveTensors<CoefficientTensor, RhsTensor>
143void solve_inplace(CoefficientTensor&& coefficients, RhsTensor&& right_hand_sides, std::optional<Precision> p = {})
144{
145 detail::require_linear_solve_shape(coefficients, right_hand_sides);
146 auto selector = select_backend(linear_solve_op{}, coefficients, right_hand_sides);
147 solve_inplace(selector, std::forward<CoefficientTensor>(coefficients), std::forward<RhsTensor>(right_hand_sides), p);
148}
149
153template <KernelBackendSelector BackendSelector, uni20::RankedTensorView<2> CoefficientTensor,
154 uni20::RankedTensorView<2> RhsTensor>
156 std::same_as<uni20::tensor_element_t<CoefficientTensor>, uni20::tensor_element_t<RhsTensor>>
157[[nodiscard]] auto solve(BackendSelector&& selector, CoefficientTensor const& coefficients,
158 RhsTensor const& right_hand_sides, std::optional<Precision> requested = {})
159{
160 auto p = requested ? *requested : common_default_precision(coefficients, right_hand_sides);
161 require_precision<tensor_element_t<CoefficientTensor>>(p);
162 detail::require_linear_solve_shape(coefficients, right_hand_sides);
163 auto coefficient_work = uni20::make_tensor<uni20::ColumnMajor>(coefficients);
164 auto solution = uni20::make_tensor<uni20::ColumnMajor>(right_hand_sides);
165 solve_inplace(std::forward<BackendSelector>(selector), coefficient_work, solution, p);
166 uni20::detail::record_output_precision(solution, p);
167 return solution;
168}
169
171template <uni20::RankedTensorView<2> CoefficientTensor, uni20::RankedTensorView<2> RhsTensor>
173 std::same_as<uni20::tensor_element_t<CoefficientTensor>, uni20::tensor_element_t<RhsTensor>>
174[[nodiscard]] auto solve(CoefficientTensor const& coefficients, RhsTensor const& right_hand_sides,
175 std::optional<Precision> requested = {})
176{
177 using work_type = decltype(uni20::make_tensor<uni20::ColumnMajor>(right_hand_sides));
178 auto selector = select_backend_for<work_type, work_type>(linear_solve_op{});
179 return solve(selector, coefficients, right_hand_sides, requested);
180}
181
183template <class A, class B>
184 requires detail::CompatibleLinearSolveTensors<A, B>
185[[nodiscard]] SolveInfo solve_inplace_with_info(A&& a, B&& b, Precision p,
186 SolveOptions<make_real_t<tensor_element_t<A>>> const& options = {})
187{
188 auto selector = select_backend(linear_solve_op{}, a, b);
189 return solve_inplace_with_info(selector, std::forward<A>(a), std::forward<B>(b), p, options);
190}
191
192} // namespace uni20::linalg
Reference CPU backend for dense general linear systems.
LAPACK backend for dense general linear systems.
Exact arithmetic or an explicit binary working precision.
Definition core/precision.hpp:13
MutableTensorView with a specified static rank.
Definition tensor/concepts.hpp:166
Concept for types that are either real or complex.
Definition scalar_concepts.hpp:87
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
void info(checked_format_string< Args... > format, Args &&... args)
Emit an informational display message.
Definition display.hpp:393
Definition linalg/async.hpp:28
auto solve(BackendSelector selector, async::Async< CoefficientTensor > const &coefficients, async::Async< RhsTensor > const &right_hand_sides, std::optional< Precision > p={})
Schedule a preserving dense general solve through an explicit selector.
Definition async/linear_solve.hpp:100
@ nonfinite_input
An input coefficient or RHS component was nonfinite; both workspaces are preserved.
@ singular
An exactly zero elimination pivot was found.
SolveInfo solve_inplace_with_info(BackendSelector &&selector, A &&a, B &&b, Precision p, SolveOptions< make_real_t< tensor_element_t< A > > > const &options={})
Solve in place at an explicit operation precision, independent of workspace defaults.
Definition ops/linear_solve.hpp:61
void solve_inplace(BackendSelector selector, async::Async< CoefficientTensor > &coefficients, async::Async< RhsTensor > &right_hand_sides, std::optional< Precision > p={})
Schedule a destructive dense general solve through an explicit selector.
Definition async/linear_solve.hpp:125
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 common_default_precision(A const &a, B const &b)
Select a binary operation's default without inspecting element precisions.
Definition tensor/precision.hpp:43
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
Backend-independent operation values used with normalized kernel operands.
Diagnostics written by a completed numerical attempt, independent of dispatch.
Definition solve_info.hpp:41
Real-scalar pivot policy for a square linear solve.
Definition solve_info.hpp:62
Concepts for tensor-level objects that resolve mdspan kernel operands.
Backend-dispatched tensor copies and inferred owning materialization.
General-purpose owning tensors with runtime extents.
#define ERROR_IF(cond,...)
Definition trace.hpp:389