326 static constexpr int B = Shape.border;
327 static constexpr int S = Shape.block;
328 static constexpr int NB = Shape.blocks;
329 static constexpr bool col = Config.layout == MatrixLayout::ColMajor;
330 static constexpr bool diag = Config.coupling == ArrowheadCoupling::Diagonal;
333 static constexpr bool reg = detail::arrowhead_register_blocks(Config, S);
336 static constexpr int rhs_pass = detail::arrowhead_rhs_pass_width(Config, reg);
337#if defined(TDLS_DETAIL_SIDE_DISPATCH)
341 detail::arrowhead_resolved_config<T, true>(Config, S);
344 detail::arrowhead_resolved_config<T, false>(Config, S);
347 static constexpr bool sided =
357 template<
typename U, ArrowheadShape OtherShape, ArrowheadLUppConfig<U> OtherConfig>
363 static constexpr int R = diag ? S : B;
364 static constexpr int R0 = diag ? Shape.coupling_row : 0;
372 shape_value() noexcept {
373 return {B, S, NB, R0};
377 static constexpr int front_rows = S + B;
381 static constexpr int front_cols_for = S + B + R + nc;
384 static constexpr int extra_cols = R > S ? R - S : 0;
392 front_rows * front_cols_for<nrhs> + NB * S * extra_cols;
397 static constexpr int pass_width = rhs_pass == 0 ? B + 1 : rhs_pass;
403 static constexpr int pass_width_for = rhs_pass == 0 || rhs_pass > B + ny ? B + ny : rhs_pass;
409 static constexpr bool forward_check_for = !reg && col && pass_width_for<ny> == B + ny;
415 static constexpr bool stores_recovery_for = ny > 0;
423 static constexpr bool multiplier_update =
424 !col && !diag && Config.condensation == ArrowheadCondensation::MinFlops;
427 static constexpr bool in_place = Config.schur_in_place;
429 static_assert(Shape.border >= 1 && Shape.block >= 1 && Shape.blocks >= 1,
430 "ArrowheadLUppSolverStatic: border, block and blocks must be >= 1");
431 static_assert(diag || Shape.coupling_row == 0,
432 "ArrowheadLUppSolverStatic: coupling_row applies to the diagonal coupling only");
433 static_assert(!diag || (Shape.coupling_row >= 0 && Shape.coupling_row + S <= B),
434 "ArrowheadLUppSolverStatic: the diagonal coupling rows exceed the border");
435 static_assert(Config.storage != ArrowheadStorage::Bsr ||
436 (B % S == 0 && (!diag || Shape.coupling_row % S == 0)),
437 "ArrowheadLUppSolverStatic: the Bsr storage needs a border (and a coupling_row) "
438 "multiple of the block");
440 "ArrowheadLUppSolverStatic: the storage exceeds 2^31 entries");
441 static_assert(Config.condensation_pivot_threshold.is_finite() &&
442 T(Config.condensation_pivot_threshold) >= T(0) &&
443 T(Config.condensation_pivot_threshold) <= T(1),
444 "ArrowheadLUppSolverStatic: condensation_pivot_threshold must be in [0, 1]");
449 static constexpr T condensation_pivot_threshold = Config.condensation_pivot_threshold;
450 static_assert(Config.rhs_pass_width >= -1 && Config.rhs_pass_width <= Shape.border + 1,
451 "ArrowheadLUppSolverStatic: rhs_pass_width must be in [-1, border + 1]");
462 template<
typename U, ArrowheadShape OtherShape, ArrowheadLUppConfig<U> OtherConfig>
468 c.
storage = ArrowheadStorage::Packed;
477 template<
int capacity>
479 store_shape() noexcept {
480 return {B, S, capacity, R0};
489 template<
int capacity,
int nrhs>
490 [[nodiscard]]
TDLS_HOST_DEVICE static constexpr int recomputed_size() noexcept {
491 if constexpr (capacity == 0) {
502 template<
int capacity>
546 template<
bool internal_rhs,
bool internal_work,
bool internal_matrix,
552 const int rhs_stride,
int& refused_count)
noexcept {
553 if constexpr (Config.streamed_out_of_line)
554 return solve_core_out_of_line<1,
false, internal_rhs, internal_work, internal_matrix,
555 A_static_stride, work_static_stride, rhs_static_stride>(
556 A, A_stride, work, work_stride, y, rhs_stride, 0, 0, refused_count, &provider);
558 return solve_core<1,
false, internal_rhs, internal_work, internal_matrix,
559 A_static_stride, work_static_stride, rhs_static_stride>(
560 A, A_stride, work, work_stride, y, rhs_stride, 0, 0, refused_count, &provider);
618 template<
int ntan,
bool internal_rhs,
bool internal_work,
bool internal_matrix,
621 typename Provider,
typename Converged,
bool outlined =
false>
627 const int x_stride,
const std::size_t xcol_stride,
628 int& refused_count)
noexcept {
629 static_assert(ntan >= 1 && ntan <= Shape.border,
630 "ArrowheadLUppSolverStatic: ntan must be in [1, border]");
632 ntan, internal_rhs, internal_work, internal_matrix, A_static_stride,
633 work_static_stride, rhs_static_stride, x_static_stride, Provider,
634 Converged, outlined>(
635 std::forward<Provider>(provider), std::forward<Converged>(converged), A, A_stride, work,
636 work_stride, y, rhs_stride, col0, x, x_stride, xcol_stride, refused_count))
637 if constexpr (Config.streamed_out_of_line && !outlined)
638 return streamed_or_tangent_out_of_line<
639 ntan, internal_rhs, internal_work, internal_matrix, A_static_stride,
640 work_static_stride, rhs_static_stride, x_static_stride>(
641 provider, converged, A, A_stride, work, work_stride, y, rhs_stride, col0, x,
642 x_stride, xcol_stride, refused_count);
644 return streamed_or_tangent_core<ntan, internal_rhs, internal_work, internal_matrix,
645 A_static_stride, work_static_stride, rhs_static_stride,
646 x_static_stride>(provider, converged, A, A_stride, work,
647 work_stride, y, rhs_stride, col0, x,
648 x_stride, xcol_stride, refused_count);
681 template<
int nrhs,
bool internal_rhs,
bool internal_work,
bool internal_matrix,
686 const int work_stride,
const int col0, T*
TDLS_RESTRICT x,
const int rhs_stride,
687 const std::size_t xcol_stride,
int& refused_count)
noexcept {
688 static_assert(nrhs >= 1 && nrhs <= Shape.border,
689 "ArrowheadLUppSolverStatic: nrhs must be in [1, border]");
690 if constexpr (Config.streamed_out_of_line)
691 return solve_core_out_of_line<nrhs,
true, internal_rhs, internal_work, internal_matrix,
692 A_static_stride, work_static_stride, rhs_static_stride>(
693 A, A_stride, work, work_stride, x, rhs_stride, xcol_stride, col0, refused_count,
696 return solve_core<nrhs,
true, internal_rhs, internal_work, internal_matrix,
697 A_static_stride, work_static_stride, rhs_static_stride>(
698 A, A_stride, work, work_stride, x, rhs_stride, xcol_stride, col0, refused_count,
723 template<
bool internal_rhs,
bool internal_work,
bool internal_matrix,
728 const int work_stride, T*
TDLS_RESTRICT y,
const int rhs_stride,
729 int& refused_count)
noexcept {
730 return solve_core<1,
false, internal_rhs, internal_work, internal_matrix, A_static_stride,
731 work_static_stride, rhs_static_stride>(A, A_stride, work, work_stride, y,
732 rhs_stride, 0, 0, refused_count);
752 template<
bool internal_rhs,
bool internal_work,
bool internal_matrix,
757 const int work_stride, T*
TDLS_RESTRICT y,
const int rhs_stride)
noexcept {
758 int refused_count = 0;
759 return solve_inplace<internal_rhs, internal_work, internal_matrix, A_static_stride,
760 work_static_stride, rhs_static_stride>(A, A_stride, work, work_stride,
761 y, rhs_stride, refused_count);
787 template<
bool internal_rhs,
bool internal_work,
bool internal_matrix,
793 int& refused_count)
noexcept {
794 const int stride = detail::stride_or<rhs_static_stride>(rhs_stride);
796 if constexpr (internal_rhs)
801 return solve_inplace<internal_rhs, internal_work, internal_matrix, A_static_stride,
802 work_static_stride, rhs_static_stride>(A, A_stride, work, work_stride,
803 x, rhs_stride, refused_count);
825 template<
bool internal_rhs,
bool internal_work,
bool internal_matrix,
831 int refused_count = 0;
832 return solve<internal_rhs, internal_work, internal_matrix, A_static_stride,
833 work_static_stride, rhs_static_stride>(A, A_stride, work, work_stride, b, x,
834 rhs_stride, refused_count);
869 template<
int nrhs,
bool internal_rhs,
bool internal_work,
bool internal_matrix,
874 const int work_stride, T*
TDLS_RESTRICT y,
const int rhs_stride,
875 const std::size_t xcol_stride,
int& refused_count)
noexcept {
876 static_assert(nrhs >= 1,
"ArrowheadLUppSolverStatic: nrhs must be >= 1");
877 return solve_core<nrhs,
false, internal_rhs, internal_work, internal_matrix,
878 A_static_stride, work_static_stride, rhs_static_stride>(
879 A, A_stride, work, work_stride, y, rhs_stride, xcol_stride, 0, refused_count);
904 template<
int nrhs,
bool internal_rhs,
bool internal_work,
bool internal_matrix,
909 const int work_stride, T*
TDLS_RESTRICT y,
const int rhs_stride,
910 const std::size_t xcol_stride)
noexcept {
911 int refused_count = 0;
913 A_static_stride, work_static_stride, rhs_static_stride>(
914 A, A_stride, work, work_stride, y, rhs_stride, xcol_stride, refused_count);
944 template<
int nrhs,
bool internal_rhs,
bool internal_work,
bool internal_matrix,
950 const int rhs_stride,
const std::size_t xcol_stride,
951 int& refused_count)
noexcept {
952 const int stride = detail::stride_or<rhs_static_stride>(rhs_stride);
953 for (
int m = 0; m < nrhs; ++m)
955 if constexpr (internal_rhs)
962 A_static_stride, work_static_stride, rhs_static_stride>(
963 A, A_stride, work, work_stride, x, rhs_stride, xcol_stride, refused_count);
988 template<
int nrhs,
bool internal_rhs,
bool internal_work,
bool internal_matrix,
994 const int rhs_stride,
const std::size_t xcol_stride)
noexcept {
995 int refused_count = 0;
996 return solve_multirhs<nrhs, internal_rhs, internal_work, internal_matrix, A_static_stride,
997 work_static_stride, rhs_static_stride>(
998 A, A_stride, work, work_stride, b, x, rhs_stride, xcol_stride, refused_count);
1043 template<
int nrhs,
bool internal_rhs,
bool internal_work,
bool internal_matrix,
1049 const int rhs_stride,
const std::size_t xcol_stride,
1050 int& refused_count)
noexcept {
1051 static_assert(nrhs >= 1 && nrhs <= Shape.border,
1052 "ArrowheadLUppSolverStatic: nrhs must be in [1, border]");
1053 return solve_core<nrhs,
true, internal_rhs, internal_work, internal_matrix, A_static_stride,
1054 work_static_stride, rhs_static_stride>(
1055 A, A_stride, work, work_stride, x, rhs_stride, xcol_stride, col0, refused_count);
1082 template<
int nrhs,
bool internal_rhs,
bool internal_work,
bool internal_matrix,
1088 const int rhs_stride,
const std::size_t xcol_stride)
noexcept {
1089 int refused_count = 0;
1091 A_static_stride, work_static_stride,
1093 A, A_stride, work, work_stride, col0, x, rhs_stride, xcol_stride, refused_count);
1106 template<
int capacity,
int nrhs = 1>
1166 template<
int capacity,
bool internal_rhs,
bool internal_work,
bool internal_matrix,
1172 const int rhs_stride,
int& refused_count)
noexcept {
1173 return recomputed_core<0, capacity, internal_rhs, internal_work, internal_matrix,
1174 Abb_static_stride, work_static_stride, rhs_static_stride,
1176 rhs_stride, 0,
nullptr, 1, 0, refused_count);
1230 template<
int ntan,
int capacity,
bool internal_rhs,
bool internal_work,
bool internal_matrix,
1233 typename Provider,
typename Converged>
1240 const std::size_t xcol_stride,
1241 int& refused_count)
noexcept {
1242 static_assert(ntan >= 1 && ntan <= Shape.border,
1243 "ArrowheadLUppSolverStatic: ntan must be in [1, border]");
1244 return recomputed_core<ntan, capacity, internal_rhs, internal_work, internal_matrix,
1245 Abb_static_stride, work_static_stride, rhs_static_stride,
1246 x_static_stride>(provider, Abb, Abb_stride, work, work_stride, y,
1247 rhs_stride, col0, x, x_stride, xcol_stride,
1248 refused_count, &converged);
1257#if defined(TDLS_DETAIL_COMPILER_GCC)
1258#pragma GCC diagnostic push
1259#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
1294 template<
int ntan,
int capacity,
bool internal_rhs,
bool internal_work,
bool internal_matrix,
1297 typename Provider,
typename... Converged>
1299 recomputed_core(Provider& provider,
const T*
TDLS_RESTRICT Abb,
const int Abb_stride_arg,
1301 [[maybe_unused]]
const int work_stride_arg, T*
TDLS_RESTRICT y,
1302 const int rhs_stride_arg, [[maybe_unused]]
const int col0,
1303 [[maybe_unused]] T*
TDLS_RESTRICT x, [[maybe_unused]]
const int x_stride_arg,
1304 [[maybe_unused]]
const std::size_t xcol_stride,
int& refused_count,
1305 Converged*... converged)
noexcept {
1306 const int Abb_stride = detail::stride_or<Abb_static_stride>(Abb_stride_arg);
1307 [[maybe_unused]]
const int work_stride =
1308 detail::stride_or<work_static_stride>(work_stride_arg);
1309 const int rhs_stride = detail::stride_or<rhs_static_stride>(rhs_stride_arg);
1310 [[maybe_unused]]
const int x_stride = detail::stride_or<x_static_stride>(x_stride_arg);
1312 template recomputed_core<ntan, capacity, internal_rhs, internal_work, internal_matrix,
1313 Abb_static_stride, work_static_stride, rhs_static_stride,
1314 x_static_stride>(provider, Abb, Abb_stride, work, work_stride,
1315 y, rhs_stride, col0, x, x_stride, xcol_stride,
1316 refused_count, converged...))
1317 static_assert(capacity >= 0 && capacity <= NB,
1319 "must be in [0, blocks]");
1321 "Schur complement apart (schur_in_place off)");
1324 constexpr
int fnc = ntan > 1 ? ntan : 1;
1331 Sacc[r * B + c] = border_entry<internal_matrix>(
1332 Abb, Abb_stride, R0 + r, c);) racc[r] =
1334 constexpr
int words = (NB + 31) / 32;
1335 unsigned refused[words];
1339#if defined(TDLS_DETAIL_CODEGEN_NVCXX)
1346 for (
int k = 0; k < NB; ++k) {
1347#if defined(TDLS_DETAIL_CODEGEN_NVCXX)
1352 blk.recovery =
false;
1356 constexpr bool forward_check = forward_check_for<1>;
1358 T Wsave[forward_check ? (B + 1) * S : 1];
1360 if constexpr (forward_check) {
1365 if (condense_streamed<1, true, true, true>(
nullptr, 1,
nullptr, 1, 0, k, Sacc, racc,
1371 refused_count = count;
1372 refused[k >> 5] |= 1u << (k & 31);
1373 if constexpr (capacity == 0) {
1374 return RecomputedOutcome::deferred;
1376 if (count > capacity)
return RecomputedOutcome::deferred;
1378 if constexpr (forward_check) {
1381 keep_refused<capacity, fnc, internal_work>(work, work_stride, count - 1, blk);
1389 Sbb[r * B + c] = acc ? Sacc[(acc ? r - R0 : 0) * B + c]
1390 : border_entry<internal_matrix>(Abb, Abb_stride, r, c);))
1391 if constexpr (
sizeof...(Converged) > 0) {
1392 if ((*streamed_arg(converged...))()) {
1399 if constexpr (capacity > 0) {
1401 !second_pass_refused<capacity, fnc, fnc,
true, internal_work,
1402 work_static_stride>(work, work_stride, count, Sbb, rt))
1403 return RecomputedOutcome::singular;
1407 if constexpr (fnc == 1)
1412 Sbb, 1, pt, 1, rt, 1, B);
1413 if (!ok)
return RecomputedOutcome::singular;
1417 x[internal_rhs ?
unsigned(m * B + r)
1421 return RecomputedOutcome::tangent;
1427 if constexpr (capacity > 0) {
1429 !second_pass_refused<capacity, fnc, 1, false, internal_work, work_static_stride>(
1430 work, work_stride, count, Sbb, rb))
1431 return RecomputedOutcome::singular;
1435 return RecomputedOutcome::singular;
1438 for (
int k = NB - 1; k >= 0; --k) {
1439 if ((refused[k >> 5] >> (k & 31)) & 1u)
continue;
1440#if defined(TDLS_DETAIL_CODEGEN_NVCXX)
1445 blk.recovery =
true;
1450 recover_block(blk.Dl, xk);
1453 if constexpr (capacity > 0) {
1455 recover_refused<capacity, fnc, internal_rhs, internal_work, work_static_stride,
1456 rhs_static_stride>(work, work_stride, y, rhs_stride, refused, count,
1460 return RecomputedOutcome::solved;
1462#if defined(TDLS_DETAIL_COMPILER_GCC)
1463#pragma GCC diagnostic pop
1474 template<
bool internal_matrix>
1476 border_entry(
const T*
TDLS_RESTRICT Abb,
const int Abb_stride,
const int r,
1477 const int c)
noexcept {
1478 const int e = col ? c * B + r : r * B + c;
1479 return Abb[internal_matrix ? unsigned(e) :
TDLS_STRIDED(e, Abb_stride)];
1493 template<
int capacity,
int fnc,
bool internal_work>
1495 keep_refused(T*
TDLS_RESTRICT work,
const int work_stride,
const int j,
1497 using Store = RefusedStore<capacity>;
1498 using Map =
typename Store::storage_map;
1500 constexpr int oy = off + Store::storage_size;
1505 blk.Dl[col ? j2 * S + i : i * S + j2];)
1508 c)) = blk.W[c * S + i];)
1510 if constexpr (diag) {
1513 TDLS_ARROW_LUPP_W(off + Map::abk_diag(store_shape<capacity>(), j, i)) = blk.Abk[i];)
1519 i)) = blk.Abk[r * S + i];))
1542 template<
int capacity,
int fnc,
int nc,
bool canonical,
bool internal_work,
1545 second_pass_refused(T*
TDLS_RESTRICT work,
const int work_stride_arg,
const int count,
1547 const int work_stride = detail::stride_or<work_static_stride>(work_stride_arg);
1548 using Store = RefusedStore<capacity>;
1550 constexpr int oy = off + Store::storage_size;
1551 constexpr int words = (capacity + 31) / 32;
1552 unsigned held[words];
1553 for (
int e = 0; e < words; ++e)
1555 for (
int j = 0; j < count; ++j)
1556 held[j >> 5] |= 1u << (j & 31);
1557 T*
const store = work + (internal_work ? off :
TDLS_STRIDED(off, work_stride));
1558 T*
const ystore = work + (internal_work ? oy :
TDLS_STRIDED(oy, work_stride));
1559 return Store::template second_pass<nc, canonical, internal_work, internal_work,
1560 internal_work, work_static_stride, work_static_stride,
1561 work_static_stride>(
1562 store, work_stride, work, work_stride, ystore, work_stride, 0, held, Sbb, rb,
1568#if defined(TDLS_DETAIL_COMPILER_GCC)
1569#pragma GCC diagnostic push
1570#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
1581 if constexpr (reg) {
1582 (void)register_factor(Dl, pl);
1583 register_solve<1, true>(Dl, pl, x);
1585 (void)BlockSolver::template factorize<true, true>(Dl, 1, pl, 1);
1586 BlockSolver::template substitute_inplace<true, true, true>(Dl, 1, pl, 1, x, 1);
1590#if defined(TDLS_DETAIL_COMPILER_GCC)
1591#pragma GCC diagnostic pop
1613 template<
int capacity,
int fnc,
bool internal_rhs,
bool internal_work,
1617 const int rhs_stride_arg,
const unsigned*
TDLS_RESTRICT refused,
1619 const int work_stride = detail::stride_or<work_static_stride>(work_stride_arg);
1620 const int rhs_stride = detail::stride_or<rhs_static_stride>(rhs_stride_arg);
1621 using Store = RefusedStore<capacity>;
1622 using Map =
typename Store::storage_map;
1624 constexpr int oy = off + Store::storage_size;
1625 constexpr int fcols = front_cols_for<1>;
1627 for (
int a = 0; a < R; ++a)
1630 for (
int k = NB - 1; k >= 0; --k) {
1631 if (!((refused[k >> 5] >> (k & 31)) & 1u))
continue;
1634 for (
int i = 0; i < S; ++i) {
1636 for (
int c = 0; c < B; ++c)
1639 for (
int a = 0; a < R; ++a) {
1641 a < S ? TDLS_ARROW_LUPP_W(off + Map::d(store_shape<capacity>(), j, i, a))
1647 if constexpr (diag) {
1648 for (
int i = 0; i < S; ++i)
1652 for (
int r = 0; r < B; ++r)
1653 for (
int i = 0; i < S; ++i)
1658 for (
int i = 0; i < S; ++i)
1696 template<
int ntan,
bool internal_rhs,
bool internal_work,
bool internal_matrix,
1699 typename Provider,
typename Converged>
1701 streamed_or_tangent_core(Provider& provider, Converged& converged, T*
TDLS_RESTRICT A,
1704 const int rhs_stride_arg,
const int col0, T*
TDLS_RESTRICT x,
1705 const int x_stride_arg,
const std::size_t xcol_stride,
1706 int& refused_count)
noexcept {
1707 const int A_stride = detail::stride_or<A_static_stride>(A_stride_arg);
1708 const int work_stride = detail::stride_or<work_static_stride>(work_stride_arg);
1709 const int rhs_stride = detail::stride_or<rhs_static_stride>(rhs_stride_arg);
1710 const int x_stride = detail::stride_or<x_static_stride>(x_stride_arg);
1711 constexpr int ny = 1;
1712 [[maybe_unused]]
constexpr int ycols = 1;
1713 T Sacc[in_place ? 1 : R * B];
1714 T racc[in_place ? 1 : R];
1715 if constexpr (in_place) {
1726 constexpr int words = (NB + 31) / 32;
1727 unsigned refused[words];
1730 for (
int k = 0; k < NB; ++k) {
1733 if (!condense_or_store_streamed<ny, internal_rhs, internal_matrix>(
1734 A, A_stride, y, rhs_stride, 0, k, Sacc, racc, blk)) {
1735 refused[k >> 5] |= 1u << (k & 31);
1743 constexpr int acc0 = in_place ? B : R0;
1744 constexpr int acc1 = in_place ? B : R0 + R;
1762 if (refused_count > 0 &&
1763 !second_pass<ntan,
true, internal_rhs, internal_work, internal_matrix,
1764 A_static_stride, work_static_stride, rhs_static_stride>(
1765 A, A_stride, work, work_stride, y, rhs_stride, 0, refused, Sbb, rt,
1767 return StreamedOutcome::singular;
1769 if constexpr (ntan == 1)
1773 Sbb, 1, pb, 1, rt, 1, B);
1774 if (!ok)
return StreamedOutcome::singular;
1778 x[internal_rhs ?
unsigned(m * B + r)
1782 return StreamedOutcome::tangent;
1788 if (refused_count > 0 &&
1789 !second_pass<1,
false, internal_rhs, internal_work, internal_matrix, A_static_stride,
1790 work_static_stride, rhs_static_stride>(A, A_stride, work, work_stride, y,
1791 rhs_stride, 0, refused, Sbb, rb,
1793 return StreamedOutcome::singular;
1795 return StreamedOutcome::singular;
1797 recover<1, internal_rhs, internal_work, internal_matrix>(A, A_stride, work, work_stride, y,
1798 rhs_stride, 0, refused, rb);
1799 return StreamedOutcome::solved;
1805 template<
int ntan,
bool internal_rhs,
bool internal_work,
bool internal_matrix,
1806 int A_static_stride,
int work_static_stride,
int rhs_static_stride,
1807 int x_static_stride,
typename Provider,
typename Converged>
1809 streamed_or_tangent_out_of_line(Provider& provider, Converged& converged, T*
TDLS_RESTRICT A,
1811 const int work_stride, T*
TDLS_RESTRICT y,
const int rhs_stride,
1813 const std::size_t xcol_stride,
int& refused_count)
noexcept {
1815 ntan, internal_rhs, internal_work, internal_matrix, A_static_stride, work_static_stride,
1816 rhs_static_stride, x_static_stride, Provider&, Converged&,
true>(
1817 provider, converged, A, A_stride, work, work_stride, y, rhs_stride, col0, x, x_stride,
1818 xcol_stride, refused_count);
1824 template<
int nc,
bool canonical,
bool internal_rhs,
bool internal_work,
bool internal_matrix,
1825 int A_static_stride,
int work_static_stride,
int rhs_static_stride,
typename Provider>
1828 const int work_stride, T*
TDLS_RESTRICT y,
const int rhs_stride,
1829 const std::size_t xcol_stride,
const int col0,
int& refused_count,
1830 Provider* provider)
noexcept {
1831 return solve_core<nc, canonical, internal_rhs, internal_work, internal_matrix,
1832 A_static_stride, work_static_stride, rhs_static_stride>(
1833 A, A_stride, work, work_stride, y, rhs_stride, xcol_stride, col0, refused_count,
1844 template<
typename P>
1846 streamed_arg(P* p)
noexcept {
1882 template<
int nc,
bool canonical,
bool internal_rhs,
bool internal_work,
bool internal_matrix,
1887 const int work_stride_arg, T*
TDLS_RESTRICT y,
const int rhs_stride_arg,
1888 [[maybe_unused]]
const std::size_t xcol_stride, [[maybe_unused]]
const int col0,
1889 int& refused_count, Provider*... provider)
noexcept {
1890 const int A_stride = detail::stride_or<A_static_stride>(A_stride_arg);
1891 const int work_stride = detail::stride_or<work_static_stride>(work_stride_arg);
1892 const int rhs_stride = detail::stride_or<rhs_static_stride>(rhs_stride_arg);
1894 template solve_core<nc, canonical, internal_rhs, internal_work, internal_matrix,
1895 A_static_stride, work_static_stride, rhs_static_stride>(
1896 A, A_stride, work, work_stride, y, rhs_stride, xcol_stride, col0, refused_count,
1898 constexpr
bool streamed = sizeof...(Provider) > 0;
1900 constexpr
int ny = canonical ? 0 : nc;
1902 [[maybe_unused]] constexpr
int ycols = nc;
1905 T Sacc[in_place ? 1 : R * B];
1906 T racc[in_place || ny == 0 ? 1 : R * ny];
1907 if constexpr (in_place) {
1913 if constexpr (ny == 0) racc[0] = T(0);
1921 constexpr int words = (NB + 31) / 32;
1922 unsigned refused[words];
1925 for (
int k = 0; k < NB; ++k) {
1926 if constexpr (streamed) {
1929 "ArrowheadLUppSolverStatic: streamed blocks carry one right-hand side");
1931 (*streamed_arg(provider...))(k, blk);
1932 if (!condense_or_store_streamed<ny, internal_rhs, internal_matrix>(
1933 A, A_stride, y, rhs_stride, xcol_stride, k, Sacc, racc, blk)) {
1934 refused[k >> 5] |= 1u << (k & 31);
1938 if (!condense<ny, internal_rhs, internal_matrix>(A, A_stride, y, rhs_stride,
1939 xcol_stride, k, Sacc, racc)) {
1940 refused[k >> 5] |= 1u << (k & 31);
1952 constexpr int acc0 = in_place ? B : R0;
1953 constexpr int acc1 = in_place ? B : R0 + R;
1959 m, 0, nc,
if constexpr (canonical) rb[m * B + r] = r == col0 + m ? T(1) : T(0);
1964 if constexpr (canonical) rb[m * B + r] =
1965 r == col0 + m ? T(1) : T(0);
1966 else rb[m * B + r] = racc[m * R + r - R0];))
1972 m, 0, nc, if constexpr (canonical) rb[m * B + r] = r == col0 + m ? T(1) : T(0);
1974 if (refused_count > 0 &&
1975 !second_pass<nc, canonical, internal_rhs, internal_work, internal_matrix,
1976 A_static_stride, work_static_stride, rhs_static_stride>(
1977 A, A_stride, work, work_stride, y, rhs_stride, xcol_stride, refused, Sbb, rb,
1978 BlockSolver::singular_floor))
1981 if constexpr (nc == 1) {
1989 if constexpr (canonical) {
1993 y[internal_rhs ?
unsigned(m * B + r)
2000 recover<nc, internal_rhs, internal_work, internal_matrix>(
2001 A, A_stride, work, work_stride, y, rhs_stride, xcol_stride, refused, rb);
2032 template<
int ny,
bool internal_rhs,
bool internal_matrix>
2035 [[maybe_unused]]
const std::size_t xcol_stride,
const int k, T*
TDLS_RESTRICT Sacc,
2037 constexpr bool forward_check = forward_check_for<ny>;
2038 [[maybe_unused]]
constexpr int ycols = ny;
2053 if constexpr (reg) {
2054 const int verdict = register_factor(Dl, pl);
2055 if (verdict == 2)
return false;
2058 if (!BlockSolver::template factorize<true, true>(Dl, 1, pl, 1))
return false;
2063 T acoef[diag ? S : 1];
2064 if constexpr (diag) {
2073 T U[forward_check || reg ? 1 : S * S];
2074 if constexpr (forward_check || reg) U[0] = T(0);
2075 if constexpr (!reg) ok = lower_pass<!forward_check>(Dl, pl, U);
2076 const T*
const Uf = reg ? Dl : U;
2077 if constexpr (forward_check) {
2086 BlockSolver::template forward_inplace_multirhs<B + ny, true, true, true>(Dl, 1, pl, 1,
2089 const T u = condensation_pivot_threshold;
2091 if (!ok)
return false;
2092 BlockSolver::template backward_inplace_multirhs<B + ny, true, true, true>(Dl, 1, pl, 1,
2094 condense_pass<0, true, ny, internal_rhs, internal_matrix>(
2095 A, A_stride, y, rhs_stride, xcol_stride, k, Dl, pl, acoef,
nullptr, Sacc, racc, W);
2097 T Mb[multiplier_update ? R * S : 1];
2098 if constexpr (!multiplier_update) Mb[0] = T(0);
2099 ok = border_multipliers<internal_matrix>(A, A_stride, k, Uf, acoef, Mb) && ok;
2100 if (!ok)
return false;
2101 if constexpr (multiplier_update && stores_recovery_for<ny>)
2102 store_upper<internal_matrix>(A, A_stride, k, Uf);
2103 condense_pass<0, false, ny, internal_rhs, internal_matrix>(
2104 A, A_stride, y, rhs_stride, xcol_stride, k, Dl, pl, acoef, Mb, Sacc, racc,
nullptr);
2116#if defined(TDLS_DETAIL_COMPILER_GCC)
2117#pragma GCC diagnostic push
2118#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
2147 template<
int ny,
bool internal_rhs,
bool internal_matrix,
bool recompute = false>
2150 const int rhs_stride, [[maybe_unused]]
const std::size_t xcol_stride,
2153 constexpr bool forward_check = forward_check_for<ny>;
2154 constexpr int cols = B + ny;
2155 [[maybe_unused]]
constexpr int ycols = ny == 0 ? 1 : ny;
2157 T*
const Dl = blk.Dl;
2161 if constexpr (reg) {
2162 const int verdict = register_factor(Dl, pl);
2163 if (verdict == 2)
return false;
2166 if (!BlockSolver::template factorize<true, true>(Dl, 1, pl, 1))
return false;
2168 const T*
const acoef = blk.Abk;
2169 T U[forward_check || reg ? 1 : S * S];
2170 if constexpr (forward_check || reg) U[0] = T(0);
2171 if constexpr (!reg) ok = lower_pass<!forward_check>(Dl, pl, U);
2172 const T*
const Uf = reg ? Dl : U;
2173 T Mb[multiplier_update ? R * S : 1];
2174 if constexpr (!multiplier_update) Mb[0] = T(0);
2175 if constexpr (forward_check) {
2176 BlockSolver::template forward_inplace_multirhs<cols, true, true, true>(Dl, 1, pl, 1, W,
2178 const T u = condensation_pivot_threshold;
2180 if (!ok)
return false;
2181 BlockSolver::template backward_inplace_multirhs<cols, true, true, true>(Dl, 1, pl, 1, W,
2184 ok = border_multipliers<internal_matrix>(A, A_stride, k, Uf, acoef, Mb, bp) && ok;
2185 if (!ok)
return false;
2186 if constexpr (pass_width_for<ny> < cols) {
2190 if constexpr (multiplier_update && stores_recovery_for<ny> && !recompute)
2191 store_upper<internal_matrix>(A, A_stride, k, Uf);
2192 condense_pass<0, false, ny, internal_rhs, internal_matrix, recompute>(
2193 A, A_stride, y, rhs_stride, xcol_stride, k, Dl, pl, acoef, Mb, Sacc, racc,
2197 if constexpr (multiplier_update) {
2198 if constexpr (stores_recovery_for<ny> && !recompute)
2199 store_upper<internal_matrix>(A, A_stride, k, Uf);
2201 register_solve<cols>(Dl, pl, W);
2203 BlockSolver::template forward_inplace_multirhs<cols, true, true, true>(
2204 Dl, 1, pl, 1, W, 1, S);
2205 }
else if constexpr (reg) {
2206 register_solve<cols>(Dl, pl, W);
2207 }
else if constexpr (Config.gather_rhs) {
2209 BlockSolver::template substitute_multirhs<cols, true, true, true>(Dl, 1, pl, 1, W,
2213 BlockSolver::template substitute_inplace_multirhs<cols, true, true, true>(
2214 Dl, 1, pl, 1, W, 1, S);
2221 if constexpr (stores_recovery_for<ny> && !recompute) {
2229 if constexpr (multiplier_update) {
2233 j, 0, cols, T sum = T(0);
2235 schur_sub<ny, internal_rhs, internal_matrix>(
2236 A, A_stride, y, rhs_stride, xcol_stride, Sacc, racc, r, j, sum);))
2237 }
else if constexpr (diag) {
2241 schur_sub<ny, internal_rhs, internal_matrix>(
2242 A, A_stride, y, rhs_stride, xcol_stride, Sacc, racc, i, j,
2243 acoef[i] * W[j * S + i]);))
2248 j, 0, cols, T sum = T(0);
2250 schur_sub<ny, internal_rhs, internal_matrix>(
2251 A, A_stride, y, rhs_stride, xcol_stride, Sacc, racc, r, j, sum);))
2277 template<
int ny,
bool internal_rhs,
bool internal_matrix>
2280 const int rhs_stride,
const std::size_t xcol_stride,
const int k,
2283 constexpr bool forward_check = forward_check_for<ny>;
2284 constexpr int wsave = forward_check ? (B + ny) * S : 1;
2288 if constexpr (forward_check) {
2293 if (condense_streamed<ny, internal_rhs, internal_matrix>(A, A_stride, y, rhs_stride,
2294 xcol_stride, k, Sacc, racc, blk))
2298 store_block<ny, internal_rhs, internal_matrix>(A, A_stride, y, rhs_stride, xcol_stride, k,
2317 template<
int ny,
bool internal_rhs,
bool internal_matrix>
2320 [[maybe_unused]]
const std::size_t xcol_stride,
const int k,
2322 [[maybe_unused]]
constexpr int ycols = ny == 0 ? 1 : ny;
2327 blk.Dl[col ? j * S + i : i * S + j];)
2331 if constexpr (diag) {
2340 blk.Abk[r * S + i];))
2342 if constexpr (ny == 1) {
2346#if defined(TDLS_DETAIL_COMPILER_GCC)
2347#pragma GCC diagnostic pop
2358 template<
bool keep_u>
2362 const T u = condensation_pivot_threshold;
2367 ok = ok && u * detail::abs(Dl[p * S + j]) <= T(1);
2368 }
else if constexpr (keep_u) { U[l * S + j] = Dl[p * S + j]; }))
2388 template<
bool internal_matrix, typename... Streamed>
2390 border_multipliers(const T*
TDLS_RESTRICT A, const
int A_stride, const
int k,
2393 constexpr bool streamed =
sizeof...(Streamed) > 0;
2394 const T u = condensation_pivot_threshold;
2396 if constexpr (col) {
2400 i, 0, S,
if constexpr (streamed) m[i] = streamed_arg(blk...)->W[c * S + i];
2402 multipliers_pass(m, 0, U, u) && ok;)
2403 }
else if constexpr (diag) {
2407 multipliers_pass(m, i, U, u) && ok;)
2408 }
else if constexpr (multiplier_update) {
2411 if constexpr (streamed) Mb[r * S + j] =
2412 streamed_arg(blk...)->Abk[r * S + j];
2415 ok = multipliers_pass(Mb + r * S, 0, U, u) && ok;)
2421 j, 0, S,
if constexpr (streamed) m[j] = streamed_arg(blk...)->Abk[r * S + j];
2423 multipliers_pass(m, 0, U, u) && ok;)
2433#if defined(TDLS_DETAIL_COMPILER_GCC)
2434#pragma GCC diagnostic push
2435#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
2446 magnitude(
const T x)
noexcept {
2447#if defined(__has_builtin)
2448#if __has_builtin(__builtin_is_constant_evaluated)
2449 if (__builtin_is_constant_evaluated())
return x < T(0) ? -x : x;
2451#elif defined(TDLS_DETAIL_COMPILER_MSVC) && _MSC_VER >= 1925
2452 if (__builtin_is_constant_evaluated())
return x < T(0) ? -x : x;
2454 return std::fabs(x);
2466 const T u)
noexcept {
2468 if constexpr (reg) {
2472 l, 0, S,
if (l >= first) {
2473 m[l] *= U[l * S + l];
2474 ok = ok && u * magnitude(m[l]) <= T(1);
2479 ok = ok && u * detail::abs(m[l]) <= T(1);
2493 template<
bool internal_matrix>
2495 store_upper(T*
TDLS_RESTRICT A,
const int A_stride,
const int k,
2497 if constexpr (reg) {
2501 shape_value(), k, l, j)) = U[l * S + j];))
2506 shape_value(), k, l, j)) = U[l * S + j];))
2529 return PhysicalBlockSolver::template physical_factorize_checked<true, true>(
2530 F, 1, p, 1, condensation_pivot_threshold);
2547 template<
int w,
bool backward = !multiplier_update>
2551 PhysicalBlockSolver::template forward_inplace_multirhs<w, true, true, true>(F, 1, p, 1, W,
2553 if constexpr (col || backward)
2554 PhysicalBlockSolver::template backward_inplace_multirhs<w, true, true, true>(F, 1, p, 1,
2558#if defined(TDLS_DETAIL_COMPILER_GCC)
2559#pragma GCC diagnostic pop
2577 template<
int ny,
bool internal_rhs,
bool internal_matrix>
2580 [[maybe_unused]]
const std::size_t xcol_stride, T*
TDLS_RESTRICT Sacc,
2581 T*
TDLS_RESTRICT racc,
const int r,
const int c,
const T v)
noexcept {
2582 [[maybe_unused]]
constexpr int ycols = ny;
2583 if constexpr (in_place) {
2590 Sacc[r * B + c] -= v;
2592 racc[(ny == 1 ? 0 : c - B) * R + r] -= v;
2626 template<
int c0,
bool solved,
int ny,
bool internal_rhs,
bool internal_matrix,
2627 bool recompute =
false,
typename... Streamed>
2630 [[maybe_unused]]
const std::size_t xcol_stride,
const int k,
2635 constexpr bool streamed =
sizeof...(Streamed) > 0;
2636 constexpr int cols = B + ny;
2637 constexpr int w = cols - c0 < pass_width_for<ny> ? cols - c0 : pass_width_for<ny>;
2638 [[maybe_unused]]
constexpr int ycols = ny;
2639 T Wl[
solved ? 1 : w * S];
2640 T* W =
solved ? Wsolved : Wl;
2642 if constexpr (streamed) {
2647 W[j * S + i] = streamed_arg(blk...)->W[(c0 + j) * S + i];))
2654 shape_value(), k, i, c0 + j))
2657 if constexpr (reg) {
2658 register_solve<w>(Dl, pl, W);
2659 }
else if constexpr (multiplier_update) {
2660 BlockSolver::template forward_inplace_multirhs<w, true, true, true>(Dl, 1, pl, 1, W,
2662 }
else if constexpr (Config.gather_rhs) {
2664 BlockSolver::template substitute_multirhs<w, true, true, true>(Dl, 1, pl, 1, W, X,
2668 BlockSolver::template substitute_inplace_multirhs<w, true, true, true>(Dl, 1, pl, 1,
2672 if constexpr (stores_recovery_for<ny> && !recompute) {
2681 if constexpr (multiplier_update) {
2685 j, 0, w, T sum = T(0);
2687 schur_sub<ny, internal_rhs, internal_matrix>(
2688 A, A_stride, y, rhs_stride, xcol_stride, Sacc, racc, r, c0 + j, sum);))
2689 }
else if constexpr (diag) {
2693 schur_sub<ny, internal_rhs, internal_matrix>(
2694 A, A_stride, y, rhs_stride, xcol_stride, Sacc, racc, i,
2695 c0 + j, acoef[i] * W[j * S + i]);))
2699 i, 0, S,
if constexpr (streamed) a[i] = streamed_arg(blk...)->Abk[r * S + i];
2703 schur_sub<ny, internal_rhs, internal_matrix>(
2704 A, A_stride, y, rhs_stride, xcol_stride, Sacc, racc,
2707 if constexpr (c0 + w < cols)
2708 condense_pass<c0 + w, false, ny, internal_rhs, internal_matrix, recompute>(
2709 A, A_stride, y, rhs_stride, xcol_stride, k, Dl, pl, acoef, Mb, Sacc, racc,
nullptr,
2733 template<
int nc,
bool internal_rhs,
bool internal_work,
bool internal_matrix>
2736 const int work_stride, T*
TDLS_RESTRICT y,
const int rhs_stride,
2737 [[maybe_unused]]
const std::size_t xcol_stride,
const unsigned*
TDLS_RESTRICT refused,
2739 constexpr int fcols = front_cols_for<nc>;
2740 [[maybe_unused]]
constexpr int ycols = nc;
2744 for (
int k = NB - 1; k >= 0; --k) {
2753 if ((refused[k >> 5] >> (k & 31)) & 1u) {
2762 (k * S + i) * extra_cols + a - S);
2764 if constexpr (diag) {
2779 }
else if constexpr (multiplier_update) {
2785 t, 0, S,
const int l = S - 1 - t;
2787 u, 0, t,
const int j = l + 1 + u;
2839 template<
int nc,
bool canonical,
bool internal_rhs,
bool internal_work,
bool internal_matrix,
2844 const int work_stride_arg, T*
TDLS_RESTRICT y,
const int rhs_stride_arg,
2845 [[maybe_unused]]
const std::size_t xcol_stride,
2847 const T singular_floor)
noexcept {
2848 const int A_stride = detail::stride_or<A_static_stride>(A_stride_arg);
2849 const int work_stride = detail::stride_or<work_static_stride>(work_stride_arg);
2850 const int rhs_stride = detail::stride_or<rhs_static_stride>(rhs_stride_arg);
2851 constexpr int fcols = front_cols_for<nc>;
2852 [[maybe_unused]]
constexpr int ycols = nc;
2854 constexpr int rhs0 = S + B + R;
2855 const T u = condensation_pivot_threshold;
2858 for (
int r = 0; r < B; ++r) {
2859 for (
int c = 0; c < B; ++c)
2861 for (
int a = 0; a < R; ++a)
2863 for (
int m = 0; m < nc; ++m)
2866 for (
int k = 0; k < NB; ++k) {
2867 if (!((refused[k >> 5] >> (k & 31)) & 1u))
continue;
2869 for (
int i = 0; i < S; ++i) {
2870 for (
int j = 0; j < S; ++j)
2873 for (
int c = 0; c < B; ++c)
2876 for (
int a = 0; a < R; ++a)
2878 for (
int m = 0; m < nc; ++m) {
2879 if constexpr (canonical)
2886 for (
int r = 0; r < B; ++r) {
2887 for (
int j = 0; j < S; ++j) {
2889 if constexpr (diag) {
2893 for (
int a = 0; a < B; ++a)
2902 bool block_row[front_rows];
2903 for (
int e = 0; e < front_rows; ++e)
2904 block_row[e] = e < S;
2905 for (
int j = 0; j < S; ++j) {
2906 int pmax = j, pblk = -1;
2907 T vmax = T(0), vblk = T(0);
2908 for (
int e = j; e < front_rows; ++e) {
2914 if (block_row[e] && v > vblk) {
2919 if (!(vmax >= singular_floor))
return false;
2920 const int p = pblk >= 0 && vblk >= u * vmax && vblk >= singular_floor ? pblk : pmax;
2922 for (
int c = j; c < fcols; ++c) {
2927 const bool t = block_row[p];
2928 block_row[p] = block_row[j];
2933 for (
int e = j + 1; e < front_rows; ++e) {
2935 if (l == T(0))
continue;
2936 for (
int c = j + 1; c < fcols; ++c)
2940 if constexpr (!canonical) {
2944 for (
int c = S; c < fcols; ++c) {
2945 for (
int i = S - 1; i >= 0; --i) {
2947 for (
int m = i + 1; m < S; ++m)
2952 for (
int i = 0; i < S; ++i) {
2953 for (
int c = 0; c < B; ++c)
2956 for (
int a = 0; a < R; ++a) {
2964 for (
int m = 0; m < nc; ++m)
2969 for (
int r = 0; r < B; ++r) {
2970 for (
int c = 0; c < B; ++c)
2972 for (
int m = 0; m < nc; ++m)