14#ifndef NUMERICAL_BLAS_HPP
15#define NUMERICAL_BLAS_HPP
47 inline constexpr std::size_t
syrk_kept_limit {(std::size_t {32} << 20U) /
sizeof(
double)};
61 return op ==
'N' ||
op ==
'n' ||
op ==
'T' ||
op ==
't' ||
op ==
'C' ||
op ==
'c';
67 return op !=
'N' &&
op !=
'n';
73 return op ==
'C' ||
op ==
'c';
80 return std::isfinite(x);
87 return std::isfinite(x.real()) && std::isfinite(x.imag());
103 template <
typename T>
112 const auto r {
static_cast<std::size_t
>(rows)};
113 const auto c {
static_cast<std::size_t
>(cols)};
114 const auto ld {
static_cast<std::size_t
>(lda)};
122 const T x {a[i + (j * ld)]};
132 template <
typename T>
146 inline constexpr std::size_t
kept_bytes {std::size_t {32} << 20U};
153 template <
typename T>
156 thread_local std::array<buffer<T>, 2> kept;
161 template <
typename T>
168 template <
typename T>
183 template <
typename T>
191 if (std::memcmp(b,
middle, n *
sizeof(
T)) != 0) {
194 std::atomic<bool>
holds {
true};
196 if (std::memcmp(b + ((j + 1) *
ldb),
middle - (j + 1), n *
sizeof(
T)) != 0) {
197 holds.store(
false, std::memory_order_relaxed);
200 return holds.load(std::memory_order_relaxed);
204 template <
typename T>
216 a[i + (j * lda)] =
from[(i * cols) + j];
224 template <
typename T>
227 const std::size_t*
to,
236 a[i + (
to[j] * lda)] =
from[(i * n) + j];
248 template <
typename T>
289 template <
typename T>
302 rows[(i * n) + j] = a[i + (j * lda)];
305 a[i + (j * lda)] = rows[(i * n) + j];
315 template <
typename T>
322 const auto r {
static_cast<std::size_t
>(rows)};
323 const auto c {
static_cast<std::size_t
>(cols)};
325 for (std::size_t j {0}; j < c; ++j) {
326 for (std::size_t i {0}; i < r; ++i) {
327 out[(j * r) + i] = scale * a[i + (j *
static_cast<std::size_t
>(lda))];
339 template <
typename T>
356 left =
row_major(b,
static_cast<std::ptrdiff_t
>(
ldb),
static_cast<std::ptrdiff_t
>(m),
static_cast<std::ptrdiff_t
>(k),
alpha,
360 left =
columns_as_rows(b,
static_cast<std::ptrdiff_t
>(
ldb),
static_cast<std::ptrdiff_t
>(k),
static_cast<std::ptrdiff_t
>(m),
alpha);
382 product_of_ops<double>(
transa,
transb,
alpha, m, n, k, a, lda, b,
ldb, c, ldc);
397 template <
typename Index>
401 const std::size_t size {pivots.size()};
402 std::vector<std::size_t> at(size);
403 std::vector<std::size_t>
where(size);
404 for (std::size_t i {0}; i < size; ++i) {
408 for (std::size_t i {0}; i < size; ++i) {
409 const std::size_t
from {
where[pivots[i]]};
412 where[pivots[i]] = i;
413 std::swap(at[i], at[
from]);
421 template <
typename T,
typename Index>
429 for (std::size_t j {0}; j < std::min(m, n); ++j) {
430 T*
const column {a + (j * lda)};
431 std::size_t
pivot {j};
432 for (std::size_t i {j + 1}; i < m; ++i) {
442 for (std::size_t c {0}; c < n; ++c) {
443 std::swap(a[j + (c * lda)], a[
pivot + (c * lda)]);
445 for (std::size_t i {j + 1}; i < m; ++i) {
448 for (std::size_t c {j + 1}; c < n; ++c) {
449 T*
const target {a + (c * lda)};
451 for (std::size_t i {j + 1}; i < m; ++i) {
467 template <
typename T>
500 else if (lda < std::max<std::ptrdiff_t>(1, a_rows)) {
503 else if (
ldb < std::max<std::ptrdiff_t>(1, b_rows)) {
506 else if (ldc < std::max<std::ptrdiff_t>(1, m)) {
509 if (
illegal != 0 || m == 0 || n == 0) {
512 const auto rows {
static_cast<std::size_t
>(m)};
513 const auto cols {
static_cast<std::size_t
>(n)};
514 const auto stride {
static_cast<std::size_t
>(ldc)};
515 for (std::size_t j {0}; j < cols; ++j) {
518 std::fill_n(
column, rows,
T {});
520 else if (beta !=
T {1}) {
524 if (
alpha ==
T {} || k == 0) {
528 static_cast<std::size_t
>(
ldb), c,
stride);
538 std::ptrdiff_t
inc)
noexcept
540 return inc > 0 ? i *
static_cast<std::size_t
>(
inc) : (
length - 1 - i) *
static_cast<std::size_t
>(-
inc);
544 template <
typename T>
554 const auto count {
static_cast<std::size_t
>(n)};
560 for (std::size_t i {0}; i < count; ++i) {
599 template <
typename T>
602 const std::complex<T>* x,
604 const std::complex<T>*
y,
605 std::ptrdiff_t
incy)
noexcept
607 std::complex<T>
sum {};
611 const auto count {
static_cast<std::size_t
>(n)};
615 for (std::size_t i {0}; i < count; ++i) {
659 if (lda < std::max<std::ptrdiff_t>(1, m)) {
668 if (m == 0 || n == 0 || (
alpha == 0.0 && beta == 1.0)) {
672 const auto rows {
static_cast<std::size_t
>(m)};
673 const auto cols {
static_cast<std::size_t
>(n)};
674 const auto ld {
static_cast<std::size_t
>(lda)};
681 for (std::size_t i {0}; i <
y_length; ++i) {
687 for (std::size_t i {0}; i < scaled.size(); ++i) {
691 const double*
const factors {in_place ? x : scaled.data()};
696 factors, rows,
dots.data() + first);
698 for (std::size_t j {0}; j < cols; ++j) {
704 for (
double& factor : scaled) {
714 for (std::size_t i {0};
incy != 1 && i <
y_length; ++i) {
774 for (std::size_t j {0}; j <
w; ++j) {
775 for (std::size_t i {
operands.lower ? j : 0}; i < (
operands.lower ?
w : j + 1); ++i) {
781 const std::size_t h {
w / 2};
785 const std::size_t rows {
operands.lower ?
w - h : h};
786 const std::size_t cols {
operands.lower ? h :
w - h};
800 const std::size_t k {
operands.depth};
839 const bool lower {
uplo ==
'L' ||
uplo ==
'l'};
841 if (!lower &&
uplo !=
'U' &&
uplo !=
'u') {
853 if (lda < std::max<std::ptrdiff_t>(1,
transposed ? k : n)) {
856 if (ldc < std::max<std::ptrdiff_t>(1, n)) {
862 const auto order {
static_cast<std::size_t
>(n)};
863 const auto ld {
static_cast<std::size_t
>(ldc)};
864 if (
alpha == 0.0 || k == 0) {
865 for (std::size_t j {0}; j < order && beta != 1.0; ++j) {
866 for (std::size_t i {lower ? j : 0}; i < (lower ? order : j + 1); ++i) {
867 c[i + (j * ld)] = beta == 0.0 ? 0.0 : beta * c[i + (j * ld)];
876 const auto depth {
static_cast<std::size_t
>(k)};
877 const auto lda_s {
static_cast<std::size_t
>(lda)};
878 for (std::size_t j {0}; j < order; ++j) {
879 for (std::size_t i {lower ? j : 0}; i < (lower ? order : j + 1); ++i) {
880 double&
entry {c[i + (j * ld)]};
885 detail::syrk_all({
transposed ? a :
nullptr,
lda_s,
transposed ?
nullptr : a,
lda_s, depth, c, ld, lower,
transposed, !
transposed}, order);
896 for (std::size_t i {0}; i <
copy_rows; ++i) {
897 for (std::size_t j {0}; j <
copy_cols; ++j) {
905 detail::syrk_all({
p_rows, ldp,
q_cols, ldq, depth, c, ld, lower,
false,
false}, order);
932 for (std::size_t done {0}; done < k; done +=
trsm_block) {
933 const std::size_t
w {std::min(
trsm_block, k - done)};
934 const std::size_t
k0 {lower ? done : k - done -
w};
935 const std::size_t
k1 {
k0 +
w};
938 double* x {b + (j *
ldb)};
939 for (std::size_t s {0}; s <
k1 -
k0; ++s) {
940 const std::size_t p {lower ?
k0 + s :
k1 - 1 - s};
942 x[p] /= a[p + (p * lda)];
944 const std::size_t
from {lower ? p + 1 :
k0};
945 const std::size_t
to {lower ?
k1 : p};
949 const std::size_t first {lower ?
k1 : 0};
950 const std::size_t count {lower ? k -
k1 :
k0};
952 (
void)
gemm(
'N',
'N',
static_cast<std::ptrdiff_t
>(count),
static_cast<std::ptrdiff_t
>(n),
static_cast<std::ptrdiff_t
>(
w), -1.0,
953 a + first + (
k0 * lda),
static_cast<std::ptrdiff_t
>(lda), b +
k0,
static_cast<std::ptrdiff_t
>(
ldb), 1.0, b + first,
954 static_cast<std::ptrdiff_t
>(
ldb));
980 const bool left {
side ==
'L' ||
side ==
'l'};
981 const bool lower {
uplo ==
'L' ||
uplo ==
'l'};
983 if (!left &&
side !=
'R' &&
side !=
'r') {
986 if (!lower &&
uplo !=
'U' &&
uplo !=
'u') {
1001 if (lda < std::max<std::ptrdiff_t>(1, left ? m : n)) {
1004 if (
ldb < std::max<std::ptrdiff_t>(1, m)) {
1007 if (m == 0 || n == 0) {
1010 const auto rows {
static_cast<std::size_t
>(m)};
1011 const auto cols {
static_cast<std::size_t
>(n)};
1012 const auto ld {
static_cast<std::size_t
>(
ldb)};
1013 for (std::size_t j {0}; j < cols; ++j) {
1014 for (std::size_t i {0}; i < rows; ++i) {
1015 double&
entry {b[i + (j * ld)]};
1022 const std::size_t k {left ? rows : cols};
1025 const double*
a_used {a};
1026 std::size_t
lda_used {
static_cast<std::size_t
>(lda)};
1029 for (std::size_t j {0}; j < k; ++j) {
1030 for (std::size_t i {lower ? j : 0}; i < (lower ? k : j + 1); ++i) {
1031 transposed_a[j + (i * k)] = a[i + (j *
static_cast<std::size_t
>(lda))];
1042 for (std::size_t j {0}; j < cols; ++j) {
1043 for (std::size_t i {0}; i < rows; ++i) {
1044 bt[j + (i * cols)] = b[i + (j * ld)];
1048 for (std::size_t j {0}; j < cols; ++j) {
1049 for (std::size_t i {0}; i < rows; ++i) {
1050 b[i + (j * ld)] =
bt[j + (i * cols)];
1056 template <
typename T,
typename Index>
1059 std::ptrdiff_t
nrhs,
1064 std::ptrdiff_t
ldb);
1076 template <
typename T,
typename Index>
1078 std::ptrdiff_t
nrhs,
1091 if (lda < std::max<std::ptrdiff_t>(1, n)) {
1094 if (
ldb < std::max<std::ptrdiff_t>(1, n)) {
1100 const auto size {
static_cast<std::size_t
>(n)};
1101 const auto ld {
static_cast<std::size_t
>(lda)};
1102 std::vector<std::size_t> pivots;
1104 bool singular {
false};
1110 pivots =
lu.pivots();
1111 singular =
lu.singular();
1112 if (!singular &&
nrhs > 0) {
1130 factors = std::move(
lu).factors();
1142 for (std::size_t i {0}; i < size; ++i) {
1143 if (a[i + (i * ld)] ==
T {}) {
1144 return static_cast<int>(i + 1);
1157 template <
typename T>
1164 const auto l = [&](std::size_t i, std::size_t j) ->
T& {
return lower ? a[i + (j * ld)] : a[j + (i * ld)]; };
1166 for (std::size_t j {0}; j < size; ++j) {
1167 auto diagonal {std::real(a[j + (j * ld)])};
1168 for (std::size_t k {0}; k < j; ++k) {
1174 return static_cast<int>(j + 1);
1178 for (std::size_t i {j + 1}; i < size; ++i) {
1180 for (std::size_t k {0}; k < j; ++k) {
1200 template <
typename T>
1206 const bool lower {
uplo ==
'L' ||
uplo ==
'l'};
1207 if (!lower &&
uplo !=
'U' &&
uplo !=
'u') {
1213 if (lda < std::max<std::ptrdiff_t>(1, n)) {
1219 const auto size {
static_cast<std::size_t
>(n)};
1220 const auto ld {
static_cast<std::size_t
>(lda)};
1230 for (std::size_t i {0}; i < size; ++i) {
1231 for (std::size_t j {0}; j <= i; ++j) {
1242 for (std::size_t i {0}; i < size; ++i) {
1243 for (std::size_t j {0}; j <= i; ++j) {
1251 return static_cast<int>(failed.
order());
1266 template <
typename T,
typename Index>
1279 if (lda < std::max<std::ptrdiff_t>(1, m)) {
1282 if (m == 0 || n == 0) {
1285 const auto rows {
static_cast<std::size_t
>(m)};
1286 const auto cols {
static_cast<std::size_t
>(n)};
1287 const auto ld {
static_cast<std::size_t
>(lda)};
1293 std::optional<lu_decomposition<T>>
factored;
1305 for (std::size_t i {0}; i < rows; ++i) {
1306 if (a[i + (i * ld)] ==
T {}) {
1307 return static_cast<int>(i + 1);
1319 template <
typename T,
typename Index>
1322 std::ptrdiff_t
nrhs,
1338 if (lda < std::max<std::ptrdiff_t>(1, n)) {
1341 if (
ldb < std::max<std::ptrdiff_t>(1, n)) {
1344 const auto size {
static_cast<std::size_t
>(n)};
1345 const auto ld {
static_cast<std::size_t
>(lda)};
1347 const auto at = [&](std::size_t i, std::size_t j) {
return a[i + (j * ld)]; };
1351 T*
const x {b + (c *
static_cast<std::size_t
>(
ldb))};
1353 for (std::size_t i {0}; i < size; ++i) {
1354 std::swap(x[i], x[
static_cast<std::size_t
>(
ipiv[i]) - 1]);
1356 for (std::size_t j {0}; j < size; ++j) {
1357 for (std::size_t i {j + 1}; i < size; ++i) {
1358 x[i] -= at(i, j) * x[j];
1361 for (std::size_t j {size}; j-- > 0;) {
1363 for (std::size_t i {0}; i < j; ++i) {
1364 x[i] -= at(i, j) * x[j];
1369 for (std::size_t i {0}; i < size; ++i) {
1371 for (std::size_t k {0}; k < i; ++k) {
1376 for (std::size_t i {size}; i-- > 0;) {
1378 for (std::size_t k {i + 1}; k < size; ++k) {
1383 for (std::size_t i {size}; i-- > 0;) {
1384 std::swap(x[i], x[
static_cast<std::size_t
>(
ipiv[i]) - 1]);
1396 template <
typename T>
1399 std::ptrdiff_t
nrhs,
1405 const bool lower {
uplo ==
'L' ||
uplo ==
'l'};
1406 if (!lower &&
uplo !=
'U' &&
uplo !=
'u') {
1415 if (lda < std::max<std::ptrdiff_t>(1, n)) {
1418 if (
ldb < std::max<std::ptrdiff_t>(1, n)) {
1421 const auto size {
static_cast<std::size_t
>(n)};
1422 const auto ld {
static_cast<std::size_t
>(lda)};
1424 const auto l = [&](std::size_t i, std::size_t j) {
return lower ? a[i + (j * ld)] :
numerical::detail::conj_of(a[j + (i * ld)]); };
1426 T*
const x {b + (c *
static_cast<std::size_t
>(
ldb))};
1427 for (std::size_t i {0}; i < size; ++i) {
1429 for (std::size_t k {0}; k < i; ++k) {
1430 sum -=
l(i, k) * x[k];
1432 x[i] =
sum /
l(i, i);
1434 for (std::size_t i {size}; i-- > 0;) {
1436 for (std::size_t k {i + 1}; k < size; ++k) {
1456 template <
typename Index>
1464 std::ptrdiff_t
lwork,
1468 const bool vectors {
jobz ==
'V' ||
jobz ==
'v'};
1469 const bool lower {
uplo ==
'L' ||
uplo ==
'l'};
1470 if (!vectors &&
jobz !=
'N' &&
jobz !=
'n') {
1473 if (!lower &&
uplo !=
'U' &&
uplo !=
'u') {
1479 if (lda < std::max<std::ptrdiff_t>(1, n)) {
1485 lwork_least = vectors ? 1 + (6 * n) + (2 * n * n) : (2 * n) + 1;
1502 const auto size {
static_cast<std::size_t
>(n)};
1503 const auto ld {
static_cast<std::size_t
>(lda)};
1505 for (std::size_t i {0}; i < size; ++i) {
1506 for (std::size_t j {0}; j <= i; ++j) {
1507 lower_rows[(i * size) + j] = lower ? a[i + (j * ld)] : a[j + (i * ld)];
1514 std::copy_n(&values[0], size,
w);
1518 std::copy_n(&
eigen.values()[0], size,
w);
1519 for (std::size_t j {0}; j < size; ++j) {
1520 for (std::size_t i {0}; i < size; ++i) {
1521 a[i + (j * ld)] =
eigen.vectors()(i, j);
1526 std::fill_n(
w, size, std::numeric_limits<double>::quiet_NaN());
1528 for (std::size_t j {0}; j < size; ++j) {
1529 std::fill_n(a + (j * ld), size, std::numeric_limits<double>::quiet_NaN());
1532 return static_cast<int>(size);
1546 template <
typename Index>
1556 std::ptrdiff_t
ldvt,
1558 std::ptrdiff_t
lwork,
1575 if (lda < std::max<std::ptrdiff_t>(1, m)) {
1578 const std::ptrdiff_t
least {std::min(m, n)};
1579 const std::ptrdiff_t
most {std::max(m, n)};
1582 if (
ldu < std::max<std::ptrdiff_t>(1,
u_out ? m : 1)) {
1592 if (
ldvt < std::max<std::ptrdiff_t>(1,
vt_rows)) {
1603 work[0] =
static_cast<double>(std::max<std::ptrdiff_t>(1,
lwork_least));
1612 const auto rows {
static_cast<std::size_t
>(m)};
1613 const auto cols {
static_cast<std::size_t
>(n)};
1614 const auto k {
static_cast<std::size_t
>(
least)};
1619 std::copy_n(&values[0], k, s);
1623 std::copy_n(&
svd.singular_values()[0], k, s);
1628 const std::size_t
ld_u {
overwrite && m >= n ?
static_cast<std::size_t
>(lda) :
static_cast<std::size_t
>(
ldu)};
1631 for (std::size_t j {0}; j < left.cols(); ++j) {
1632 for (std::size_t i {0}; i < left.rows(); ++i) {
1636 for (std::size_t j {0}; j < right.cols(); ++j) {
1637 for (std::size_t i {0}; i < right.rows(); ++i) {
1664 std::ptrdiff_t
lwork)
1672 if (lda < std::max<std::ptrdiff_t>(1, m)) {
1675 const std::ptrdiff_t
lwork_least {std::min(m, n) == 0 ? 1 : n};
1683 if (std::min(m, n) == 0) {
1686 const auto rows {
static_cast<std::size_t
>(m)};
1687 const auto cols {
static_cast<std::size_t
>(n)};
1688 const auto ld {
static_cast<std::size_t
>(lda)};
1693#ifdef NUMERICAL_X86_COMPILED
1695 for (std::size_t j {0}; j < cols; ++j) {
1696 std::copy_n(a + (j * ld), rows,
entries.data() + (j * rows));
1701#ifdef NUMERICAL_X86_COMPILED
1703 for (std::size_t j {0}; j < cols; ++j) {
1704 std::copy_n(
entries.data() + (j * rows), rows, a + (j * ld));
1712 for (std::size_t j {0}; j <
block.width; ++j) {
1735 std::ptrdiff_t
lwork)
1746 if (lda < std::max<std::ptrdiff_t>(1, m)) {
1749 const std::ptrdiff_t
lwork_least {std::max<std::ptrdiff_t>(1, n)};
1760 const auto rows {
static_cast<std::size_t
>(m)};
1761 const auto cols {
static_cast<std::size_t
>(n)};
1762 const auto depth {
static_cast<std::size_t
>(k)};
1763 const auto ld {
static_cast<std::size_t
>(lda)};
1765 std::vector<buffer<double>> reflectors(depth);
1766 const std::vector<double>
taus(
tau,
tau + depth);
1767 for (std::size_t j {0}; j < depth; ++j) {
1768 reflectors[j].resize(rows - j);
1769 reflectors[j][0] = 1.0;
1770 std::copy_n(a + (j + 1) + (j * ld), rows - j - 1, reflectors[j].data() + 1);
1772 std::vector<numerical::detail::reflector_block<double>> blocks;
1778 for (std::size_t j {0}; j < cols; ++j) {
1779 std::copy_n(columns.data() + (j * rows), rows, a + (j * ld));
1796 template <
typename Index>
1799 std::ptrdiff_t
nrhs,
1808 std::ptrdiff_t
lwork,
1820 if (lda < std::max<std::ptrdiff_t>(1, m)) {
1823 if (
ldb < std::max<std::ptrdiff_t>({1, m, n})) {
1827 constexpr std::ptrdiff_t
leaf {25};
1828 const std::ptrdiff_t
least {std::max<std::ptrdiff_t>(1, std::min(m, n))};
1829 const auto levels {std::max<std::ptrdiff_t>(
1830 static_cast<std::ptrdiff_t
>(std::log2(
static_cast<double>(
least) /
static_cast<double>(
leaf + 1))) + 1, 0)};
1842 if (m == 0 || n == 0) {
1845 const auto rows {
static_cast<std::size_t
>(m)};
1846 const auto cols {
static_cast<std::size_t
>(n)};
1847 const auto rhs {
static_cast<std::size_t
>(
nrhs)};
1848 const auto ld {
static_cast<std::size_t
>(
ldb)};
1850 for (std::size_t i {0}; i < rows; ++i) {
1851 for (std::size_t c {0}; c <
rhs; ++c) {
1852 right[(i *
rhs) + c] = b[i + (c * ld)];
1855 if (!std::ranges::all_of(right, [](
double x) {
return std::isfinite(x); })) {
1862 std::copy_n(&
fit.singular_values[0],
fit.singular_values.size(), s);
1863 *rank =
static_cast<Index>(
fit.rank);
1864 for (std::size_t c {0}; c <
rhs; ++c) {
1865 for (std::size_t i {0}; i < cols; ++i) {
1866 b[i + (c * ld)] =
fit.solution(i, c);
1868 for (std::size_t i {cols}; i < rows; ++i) {
1869 b[i + (c * ld)] = i == cols &&
fit.residuals.size() > 0 ? std::sqrt(
fit.residuals[c]) : 0.0;
1885 const vector<std::complex<double>>& values,
1886 const std::vector<std::size_t>&
column_of,
1891 const std::size_t n {values.size()};
1893 for (std::size_t j {0}; j < n; ++j) {
1895 if (values[j].
imag() == 0.0) {
1896 for (std::size_t i {0}; i < n; ++i) {
1897 out[i + (j * ld)] = v(i, c).real();
1900 else if (values[j].
imag() > 0.0) {
1901 for (std::size_t i {0}; i < n; ++i) {
1902 out[i + (j * ld)] = v(i, c).real();
1903 out[i + ((j + 1) * ld)] =
sign * v(i, c).imag();
1930 std::ptrdiff_t
ldvl,
1932 std::ptrdiff_t
ldvr,
1934 std::ptrdiff_t
lwork)
1936 const bool left {
jobvl ==
'V' ||
jobvl ==
'v'};
1937 const bool right {
jobvr ==
'V' ||
jobvr ==
'v'};
1941 if (!right &&
jobvr !=
'N' &&
jobvr !=
'n') {
1947 if (lda < std::max<std::ptrdiff_t>(1, n)) {
1950 if (
ldvl < 1 || (left &&
ldvl < n)) {
1953 if (
ldvr < 1 || (right &&
ldvr < n)) {
1956 const std::ptrdiff_t
lwork_least {std::max<std::ptrdiff_t>(1, (left || right ? 4 : 3) * n)};
1967 const auto size {
static_cast<std::size_t
>(n)};
1972 for (std::size_t j {0}; j < size; ++j) {
1973 wr[j] = values[j].real();
1974 wi[j] = values[j].imag();
1976 std::vector<std::size_t>
same(size);
1977 for (std::size_t j {0}; j < size; ++j) {
1987 std::vector<std::size_t>
column_of(size);
1988 std::vector<bool>
taken(size,
false);
1989 for (std::size_t j {0}; j < size; ++j) {
1990 std::size_t
best {size};
1991 for (std::size_t p {0}; p < size; ++p) {
A Cholesky factorisation A = L Lᴴ of a Hermitian positive-definite matrix.
The eigenvalues, and optionally the right eigenvectors, of a general square matrix,...
An LU factorisation with partial pivoting of a square matrix.
A dense, row-major matrix of T with value semantics.
buffer< T >::const_iterator begin() const noexcept
Const iterator to the first element (row-major).
buffer< T > elements() &&
The elements, row-major, handed over by a matrix about to expire, which is left 0 × 0: a large result...
Thrown when a decomposition's input holds an infinite or NaN entry: no factorisation of it means anyt...
Thrown when a Cholesky factorisation finds the matrix not positive-definite.
std::size_t order() const noexcept
The order of the first leading minor found not positive definite (LAPACK's info), 0 where unknown.
The magnitude at or under which a singular value counts as zero, in a rank (matrix_rank),...
static rank_cutoff relative(double ratio)
The largest singular value times ratio.
The singular value decomposition A = U Σ Vᴴ of an m × n matrix.
The eigenvalues and eigenvectors of a real symmetric matrix.
A dense vector of T with value semantics.
Matrix factorisations and the algorithms built on them.
The eigenvalues and eigenvectors of a general square matrix.
The matrix product kernel behind matrix * matrix and the einsum matmul path.
A dense, row-major, value-semantic matrix over a scalar type.
void syrk_product(const syrk_operands &operands, std::size_t c0, std::size_t cols, std::size_t r0, std::size_t rows, double *out, std::size_t ldo)
P(c0…) Q(…, r0…) added to the cols × rows row-major block at out (ldo apart): numerical::detail::gemm...
void syrk_triangle(syrk_operands operands, std::size_t j0, std::size_t w)
Adds P Q to the triangle of the diagonal block [j0, j0 + w) of C: halved until it is a block of syrk_...
buffer< double > & syrk_operand() noexcept
The storage of syrk's operand copy this thread keeps between calls.
void lower_triangle_rows(T *a, std::size_t lda, std::size_t n, T *rows, bool in)
The lower triangle of the column-major n × n a (lda apart) into that of the row-major rows (n apart) ...
buffer< T > & kept_storage(std::size_t slot) noexcept
Row-major storage of the scalar T this thread keeps between calls, in slot (0 for a call's A,...
bool is_identity(const T *b, std::size_t ldb, std::size_t n)
Whether the column-major n × n b (ldb apart) is the identity to the bit (a -0 is no zero of it,...
void triangular_solve(bool lower, bool unit, std::size_t k, std::size_t n, const double *a, std::size_t lda, double *b, std::size_t ldb)
A X = B in place for the column-major triangular k × k a (lower or upper, a unit diagonal not read) a...
constexpr std::size_t strided(std::size_t i, std::size_t length, std::ptrdiff_t inc) noexcept
Index of element i of a BLAS vector of length elements inc apart: from the last one where inc is nega...
bool finite(const T &x)
Whether the real x is finite (an overload per kind of scalar, as conj_of: each one expression).
void column_major_permuted_into(const T *from, std::size_t n, const std::size_t *to, T *a, std::size_t lda)
column_major_into for the n × n from, its column j written as column to[j] of a.
constexpr bool is_operation(char op) noexcept
Whether op is one of BLAS's N, T or C (either case): no transpose, transpose, conjugate one.
constexpr std::size_t kept_bytes
The most bytes a thread keeps in each of kept_storage's slots between calls (32 MiB).
int rectangular_lu(std::size_t m, std::size_t n, T *a, std::size_t lda, Index *ipiv)
The LU factorisation with partial pivoting of a rectangular column-major A in place,...
void give_back(std::size_t slot, buffer< T > &&storage)
storage given back to kept_storage's slot, unless past kept_bytes.
void interchanges(const std::vector< std::size_t > &pivots, Index *ipiv)
The permutation pivots (row i of P A is row pivots[i] of A) as LAPACK's successive row interchanges,...
constexpr bool conjugates(char op) noexcept
Whether op is BLAS's C: the conjugate transpose (a real matrix's is its transpose).
void row_major_into(buffer< T > &out, const T *a, std::ptrdiff_t lda, std::ptrdiff_t rows, std::ptrdiff_t cols, T scale, bool conjugate=false)
The column-major rows × cols a (lda apart) into the row-major out (resized to it),...
void column_major_into(const T *from, std::size_t rows, std::size_t cols, T *a, std::size_t lda)
The row-major rows × cols from into the column-major a (lda apart), by tiles.
buffer< T > row_major(const T *a, std::ptrdiff_t lda, std::ptrdiff_t rows, std::ptrdiff_t cols, T scale, bool conjugate=false)
rows × cols of the column-major a (lda apart), as a row-major buffer, each element times scale (conju...
buffer< T > take_kept(std::size_t slot)
kept_storage's slot, taken over by the caller (left empty there meanwhile).
void product_by_op_a(char transa, std::size_t m, std::size_t n, std::size_t k, const T *l, std::size_t ldl, const T *a, std::size_t lda, T *c, std::size_t ldc)
C += L op(A)ᵀ (C row-major m × n, L m × k), a the column-major op(A)'s storage (lda apart): op(A)ᵀ is...
int column_cholesky(bool lower, std::size_t size, T *a, std::size_t ld)
The Cholesky factor of the column-major order-size A in place, column by column as the reference's dp...
void syrk_all(const syrk_operands &operands, std::size_t n)
The whole triangle of C (order n) from operands: a product the matrix product kernel packs runs in on...
buffer< T > columns_as_rows(const T *a, std::ptrdiff_t lda, std::ptrdiff_t rows, std::ptrdiff_t cols, T scale)
The cols columns of rows elements of the column-major a (lda apart) as the rows of a row-major buffer...
void real_form(const matrix< std::complex< double > > &v, const vector< std::complex< double > > &values, const std::vector< std::size_t > &column_of, bool conjugate, double *out, std::size_t ld)
The eigenvectors v (columns, complex) in dgeev's real form, into the column-major out: column j of a ...
constexpr bool transposes(char op) noexcept
Whether op transposes (T or C: a real matrix's conjugate transpose is its transpose).
constexpr std::size_t transpose_weight
The weight of an element of the transposing copies against a multiply-add: bound by the memory,...
T real_dot(std::ptrdiff_t n, const T *x, std::ptrdiff_t incx, const T *y, std::ptrdiff_t incy)
numerical::blas::dot of the real scalar T.
constexpr std::size_t transpose_tile
The tile side of the transposing copies between column-major arguments and row-major storage: a tile'...
void product_of_ops(char transa, char transb, T alpha, std::size_t m, std::size_t n, std::size_t k, const T *a, std::size_t lda, const T *b, std::size_t ldb, T *c, std::size_t ldc)
C += α op(B)ᵀ op(A)ᵀ, row-major C (m × n, ldc apart), the column-major C of BLAS's gemm as its transp...
std::complex< T > complex_dot(bool conjugate, std::ptrdiff_t n, const std::complex< T > *x, std::ptrdiff_t incx, const std::complex< T > *y, std::ptrdiff_t incy) noexcept
Σ x_i y_i (conjugate false, BLAS's zdotu) or Σ conj(x_i) y_i (true, zdotc) over n complex elements in...
int potrf(char uplo, std::ptrdiff_t n, T *a, std::ptrdiff_t lda)
The Cholesky factor of a symmetric positive-definite A, column-major, as LAPACK's dpotrf: with uplo L...
int gemm(char transa, char transb, std::ptrdiff_t m, std::ptrdiff_t n, std::ptrdiff_t k, T alpha, const T *a, std::ptrdiff_t lda, const T *b, std::ptrdiff_t ldb, T beta, T *c, std::ptrdiff_t ldc)
C ← α op(A) op(B) + β C, column-major, as BLAS's dgemm: op(A) is m × k, op(B) k × n,...
double dot(std::ptrdiff_t n, const double *x, std::ptrdiff_t incx, const double *y, std::ptrdiff_t incy)
Σ x_i y_i over n elements incx and incy apart (from the last where negative), as BLAS's ddot; 0 where...
int getrf(std::ptrdiff_t m, std::ptrdiff_t n, T *a, std::ptrdiff_t lda, Index *ipiv)
P A = L U of the column-major m × n A in place, as LAPACK's dgetrf: the factors as dgetrf leaves them...
int trsm(char side, char uplo, char transa, char diag, std::ptrdiff_t m, std::ptrdiff_t n, double alpha, const double *a, std::ptrdiff_t lda, double *b, std::ptrdiff_t ldb)
B ← α op(A)⁻¹ B (side L) or α B op(A)⁻¹ (R), column-major, B m × n and the triangular A (uplo U or L,...
constexpr std::size_t syrk_block
The columns of syrk's smallest diagonal blocks, formed whole: their wasted half, at most 64 n k multi...
int orgqr(std::ptrdiff_t m, std::ptrdiff_t n, std::ptrdiff_t k, double *a, std::ptrdiff_t lda, const double *tau, double *work, std::ptrdiff_t lwork)
The first n columns of Q = H₀ H₁ … H_{k-1}, from the reflectors of a dgeqrf (geqrf's or any implement...
constexpr double lapack_precision
LAPACK's relative machine precision, ‘dlamch('E’): the unit roundoff2⁻⁵³, half of std::numeric_limits...
constexpr std::size_t trsm_block
The rows of trsm's blocks: within one, each column solved alone; past it, the matrix product kernel.
int syevd(char jobz, char uplo, std::ptrdiff_t n, double *a, std::ptrdiff_t lda, double *w, double *work, std::ptrdiff_t lwork, Index *iwork, std::ptrdiff_t liwork)
The eigenvalues, and with jobz V the eigenvectors, of a symmetric column-major A, as LAPACK's dsyevd:...
int gesdd(char jobz, std::ptrdiff_t m, std::ptrdiff_t n, double *a, std::ptrdiff_t lda, double *s, double *u, std::ptrdiff_t ldu, double *vt, std::ptrdiff_t ldvt, double *work, std::ptrdiff_t lwork, Index *iwork)
The singular value decomposition A = U Σ Vᵀ of a column-major m × n A, as LAPACK's dgesdd: the singul...
constexpr std::size_t syrk_kept_limit
The most elements of syrk's operand copy a thread keeps between calls (32 MiB).
int gemv(char trans, std::ptrdiff_t m, std::ptrdiff_t n, double alpha, const double *a, std::ptrdiff_t lda, const double *x, std::ptrdiff_t incx, double beta, double *y, std::ptrdiff_t incy)
y ← α op(A) x + β y, column-major A m × n, as BLAS's dgemv: the vectors incx and incy apart (from the...
int geev(char jobvl, char jobvr, std::ptrdiff_t n, const double *a, std::ptrdiff_t lda, double *wr, double *wi, double *vl, std::ptrdiff_t ldvl, double *vr, std::ptrdiff_t ldvr, double *work, std::ptrdiff_t lwork)
The eigenvalues, and with jobvl or jobvr V the left or right eigenvectors, of a column-major n × n A,...
int potrs(char uplo, std::ptrdiff_t n, std::ptrdiff_t nrhs, const T *a, std::ptrdiff_t lda, T *b, std::ptrdiff_t ldb)
A X = B from the Cholesky factor of a dpotrf (by any implementation), column-major,...
int getrs(char trans, std::ptrdiff_t n, std::ptrdiff_t nrhs, const T *a, std::ptrdiff_t lda, const Index *ipiv, T *b, std::ptrdiff_t ldb)
A X = B, Aᵀ X = B or Aᴴ X = B (trans N, T or C), column-major, from the factors and interchanges of a...
int syrk(char uplo, char trans, std::ptrdiff_t n, std::ptrdiff_t k, double alpha, const double *a, std::ptrdiff_t lda, double beta, double *c, std::ptrdiff_t ldc)
C ← α op(A) op(A)ᵀ + β C on the triangle uplo (U or L) of the column-major n × n C,...
int gesv(std::ptrdiff_t n, std::ptrdiff_t nrhs, T *a, std::ptrdiff_t lda, Index *ipiv, T *b, std::ptrdiff_t ldb)
A X = B, column-major, as LAPACK's dgesv: A (n × n, lda apart) is factorised as P A = L U by NumericA...
int gelsd(std::ptrdiff_t m, std::ptrdiff_t n, std::ptrdiff_t nrhs, const double *a, std::ptrdiff_t lda, double *b, std::ptrdiff_t ldb, double *s, double rcond, Index *rank, double *work, std::ptrdiff_t lwork, Index *iwork)
The minimum-norm least-squares solutions of A X ≈ B, column-major A m × n and B max(m,...
constexpr std::size_t gemv_rows
The rows (or, for Aᵀ x, the columns) each task of gemv takes, 64 so that an order of a few hundred sh...
int geqrf(std::ptrdiff_t m, std::ptrdiff_t n, double *a, std::ptrdiff_t lda, double *tau, double *work, std::ptrdiff_t lwork)
The QR factorisation A = Q R of a column-major m × n A, as LAPACK's dgeqrf: R overwrites the upper tr...
constexpr std::size_t gemv_weight
The weight of gemv's multiply-adds against a compute-bound product's: each reads an element of A once...
constexpr std::size_t gemm_packed_threshold
Below this many multiply-adds the plain loop (gemm_rows, by blocks of rows held in registers) runs in...
C complex_dot_product(const C *x, const C *y, std::size_t count)
Σ x[i] · y[i] of complex numbers: on the x86-64 units with AVX2 (the AVX-512 path too) their fused ch...
void form_q_into(buffer< T > &out, const std::vector< reflector_block< T > > &blocks, std::size_t rows, std::size_t first, std::size_t count, bool transposed)
The columns [first, first + count) of Q = H₀ H₁ …, the blocks applied (the last first) to those of th...
T conjugate_dot_product(const T *x, const T *y, std::size_t count)
Σ conj(x[i]) · y[i], in order, where no native vector holds the parts.
T chunked_dot(const T *a, const T *b, std::size_t count)
Σ a[i] · b[i] for a plain dot product: chunks of dot_chunk elements in parallel, each by dot_product ...
void gemm_at(std::size_t m, std::size_t n, std::size_t k, const T *at, std::size_t ldat, const T *b, std::size_t ldb, T *c, std::size_t ldc)
gemm_layouts with A given as Aᵀ (at, k × m, ldat apart).
void add_product(double *y, const double &f, const double *x, std::size_t count)
y[i] += f · x[i] for double, as subtract_product.
void row_dots(const std::complex< double > *m, std::size_t ld, std::size_t rows, const std::complex< double > *x, std::size_t count, std::complex< double > *out)
row_dots for std::complex<double>, through complex_row_dots.
void subtract_products(double *y, const double *f, const double *x, std::size_t ldx, std::size_t terms, std::size_t count)
y[i] -= Σₜ f[t] · x[(t · ldx) + i] for double, the units chosen as subtract_product chooses them,...
std::vector< reflector_block< T > > reflect_in_rows(buffer< T > &a, std::size_t rows, std::size_t cols, buffer< T > *r=nullptr)
The blocks of reflectors of a Householder QR of the row-major a (rows × cols), factorised in place as...
T conj_of(const T &x)
The conjugate of a real (or general) scalar — the value itself.
void gemm_bt(std::size_t m, std::size_t n, std::size_t k, const T *a, std::size_t lda, const T *bt, std::size_t ldbt, T *c, std::size_t ldc)
gemm_layouts with B given as Bᵀ (bt, n × k, ldbt apart).
constexpr std::size_t narrow_solve
The most right-hand sides an LU solve takes row by row rather than by blocks through the product kern...
reflector_block< T > gather_reflectors(const std::vector< buffer< T > > &reflectors, std::size_t k0, std::size_t k1, std::size_t rows, const std::vector< T > *taus=nullptr)
Gathers the reflectors reflectors[k0…k1-1] (each I − τ_k v vᴴ: τ_k from taus, else 2 for a unit v; an...
void gemm(std::size_t m, std::size_t n, std::size_t k, const T *a, std::size_t lda, const T *b, std::size_t ldb, T *c, std::size_t ldc)
C += A·B, every element of C summed in ascending order of the depth.
void parallel_for(std::size_t count, std::size_t work_per_index, const Body &body)
Runs body(i) for every i in [0, count).
constexpr std::size_t qr_block
The reflectors of one panel of the blocked QR.
constexpr std::size_t gemm_min_depth
Below this depth the plain loop runs too: each panel reads and writes its tiles of C once,...
std::vector< reflector_block< T > > reflect_in_columns(buffer< T > &columns, std::size_t rows, std::size_t cols)
The blocks of reflectors of a Householder QR of the column-major columns (rows per column,...
void gemm_atbt(std::size_t m, std::size_t n, std::size_t k, const T *at, std::size_t ldat, const T *bt, std::size_t ldbt, T *c, std::size_t ldc)
gemm_layouts with both operands given as their transposes.
std::vector< T, detail::default_init_allocator< T > > buffer
The storage of vector, matrix and tensor, namely a std::vector whose buffer<T>(n) and resize(n) leave...
T sum(const tensor< T > &t)
The sum of every element, by pairwise halving (0 for an empty tensor).
least_squares_solution< T > least_squares(const matrix< T > &a, const matrix< T > &b, rank_cutoff cutoff={})
lstsq, with the residuals, the rank and the singular values numpy.linalg.lstsq returns beside the sol...
@ amx
The Apple AMX coprocessor, fused multiply-adds; the products it does not suit on the NEON path's tile...
@ divide_and_conquer
Golub–Kahan bidiagonalisation then divide and conquer, as LAPACK's dgesdd: the default.
vector< double > singular_values(const matrix< T > &a)
The singular values of a, descending, without its singular vectors, as numpy.linalg....
vector< double > symmetric_eigenvalues(const matrix< T > &a)
The eigenvalues of the real symmetric or complex Hermitian a, ascending, without its eigenvectors,...
A minimal std::thread parallel-for for the hot kernels.
The operands of syrk_triangle, which are row-major P = op(A) and Q = op(A)ᵀ (one of them scaled by α)...
std::size_t ldp
P's row distance.
bool q_is_pt
Q is Pᵀ read from P's rows (numerical::detail::gemm_bt), q unused.
const double * p
P, n × depth.
bool p_is_qt
P is Qᵀ read from Q's columns (numerical::detail::gemm_at), p unused.
const double * q
Q, depth × n.
std::size_t ldc
C's column distance.
std::size_t ldq
Q's row distance.
bool lower
The lower triangle (else the upper).
double * c
C, column-major.
The reflectors of one panel of the blocked QR, I − V T Vᴴ as LAPACK's dlarft forms it.
A least-squares solution and what numpy.linalg.lstsq reports beside it (least_squares).