Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
cpu/lu_common.hpp
Go to the documentation of this file.
1#pragma once
2
6
7namespace uni20::linalg::detail::cpu_reference
8{
9template <class MatrixMdspan>
10void swap_rows(MatrixMdspan& matrix, std::size_t lhs, std::size_t rhs, std::size_t columns)
11{
12 if (lhs == rhs) return;
13 using index_type = typename std::remove_cvref_t<MatrixMdspan>::index_type;
14 for (std::size_t col = 0; col < columns; ++col)
15 {
16 auto const left_index = static_cast<index_type>(lhs);
17 auto const right_index = static_cast<index_type>(rhs);
18 auto const column = static_cast<index_type>(col);
19 auto temporary = static_cast<typename std::remove_cvref_t<MatrixMdspan>::value_type>(matrix[left_index, column]);
20 auto right_value = static_cast<typename std::remove_cvref_t<MatrixMdspan>::value_type>(matrix[right_index, column]);
21 matrix[left_index, column] = right_value;
22 matrix[right_index, column] = temporary;
23 }
24}
25
26// Values already have the operation precision. Keep the arithmetic shared by
27// native kernels, runtime-precision adapters and the one-shot runtime solve.
28template <class Matrix>
29KernelAttempt lu_factor(Matrix& s, std::span<std::size_t> pivots,
30 LuNorms<make_real_t<typename Matrix::value_type>>* norms, SolveInfo& info,
31 SolveOptions<make_real_t<typename Matrix::value_type>> const& options,
32 make_real_t<typename Matrix::value_type> const& zero)
33{
34 using S = typename Matrix::value_type;
35 info = {};
36 if (!detail::solve_matrix_is_finite(s))
37 {
40 }
41 detail::capture_lu_norms(s, norms, zero);
42 auto scale = detail::lu_input_scale(s, zero);
43 auto n = pivots.size();
44 // Public factors are column-major; direct kernel callers may supply other layouts.
45 bool rows_inner = true;
46 if constexpr (StridedMdspanLike<decltype(s)>) rows_inner = s.stride(0) <= s.stride(1);
47 auto update_entry = [&](std::size_t i, std::size_t j, S const& multiplier, S const& upper) {
48 S value = S(s[i, j]) - multiplier * upper;
50 {
52 return false;
53 }
54 s[i, j] = value;
55 return true;
56 };
57 for (std::size_t k = 0; k < n; ++k)
58 {
59 auto magnitude = detail::lu_magnitude(S(s[k, k]));
60 std::size_t pivot = k;
61 for (std::size_t i = k + 1; i < n; ++i)
62 {
63 auto candidate = detail::lu_magnitude(S(s[i, k]));
64 if (detail::lu_magnitude_less(magnitude, candidate))
65 {
66 magnitude = std::move(candidate);
67 pivot = i;
68 }
69 }
70 if (magnitude.scale == 0)
71 info = {.status = SolveStatus::singular, .pivot = k};
72 else if (detail::lu_small_pivot(magnitude, scale, options.relative_pivot_tolerance))
73 info = {.status = SolveStatus::small_pivot, .pivot = k};
74 if (!info.succeeded()) return KernelAttempt::success;
75 pivots[k] = pivot;
76 // Previously computed columns of L must participate in the row swap.
77 detail::cpu_reference::swap_rows(s, k, pivot, n);
78 for (std::size_t i = k + 1; i < n; ++i)
79 {
80 S multiplier = S(s[i, k]) / S(s[k, k]);
81 if (!uni20::isfinite(multiplier))
82 {
85 }
86 s[i, k] = multiplier;
87 }
88 if (rows_inner)
89 {
90 for (std::size_t j = k + 1; j < n; ++j)
91 {
92 S upper = s[k, j];
93 for (std::size_t i = k + 1; i < n; ++i)
94 if (!update_entry(i, j, S(s[i, k]), upper)) return KernelAttempt::success;
95 }
96 }
97 else
98 {
99 for (std::size_t i = k + 1; i < n; ++i)
100 {
101 S multiplier = s[i, k];
102 for (std::size_t j = k + 1; j < n; ++j)
103 if (!update_entry(i, j, multiplier, S(s[k, j]))) return KernelAttempt::success;
104 }
105 }
106 }
108}
109
110template <class Matrix, class Rhs>
111KernelAttempt lu_solve(Matrix const& as, std::span<std::size_t const> pivots, Rhs& bs, SolveInfo& info)
112{
113 info = {};
114 using S = typename Matrix::value_type;
115 if (!detail::solve_matrix_is_finite(bs))
116 {
119 }
120 auto n = pivots.size();
121 auto count = std::size_t(bs.extent(1));
122 for (std::size_t k = 0; k < n; ++k)
123 detail::cpu_reference::swap_rows(bs, k, pivots[k], count);
124 for (std::size_t col = 0; col < count; ++col)
125 {
126 for (std::size_t i = 0; i < n; ++i)
127 {
128 S value = bs[i, col];
129 for (std::size_t k = 0; k < i; ++k)
130 value -= S(as[i, k]) * S(bs[k, col]);
132 {
135 }
136 bs[i, col] = value;
137 }
138 for (std::size_t i = n; i-- > 0;)
139 {
140 S value = bs[i, col];
141 for (std::size_t k = i + 1; k < n; ++k)
142 value -= S(as[i, k]) * S(bs[k, col]);
143 value /= S(as[i, i]);
145 {
148 }
149 bs[i, col] = value;
150 }
151 }
153}
154} // namespace uni20::linalg::detail::cpu_reference
locale_t value
Definition data_table.cpp:49
Operation-tag backend dispatch over tensor-view operands.
constexpr bool isfinite(I const &x) noexcept
Returns whether an integer scalar is finite.
Definition math.hpp:121
Mdspan concept and accessor extensions for Uni20.
int columns(std::FILE *stream)
Return the terminal column count associated with a C stream.
Definition terminal.cpp:493
void info(checked_format_string< Args... > format, Args &&... args)
Emit an informational display message.
Definition display.hpp:393
DiagnosticMagnitude< R > magnitude(R const &value)
Definition gmres_diagnostics.hpp:98
KernelAttempt
Result of one runtime kernel backend attempt.
Definition kernel_attempt.hpp:27
@ nonfinite_input
An input coefficient or RHS component was nonfinite; both workspaces are preserved.
@ singular
An exactly zero elimination pivot was found.
@ nonfinite_result
A factor, solution, reduction, or required magnitude became nonfinite.
@ small_pivot
A nonzero pivot failed the requested relative threshold.
std::ptrdiff_t index_type
Definition types.hpp:19