Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
dense_linalg.hpp
Go to the documentation of this file.
1#pragma once
2
5#include <uni20/config.hpp>
8#include <uni20/core/math.hpp>
13
14#include <algorithm>
15#include <cmath>
16#include <complex>
17#include <cstddef>
18#include <memory>
19#include <span>
20#include <stdexcept>
21#include <type_traits>
22#include <vector>
23
24namespace uni20::krylov
25{
26
29
34template <typename Scalar> auto right_mdspan(RightMatrix<Scalar>& matrix) { return matrix.mdspan(); }
35
40template <typename Scalar> auto right_mdspan(RightMatrix<Scalar> const& matrix) { return matrix.mdspan(); }
41
46template <typename Scalar> RightMatrix<Scalar> copy_left_to_right(uni20::DenseMatrix<Scalar> const& matrix)
47{
48 RightMatrix<Scalar> result(matrix.rows(), matrix.cols());
49 for (uni20::index_type row = 0; row < matrix.rows(); ++row)
50 {
51 for (uni20::index_type col = 0; col < matrix.cols(); ++col)
52 {
53 result[row, col] = matrix[row, col];
54 }
55 }
56 return result;
57}
58
63template <typename Scalar> uni20::DenseMatrix<Scalar> copy_right_to_left(RightMatrix<Scalar> const& matrix)
64{
65 uni20::DenseMatrix<Scalar> result(matrix.rows(), matrix.cols());
66 for (uni20::index_type row = 0; row < matrix.rows(); ++row)
67 {
68 for (uni20::index_type col = 0; col < matrix.cols(); ++col)
69 {
70 result[row, col] = matrix[row, col];
71 }
72 }
73 return result;
74}
75
78{
79 None,
82};
83
85enum class MatrixSide
86{
87 Left,
88 Right
89};
90
93
95enum class MatrixNorm
96{
97 MaxAbs,
98 One,
101};
102
103namespace detail
104{
105
107
108inline char lapack_norm(MatrixNorm norm)
109{
110 switch (norm)
111 {
113 return 'M';
114 case MatrixNorm::One:
115 return '1';
117 return 'I';
119 return 'F';
120 }
121 throw std::invalid_argument("dense real LAPACK operation received an unknown norm selector");
122}
123
124inline blas_int gelsd_iwork_size(blas_int m, blas_int n)
125{
126 blas_int const minmn = std::min(m, n);
127 if (minmn <= 0)
128 {
129 return 1;
130 }
131
132 // LAPACK's bound uses SMLSIZ from ILAENV. Using divisor 2 overestimates the
133 // subdivision depth, avoiding a runtime dependency on ILAENV in this wrapper.
134 std::size_t levels = 0;
135 for (std::size_t size = static_cast<std::size_t>(minmn) / 2; size > 0; size /= 2)
136 {
137 ++levels;
138 }
139 std::size_t const minmn_size = static_cast<std::size_t>(minmn);
140 std::size_t const required = 3 * minmn_size * levels + 11 * minmn_size;
141 return checked_blas_int(std::max<std::size_t>(1, required));
142}
143
144template <typename Scalar> constexpr Scalar conjugate_if_complex(Scalar const& value)
145{
146 if constexpr (uni20::is_complex_v<Scalar>)
147 {
148 return std::conj(value);
149 }
150 else
151 {
152 return value;
153 }
154}
155
156template <typename Scalar> void check_same_size(std::span<Scalar const> source, std::span<Scalar> destination)
157{
158 if (source.size() != destination.size())
159 {
160 throw std::invalid_argument("dense vector sizes do not agree");
161 }
162}
163
164template <typename Scalar> bool in_selected_region(std::size_t row, std::size_t col, MatrixFill fill)
165{
166 switch (fill)
167 {
168 case MatrixFill::All:
169 return true;
170 case MatrixFill::Upper:
171 return row <= col;
172 case MatrixFill::Lower:
173 return row >= col;
174 }
175 return false;
176}
177} // namespace detail
178
183template <typename Scalar> void copy(std::span<Scalar> destination, std::span<Scalar const> source)
184{
185 detail::check_same_size(source, destination);
186 std::ranges::copy(source, destination.begin());
187}
188
193template <typename Scalar> void scal(Scalar const& alpha, std::span<Scalar> vector)
194{
195 for (Scalar& value : vector)
196 {
197 value *= alpha;
198 }
199}
200
206template <typename Scalar> void axpy(std::span<Scalar> y, Scalar const& alpha, std::span<Scalar const> x)
207{
208 detail::check_same_size(x, y);
209 for (std::size_t i = 0; i < x.size(); ++i)
210 {
211 y[i] += alpha * x[i];
212 }
213}
214
220template <typename Scalar> Scalar dotu(std::span<Scalar const> x, std::span<Scalar const> y)
221{
222 if (x.size() != y.size())
223 {
224 throw std::invalid_argument("dense vector sizes do not agree");
225 }
226
227 Scalar result{};
228 for (std::size_t i = 0; i < x.size(); ++i)
229 {
230 result += x[i] * y[i];
231 }
232 return result;
233}
234
240template <uni20::Real Scalar> Scalar dot(std::span<Scalar const> x, std::span<Scalar const> y) { return dotu(x, y); }
241
247template <typename Scalar> Scalar dotc(std::span<Scalar const> x, std::span<Scalar const> y)
248{
249 if (x.size() != y.size())
250 {
251 throw std::invalid_argument("dense vector sizes do not agree");
252 }
253
254 Scalar result{};
255 for (std::size_t i = 0; i < x.size(); ++i)
256 {
257 result += detail::conjugate_if_complex(x[i]) * y[i];
258 }
259 return result;
260}
261
267template <typename Scalar>
269{
270 if (source.rows() != destination.rows() || source.cols() != destination.cols())
271 {
272 throw std::invalid_argument("dense matrix sizes do not agree");
273 }
274
275 for (uni20::index_type col = 0; col < source.cols(); ++col)
276 {
277 for (uni20::index_type row = 0; row < source.rows(); ++row)
278 {
279 if (detail::in_selected_region<Scalar>(row, col, fill))
280 {
281 destination[row, col] = source[row, col];
282 }
283 }
284 }
285}
286
293template <typename Scalar>
294void laset(uni20::DenseMatrix<Scalar>& matrix, Scalar const& diagonal, Scalar const& off_diagonal, MatrixFill fill)
295{
296 uni20::linalg::set_matrix(matrix, diagonal, off_diagonal, fill);
297}
298
307template <typename Scalar>
308void gemv(std::span<Scalar> y, Scalar const& alpha, uni20::DenseMatrix<Scalar> const& matrix, std::span<Scalar const> x,
310{
311 std::size_t const output_size = transpose == MatrixTranspose::None ? matrix.rows() : matrix.cols();
312 std::size_t const input_size = transpose == MatrixTranspose::None ? matrix.cols() : matrix.rows();
313 if (x.size() != input_size || y.size() != output_size)
314 {
315 throw std::invalid_argument("dense matrix-vector sizes do not agree");
316 }
317
318 if (beta == Scalar{})
319 {
320 std::fill(y.begin(), y.end(), Scalar{});
321 }
322 else
323 {
324 for (Scalar& value : y)
325 value *= beta;
326 }
327
328 if (transpose == MatrixTranspose::None)
329 {
330 for (uni20::index_type col = 0; col < matrix.cols(); ++col)
331 {
332 Scalar const factor = alpha * x[col];
333 for (uni20::index_type row = 0; row < matrix.rows(); ++row)
334 {
335 y[row] += factor * matrix[row, col];
336 }
337 }
338 return;
339 }
340
341 for (uni20::index_type col = 0; col < matrix.cols(); ++col)
342 {
343 Scalar sum{};
344 for (uni20::index_type row = 0; row < matrix.rows(); ++row)
345 {
346 Scalar entry = matrix[row, col];
348 {
349 entry = detail::conjugate_if_complex(entry);
350 }
351 sum += entry * x[row];
352 }
353 y[col] += alpha * sum;
354 }
355}
356
363template <typename Scalar>
364void geru(uni20::DenseMatrix<Scalar>& matrix, Scalar const& alpha, std::span<Scalar const> x, std::span<Scalar const> y)
365{
366 if (x.size() != static_cast<std::size_t>(matrix.rows()) || y.size() != static_cast<std::size_t>(matrix.cols()))
367 {
368 throw std::invalid_argument("dense rank-one update sizes do not agree");
369 }
370
371 for (uni20::index_type col = 0; col < matrix.cols(); ++col)
372 {
373 Scalar const factor = alpha * y[col];
374 for (uni20::index_type row = 0; row < matrix.rows(); ++row)
375 {
376 matrix[row, col] += x[row] * factor;
377 }
378 }
379}
380
387template <typename Scalar>
388void gerc(uni20::DenseMatrix<Scalar>& matrix, Scalar const& alpha, std::span<Scalar const> x, std::span<Scalar const> y)
389{
390 if (x.size() != static_cast<std::size_t>(matrix.rows()) || y.size() != static_cast<std::size_t>(matrix.cols()))
391 {
392 throw std::invalid_argument("dense rank-one update sizes do not agree");
393 }
394
395 for (uni20::index_type col = 0; col < matrix.cols(); ++col)
396 {
397 Scalar const factor = alpha * detail::conjugate_if_complex(y[col]);
398 for (uni20::index_type row = 0; row < matrix.rows(); ++row)
399 {
400 matrix[row, col] += x[row] * factor;
401 }
402 }
403}
404
405} // namespace uni20::krylov
CPU dense matrix exponential interface and dispatch adapter.
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 rows() const noexcept
Return the matrix row count for rank-two tensors.
Definition basic_tensor.hpp:768
auto mdspan() noexcept -> mdspan_type
Resolve a writable mdspan over the owned storage.
Definition basic_tensor.hpp:609
auto cols() const noexcept
Return the matrix column count for rank-two tensors.
Definition basic_tensor.hpp:776
Concept for numeric scalar types (integer, real, or complex).
Definition scalar_concepts.hpp:81
locale_t value
Definition data_table.cpp:49
Checked LAPACK wrappers over provider-specific unchecked overloads.
Scalar math helper utilities.
Configured gateway to Uni20's mdspan implementation.
std::pair< int, int > size(std::FILE *stream)
Return the terminal size associated with a C stream.
Definition terminal.cpp:504
blas_int checked_blas_int(std::size_t value)
Convert a dense dimension to blas_int or throw on overflow.
Definition blas_int.hpp:40
Definition block_tensor_vector.hpp:23
void gerc(uni20::DenseMatrix< Scalar > &matrix, Scalar const &alpha, std::span< Scalar const > x, std::span< Scalar const > y)
Apply a conjugated dense rank-one update.
Definition dense_linalg.hpp:388
void scal(Scalar const &alpha, std::span< Scalar > vector)
Scale a local dense vector in place.
Definition dense_linalg.hpp:193
void laset(uni20::DenseMatrix< Scalar > &matrix, Scalar const &diagonal, Scalar const &off_diagonal, MatrixFill fill)
Set a selected region of a local dense matrix.
Definition dense_linalg.hpp:294
uni20::DenseMatrix< Scalar > copy_right_to_left(RightMatrix< Scalar > const &matrix)
Copy a row-major matrix into a column-major DenseMatrix.
Definition dense_linalg.hpp:63
Scalar dot(std::span< Scalar const > x, std::span< Scalar const > y)
Compute a BLAS-style real dot product.
Definition dense_linalg.hpp:240
void axpy(std::span< Scalar > y, Scalar const &alpha, std::span< Scalar const > x)
Add a scaled local dense vector to another vector.
Definition dense_linalg.hpp:206
Scalar dotc(std::span< Scalar const > x, std::span< Scalar const > y)
Compute a conjugated dot product.
Definition dense_linalg.hpp:247
MatrixTranspose
Matrix transpose mode for local dense Krylov operations.
Definition dense_linalg.hpp:78
void lacpy(uni20::DenseMatrix< Scalar > &destination, uni20::DenseMatrix< Scalar > const &source, MatrixFill fill)
Copy a selected region of a local dense matrix.
Definition dense_linalg.hpp:268
auto right_mdspan(RightMatrix< Scalar > &matrix)
Return a mutable layout-right mdspan view of a prototype right-layout matrix.
Definition dense_linalg.hpp:34
uni20::linalg::MatrixRegion MatrixFill
Matrix region selected by LAPACK-style copy and set operations.
Definition dense_linalg.hpp:92
MatrixSide
Matrix side selected by LAPACK-style multiply and solve operations.
Definition dense_linalg.hpp:86
void gemv(std::span< Scalar > y, Scalar const &alpha, uni20::DenseMatrix< Scalar > const &matrix, std::span< Scalar const > x, Scalar const &beta, MatrixTranspose transpose=MatrixTranspose::None)
Compute a dense matrix-vector product.
Definition dense_linalg.hpp:308
MatrixNorm
LAPACK-compatible dense matrix norm selector.
Definition dense_linalg.hpp:96
RightMatrix< Scalar > copy_left_to_right(uni20::DenseMatrix< Scalar > const &matrix)
Copy a column-major DenseMatrix into a row-major matrix.
Definition dense_linalg.hpp:46
void geru(uni20::DenseMatrix< Scalar > &matrix, Scalar const &alpha, std::span< Scalar const > x, std::span< Scalar const > y)
Apply a dense rank-one update.
Definition dense_linalg.hpp:364
Scalar dotu(std::span< Scalar const > x, std::span< Scalar const > y)
Compute an unconjugated dot product.
Definition dense_linalg.hpp:220
void copy(std::span< Scalar > destination, std::span< Scalar const > source)
Copy a local dense vector.
Definition dense_linalg.hpp:183
void set_matrix(BackendSelector selector, async::Async< MatrixTensor > &matrix, Diagonal &&diagonal, OffDiagonal &&off_diagonal, MatrixRegion region=MatrixRegion::All)
Schedule structured matrix initialization through an explicit selector.
Definition async/matrix_set.hpp:58
MatrixRegion
Matrix region selected by structured initialization operations.
Definition operation_tags.hpp:208
void sum(BackendSelector selector, async::Async< OutputTensor > &output, async::Async< InputTensor > const &input)
Schedule a full sum into an explicit async scalar tensor.
Definition linalg/async/reductions.hpp:309
mpreal norm(mpcomplex const &z)
Definition mpcomplex.hpp:494
void fill(BackendSelector selector, async::Async< OutputTensor > &output, Value &&value)
Fill an existing async Tensor without reading its old values.
Definition linalg/async/transform.hpp:205
std::ptrdiff_t index_type
Definition types.hpp:19
mpreal beta(mpreal const &a, mpreal const &x)
Real Beta function; positive rational/integer pairs retain exact values.
Definition mpreal_special.hpp:164
General-purpose owning tensors with runtime extents.