117 static constexpr bool col = Config.layout == MatrixLayout::ColMajor;
118 static constexpr bool diag = Config.coupling == ArrowheadCoupling::Diagonal;
122 static constexpr bool multiplier_update =
123 !col && !diag && Config.condensation == ArrowheadCondensation::MinFlops;
124 static constexpr bool in_place = Config.schur_in_place;
126 static_assert(Config.condensation_pivot_threshold.is_finite() &&
127 T(Config.condensation_pivot_threshold) >= T(0) &&
128 T(Config.condensation_pivot_threshold) <= T(1),
129 "ArrowheadLUppSolverDynamic: condensation_pivot_threshold must be in [0, 1]");
134 static constexpr T condensation_pivot_threshold = Config.condensation_pivot_threshold;
135 static_assert(Config.rhs_pass_width >= -1,
136 "ArrowheadLUppSolverDynamic: rhs_pass_width must be >= -1");
148 int B, S, NB, R, R0, front_rows, front_cols, extra_cols, pass_width;
157 I extra, Dl, U, W, X, Mb, m, a, acoef, Sacc, racc, Sbb, rb, w, s, refused, block_row, total;
160 using Offsets = OffsetsOf<int>;
164 struct StreamedOffsetsOf {
165 I Abk, Dsave, Wsave, total;
168 using StreamedOffsets = StreamedOffsetsOf<int>;
177 sizes(
const ArrowheadShape& shape,
const int nc,
const int ny)
noexcept {
182 z.R = diag ? z.S : z.B;
183 z.R0 = diag ? shape.coupling_row : 0;
184 z.front_rows = z.S + z.B;
185 z.front_cols = z.S + z.B + z.R + nc;
186 z.extra_cols = z.R > z.S ? z.R - z.S : 0;
187 constexpr RowInterchange interchange = Config.block_row_interchange;
188 constexpr int width = Config.rhs_pass_width;
189 z.reg = detail::arrowhead_register_blocks_here<T>(interchange, z.S);
190 const int pass = detail::arrowhead_rhs_pass_width_here(width, z.reg);
191 z.pass_width = pass == 0 || pass > z.B + ny ? z.B + ny : pass;
203 template<
typename I =
int>
205 offsets(
const ArrowheadShape& shape,
const int nc)
noexcept {
206 const Sizes z = sizes(shape, nc, nc);
208 I e = I(z.front_rows) * z.front_cols;
210 e += I(z.NB) * z.S * z.extra_cols;
216 e += (I(z.B) + nc) * z.S;
218 e += (I(z.B) + nc) * z.S;
255 template<
typename I =
int>
257 streamed_offsets(
const ArrowheadShape& shape,
const int nc)
noexcept {
258 const Sizes z = sizes(shape, nc, nc);
259 StreamedOffsetsOf<I> so{};
260 I e = offsets<I>(shape, nc).total;
262 e += diag ? I(0) : I(z.B) * z.S;
266 e += (I(z.B) + 1) * z.S;
282 const int nrhs = 1) noexcept {
284 streamed_offsets<long long>(shape, nrhs).total < (1LL << 31);
293 return valid(shape) ? offsets(shape, 1).total : 0;
304 const int nrhs)
noexcept {
305 return valid(shape, nrhs) ? offsets(shape, nrhs).total : 0;
316 return valid(shape) ? streamed_offsets(shape, 1).total : 0;
328 return valid(shape, nrhs) ? streamed_offsets(shape, nrhs).total : 0;
337 if (!
valid(shape))
return 0;
338 return shape.block > shape.border ? shape.block : shape.border;
360 const int work_stride, T*
TDLS_RESTRICT y,
const int rhs_stride,
361 int& refused_count)
noexcept {
362 return solve_core<1, false>(shape, 1, A, A_stride, piv, piv_stride, work, work_stride, y,
363 rhs_stride, 0, 0, refused_count);
381 const int work_stride, T*
TDLS_RESTRICT y,
const int rhs_stride)
noexcept {
382 int refused_count = 0;
383 return solve_inplace(shape, A, A_stride, piv, piv_stride, work, work_stride, y, rhs_stride,
409 int& refused_count)
noexcept {
414 const int n = shape.n();
415 for (
int i = 0; i < n; ++i)
417 return solve_inplace(shape, A, A_stride, piv, piv_stride, work, work_stride, x, rhs_stride,
438 const int rhs_stride)
noexcept {
439 int refused_count = 0;
440 return solve(shape, A, A_stride, piv, piv_stride, work, work_stride, b, x, rhs_stride,
471 const int A_stride,
int*
TDLS_RESTRICT piv,
const int piv_stride,
473 const int rhs_stride,
const std::size_t xcol_stride,
474 int& refused_count)
noexcept {
475 return solve_core<0, false>(shape, nrhs, A, A_stride, piv, piv_stride, work, work_stride, y,
476 rhs_stride, xcol_stride, 0, refused_count);
497 const int A_stride,
int*
TDLS_RESTRICT piv,
const int piv_stride,
499 const int rhs_stride,
const std::size_t xcol_stride)
noexcept {
500 int refused_count = 0;
502 y, rhs_stride, xcol_stride, refused_count);
528 const int A_stride,
int*
TDLS_RESTRICT piv,
const int piv_stride,
530 T*
TDLS_RESTRICT x,
const int rhs_stride,
const std::size_t xcol_stride,
531 int& refused_count)
noexcept {
532 if (!
valid(shape, nrhs)) {
536 const int n = shape.n();
537 for (
int m = 0; m < nrhs; ++m)
538 for (
int i = 0; i < n; ++i)
542 x, rhs_stride, xcol_stride, refused_count);
563 const int A_stride,
int*
TDLS_RESTRICT piv,
const int piv_stride,
566 const std::size_t xcol_stride)
noexcept {
567 int refused_count = 0;
568 return solve_multirhs(shape, nrhs, A, A_stride, piv, piv_stride, work, work_stride, b, x,
569 rhs_stride, xcol_stride, refused_count);
597 const int col0, T*
TDLS_RESTRICT x,
const int rhs_stride,
const std::size_t xcol_stride,
598 int& refused_count)
noexcept {
599 return solve_core<0, true>(shape, nrhs, A, A_stride, piv, piv_stride, work, work_stride, x,
600 rhs_stride, xcol_stride, col0, refused_count);
626 const int rhs_stride,
const std::size_t xcol_stride)
noexcept {
627 int refused_count = 0;
629 work_stride, col0, x, rhs_stride, xcol_stride,
653 const int j)
const noexcept {
660 const int c)
const noexcept {
678 const int i)
const noexcept {
731 template<
typename Prov
ider>
734 const int A_stride,
int*
TDLS_RESTRICT piv,
const int piv_stride,
736 const int rhs_stride,
int& refused_count)
noexcept {
737 return solve_core<1, false>(shape, 1, A, A_stride, piv, piv_stride, work, work_stride, y,
738 rhs_stride, 0, 0, refused_count, &provider);
765 template<
typename Prov
ider>
769 const int work_stride,
const int col0, T*
TDLS_RESTRICT x,
const int rhs_stride,
770 const std::size_t xcol_stride,
int& refused_count)
noexcept {
771 return solve_core<0, true>(shape, nrhs, A, A_stride, piv, piv_stride, work, work_stride, x,
772 rhs_stride, xcol_stride, col0, refused_count, &provider);
818 template<
typename Prov
ider,
typename Converged>
821 Provider&& provider, Converged&& converged,
827 const std::size_t xcol_stride,
int& refused_count)
noexcept {
828 if (!
valid(shape, ntan)) {
835 [[maybe_unused]]
constexpr int ycols = 1;
836 constexpr int y_xcol_stride = 0;
837 const Sizes z = sizes(shape, 1, 1);
838 const Offsets o = offsets(shape, ntan);
839 const StreamedOffsets so = streamed_offsets(shape, ntan);
840 const int B = z.B, R = z.R, R0 = z.R0, NB = z.NB;
841 if constexpr (!in_place) {
842 for (
int r = 0; r < R; ++r) {
843 for (
int c = 0; c < B; ++c)
850 for (
int k = 0; k < NB; ++k) {
851 StreamedBlock blk = streamed_block(z, o, so, work, work_stride);
853 const bool ok = condense_or_store_streamed<1, false>(shape, z, o, so, A, A_stride, piv,
854 piv_stride, work, work_stride, y,
855 rhs_stride, y_xcol_stride, k, 1);
857 if (!ok) ++refused_count;
861 const int acc0 = in_place ? B : R0;
862 const int acc1 = in_place ? B : R0 + R;
863 for (
int r = 0; r < acc0; ++r)
864 for (
int c = 0; c < B; ++c)
867 for (
int r = acc0; r < acc1; ++r)
868 for (
int c = 0; c < B; ++c)
871 for (
int r = acc1; r < B; ++r)
872 for (
int c = 0; c < B; ++c)
878 const Sizes zt = sizes(shape, ntan, 0);
879 for (
int m = 0; m < ntan; ++m)
880 for (
int r = 0; r < B; ++r)
884 if (refused_count > 0 &&
885 !second_pass<0, true>(shape, zt, o, A, A_stride, work, work_stride, y, rhs_stride,
886 y_xcol_stride, ntan))
889 piv_stride, rb, work_stride)
891 B, ntan, Sbb, work_stride, piv, piv_stride, rb,
894 for (
int m = 0; m < ntan; ++m)
895 for (
int r = 0; r < B; ++r)
900 for (
int r = 0; r < acc0; ++r)
902 for (
int r = acc0; r < acc1; ++r)
904 for (
int r = acc1; r < B; ++r)
906 if (refused_count > 0 && !second_pass<1, false>(shape, z, o, A, A_stride, work, work_stride,
907 y, rhs_stride, y_xcol_stride, 1))
911 for (
int r = 0; r < B; ++r)
913 recover<1>(shape, z, o, A, A_stride, work, work_stride, y, rhs_stride, y_xcol_stride, 1);
941 constexpr int digits =
942 std::numeric_limits<T>::digits < 62 ? std::numeric_limits<T>::digits : 62;
943 return valid(shape, nrhs) && capacity >= 0 && capacity <= shape.
blocks &&
944 static_cast<long long>(shape.
blocks) <= (1LL << digits) &&
945 recomputed_offsets<long long>(shape, capacity, nrhs).total < (1LL << 31);
962 const int nrhs = 1) noexcept {
964 ? recomputed_offsets(shape, capacity, nrhs).total
1002 template<
typename Prov
ider>
1007 const int work_stride, T*
TDLS_RESTRICT y,
const int rhs_stride,
1008 int& refused_count)
noexcept {
1009 return recomputed_core(shape, capacity, 0, provider, Abb, Abb_stride, piv, piv_stride, work,
1010 work_stride, y, rhs_stride, 0,
nullptr, 1, 0, refused_count);
1054 template<
typename Prov
ider,
typename Converged>
1057 const ArrowheadShape& shape,
const int ntan,
const int capacity, Provider&& provider,
1058 Converged&& converged,
const T*
TDLS_RESTRICT Abb,
const int Abb_stride,
1061 const int x_stride,
const std::size_t xcol_stride,
int& refused_count)
noexcept {
1066 return recomputed_core(shape, capacity, ntan, provider, Abb, Abb_stride, piv, piv_stride,
1067 work, work_stride, y, rhs_stride, col0, x, x_stride, xcol_stride,
1068 refused_count, &converged);
1076 template<
typename I>
1077 struct RecomputedOffsetsOf {
1078 I store, ystore, slots, total;
1081 using RecomputedOffsets = RecomputedOffsetsOf<int>;
1088 store_shape(
const ArrowheadShape& shape,
const int capacity)
noexcept {
1089 return {shape.border, shape.block, capacity, shape.coupling_row};
1100 template<
typename I =
int>
1102 recomputed_offsets(
const ArrowheadShape& shape,
const int capacity,
const int nc)
noexcept {
1103 const ArrowheadShape st = store_shape(shape, capacity);
1104 RecomputedOffsetsOf<I> ro{};
1105 I e = streamed_offsets<I>(st, nc).total;
1109 e += I(shape.border) + I(capacity) * shape.block;
1125 const int Abb_stride,
1126 const int B,
const int r,
1127 const int c)
noexcept {
1128 return Abb[
TDLS_STRIDED(col ? c * B + r : r * B + c, Abb_stride)];
1159 template<
typename Provider,
typename... Converged>
1161 const ArrowheadShape& shape,
const int capacity,
const int ntan, Provider& provider,
1164 const int rhs_stride, [[maybe_unused]]
const int col0, [[maybe_unused]] T*
TDLS_RESTRICT x,
1165 [[maybe_unused]]
const int x_stride, [[maybe_unused]]
const std::size_t xcol_stride,
1166 int& refused_count, Converged*... converged)
noexcept {
1167 static_assert(!in_place,
"ArrowheadLUppSolverDynamic: the recomputed solve accumulates "
1168 "the Schur complement apart (schur_in_place off)");
1170 const int fnc = ntan > 1 ? ntan : 1;
1174 [[maybe_unused]]
constexpr int ycols = 1;
1175 const ArrowheadShape st = store_shape(shape, capacity);
1176 const Sizes z = sizes(shape, 1, 1);
1177 const Offsets o = offsets(st, fnc);
1178 const StreamedOffsets so = streamed_offsets(st, fnc);
1179 const RecomputedOffsets ro = recomputed_offsets(shape, capacity, fnc);
1180 const int B = z.B, S = z.S, R = z.R, R0 = z.R0, NB = z.NB;
1181 for (
int r = 0; r < R; ++r) {
1182 for (
int c = 0; c < B; ++c)
1184 border_entry(Abb, Abb_stride, B, R0 + r, c);
1188 for (
int k = 0; k < NB; ++k) {
1189 RecomputedBlock blk{streamed_block(z, o, so, work, work_stride),
false};
1191 const int verdict = condense_or_keep_recomputed(
1192 shape, z, o, so, ro, capacity, piv, piv_stride, work, work_stride, k, count);
1193 refused_count = count;
1197 for (
int j = 0; j < capacity; ++j)
1199 T*
const store = work +
TDLS_STRIDED(ro.store, work_stride);
1200 T*
const ystore = work +
TDLS_STRIDED(ro.ystore, work_stride);
1201 for (
int r = 0; r < B; ++r) {
1202 const bool acc = r >= R0 && r < R0 + R;
1203 for (
int c = 0; c < B; ++c)
1206 : border_entry(Abb, Abb_stride, B, r, c);
1208 T*
const Sbb = work +
TDLS_STRIDED(o.Sbb, work_stride);
1210 if constexpr (
sizeof...(Converged) > 0) {
1211 if ((*streamed_arg(converged...))()) {
1214 const Sizes zt = sizes(st, fnc, 0);
1215 for (
int m = 0; m < fnc; ++m)
1216 for (
int r = 0; r < B; ++r)
1218 if (count > 0 && !second_pass<0, true>(st, zt, o, store, work_stride, work,
1219 work_stride, ystore, work_stride, 0, fnc))
1222 piv_stride, rb, work_stride)
1224 B, fnc, Sbb, work_stride, piv, piv_stride, rb,
1227 for (
int m = 0; m < fnc; ++m)
1228 for (
int r = 0; r < B; ++r)
1234 for (
int r = 0; r < B; ++r) {
1235 const bool acc = r >= R0 && r < R0 + R;
1239 if (count > 0 && !second_pass<1, false>(st, sizes(st, 1, 1), o, store, work_stride, work,
1240 work_stride, ystore, work_stride, 0, 1))
1247 for (
int k = NB - 1; k >= 0; --k) {
1252 RecomputedBlock blk{streamed_block(z, o, so, work, work_stride),
true};
1255 for (
int i = 0; i < S; ++i) {
1257 for (
int c = 0; c < B; ++c)
1261 for (
int i = 0; i < S; ++i)
1264 (void)physical_factor(z, o, work, work_stride, piv, piv_stride);
1265 physical_solve(z, o, work, work_stride, piv, piv_stride, 1,
true);
1272 for (
int i = 0; i < S; ++i)
1276 recover_refused(shape, st, z, o, ro, work, work_stride, y, rhs_stride, count);
1277 for (
int r = 0; r < B; ++r)
1300 condense_or_keep_recomputed(
const ArrowheadShape& shape,
const Sizes& z,
const Offsets& o,
1301 const StreamedOffsets& so,
const RecomputedOffsets& ro,
1302 const int capacity,
int*
TDLS_RESTRICT piv,
const int piv_stride,
1304 int& count)
noexcept {
1305 const int B = z.B, S = z.S;
1306 const bool forward_check = !z.reg && col && z.pass_width == B + 1;
1307 for (
int e = 0; e < S * S; ++e)
1310 for (
int e = 0; e < (B + 1) * S; ++e)
1312 if (condense<1, false, true>(shape, z, o,
nullptr, 1, piv, piv_stride, work, work_stride,
1313 nullptr, 1, 0, k, 1, &so))
1316 if (count > capacity)
return 2;
1319 const int j = count - 1;
1320 const ArrowheadShape st = store_shape(shape, capacity);
1321 const int ow = forward_check ? so.Wsave : o.W;
1322 for (
int i = 0; i < S; ++i) {
1323 for (
int jj = 0; jj < S; ++jj)
1326 for (
int c = 0; c < B; ++c)
1332 if constexpr (diag) {
1333 for (
int i = 0; i < S; ++i)
1337 for (
int r = 0; r < B; ++r)
1338 for (
int i = 0; i < S; ++i)
1362 recover_refused(
const ArrowheadShape& shape,
const ArrowheadShape& st,
const Sizes& z,
1363 const Offsets& o,
const RecomputedOffsets& ro, T*
TDLS_RESTRICT work,
1364 const int work_stride, T*
TDLS_RESTRICT y,
const int rhs_stride,
1365 const int count)
noexcept {
1367 const int B = z.B, S = z.S, R = z.R;
1368 for (
int a = 0; a < R; ++a)
1370 for (
int j = count - 1; j >= 0; --j) {
1372 for (
int i = 0; i < S; ++i) {
1374 for (
int c = 0; c < B; ++c)
1377 for (
int a = 0; a < R; ++a) {
1385 if constexpr (diag) {
1386 for (
int i = 0; i < S; ++i)
1391 for (
int r = 0; r < B; ++r)
1392 for (
int i = 0; i < S; ++i)
1397 for (
int i = 0; i < S; ++i)
1410 template<
typename P>
1412 streamed_arg(P* p)
noexcept {
1425 streamed_block(
const Sizes& z,
const Offsets& o,
const StreamedOffsets& so,
1427 StreamedBlock blk{};
1430 blk.Abk = work +
TDLS_STRIDED(diag ? o.acoef : so.Abk, work_stride);
1433 blk.stride = work_stride;
1462 template<
int NC,
bool canonical,
typename... Provider>
1464 solve_core(
const ArrowheadShape& shape,
const int nrhs, T*
TDLS_RESTRICT A,
const int A_stride,
1466 const int work_stride, T*
TDLS_RESTRICT y,
const int rhs_stride,
1467 [[maybe_unused]]
const std::size_t xcol_stride, [[maybe_unused]]
const int col0,
1468 int& refused_count, Provider*... provider)
noexcept {
1469 const int nc = NC > 0 ? NC : nrhs;
1470 if (!
valid(shape, nc)) {
1474 const int ny = canonical ? 0 : nc;
1476 [[maybe_unused]]
constexpr int ycols = NC;
1477 const Sizes z = sizes(shape, nc, ny);
1478 const Offsets o = offsets(shape, nc);
1479 const int B = z.B, R = z.R, R0 = z.R0, NB = z.NB;
1480 if constexpr (!in_place) {
1481 for (
int r = 0; r < R; ++r) {
1482 for (
int c = 0; c < B; ++c)
1485 for (
int m = 0; m < ny; ++m)
1490 if constexpr (
sizeof...(Provider) > 0) {
1492 const StreamedOffsets so = streamed_offsets(shape, nc);
1493 for (
int k = 0; k < NB; ++k) {
1494 StreamedBlock blk = streamed_block(z, o, so, work, work_stride);
1495 (*streamed_arg(provider...))(k, blk);
1496 const bool ok = condense_or_store_streamed<NC, canonical>(
1497 shape, z, o, so, A, A_stride, piv, piv_stride, work, work_stride, y, rhs_stride,
1498 xcol_stride, k, nc);
1500 if (!ok) ++refused_count;
1503 for (
int k = 0; k < NB; ++k) {
1505 condense<NC, canonical>(shape, z, o, A, A_stride, piv, piv_stride, work,
1506 work_stride, y, rhs_stride, xcol_stride, k, nc);
1508 if (!ok) ++refused_count;
1516 const int acc0 = in_place ? B : R0;
1517 const int acc1 = in_place ? B : R0 + R;
1518 for (
int r = 0; r < acc0; ++r) {
1519 for (
int c = 0; c < B; ++c)
1522 for (
int m = 0; m < nc; ++m) {
1523 if constexpr (canonical)
1529 for (
int r = acc0; r < acc1; ++r) {
1530 for (
int c = 0; c < B; ++c)
1533 for (
int m = 0; m < nc; ++m) {
1534 if constexpr (canonical)
1541 for (
int r = acc1; r < B; ++r) {
1542 for (
int c = 0; c < B; ++c)
1545 for (
int m = 0; m < nc; ++m) {
1546 if constexpr (canonical)
1552 if (refused_count > 0 &&
1553 !second_pass<NC, canonical>(shape, z, o, A, A_stride, work, work_stride, y, rhs_stride,
1558 work_stride, piv, piv_stride,
1563 B, nc, work +
TDLS_STRIDED(o.Sbb, work_stride), work_stride, piv, piv_stride,
1568 for (
int m = 0; m < nc; ++m)
1569 for (
int r = 0; r < B; ++r) {
1570 if constexpr (canonical)
1576 if constexpr (!canonical)
1577 recover<NC>(shape, z, o, A, A_stride, work, work_stride, y, rhs_stride, xcol_stride,
1610 template<
int NC,
bool canonical,
bool recompute =
false,
typename... Streamed>
1612 condense(
const ArrowheadShape& shape,
const Sizes& z,
const Offsets& o, T*
TDLS_RESTRICT A,
1613 const int A_stride,
int*
TDLS_RESTRICT piv,
const int piv_stride,
1615 [[maybe_unused]]
const std::size_t xcol_stride,
const int k,
1616 [[maybe_unused]]
const int nrhs,
const Streamed*... so)
noexcept {
1617 constexpr bool streamed =
sizeof...(Streamed) > 0;
1618 const int B = z.B, S = z.S;
1620 const int ny = canonical ? 0 : NC > 0 ? NC : nrhs;
1621 [[maybe_unused]]
constexpr int ycols = NC;
1622 const T u = condensation_pivot_threshold;
1627 if constexpr (!streamed) {
1628 for (
int i = 0; i < S; ++i)
1629 for (
int j = 0; j < S; ++j)
1638 const int verdict = physical_factor(z, o, work, work_stride, piv, piv_stride);
1639 if (verdict == 2)
return false;
1644 if constexpr (diag && !streamed) {
1645 for (
int i = 0; i < S; ++i)
1649 const bool forward_check = !z.reg && col && z.pass_width == B + ny;
1653 for (
int l = 0; l < S; ++l)
1654 for (
int j = l; j < S; ++j)
1658 for (
int l = 0; l < S; ++l) {
1660 for (
int j = 0; j < S; ++j) {
1663 }
else if (!forward_check) {
1670 if (forward_check) {
1671 if constexpr (!streamed) {
1672 for (
int i = 0; i < S; ++i) {
1673 for (
int c = 0; c < B; ++c)
1676 for (
int m = 0; m < ny; ++m)
1684 for (
int e = 0; e < B * S; ++e)
1686 if (!ok)
return false;
1689 condense_pass<NC, canonical, recompute>(shape, z, o, A, A_stride, piv, piv_stride, work,
1690 work_stride, y, rhs_stride, xcol_stride, k, 0,
1691 B + ny,
true, so...);
1693 ok = border_multipliers(shape, z, o, A, A_stride, work, work_stride, k, so...) && ok;
1694 if (!ok)
return false;
1696 if constexpr (multiplier_update && !canonical && !recompute) {
1697 for (
int l = 0; l < S; ++l)
1698 for (
int j = l; j < S; ++j)
1702 for (
int c0 = 0; c0 < B + ny; c0 += z.pass_width) {
1703 const int w = B + ny - c0 < z.pass_width ? B + ny - c0 : z.pass_width;
1704 condense_pass<NC, canonical, recompute>(shape, z, o, A, A_stride, piv, piv_stride,
1705 work, work_stride, y, rhs_stride,
1706 xcol_stride, k, c0, w,
false, so...);
1739 template<
int NC,
bool canonical>
1741 const ArrowheadShape& shape,
const Sizes& z,
const Offsets& o,
const StreamedOffsets& so,
1744 [[maybe_unused]]
const std::size_t xcol_stride,
const int k,
const int nrhs)
noexcept {
1745 const int B = z.B, S = z.S;
1746 const int ny = canonical ? 0 : NC > 0 ? NC : nrhs;
1747 [[maybe_unused]]
constexpr int ycols = NC;
1748 const bool forward_check = !z.reg && col && z.pass_width == B + ny;
1749 for (
int e = 0; e < S * S; ++e)
1752 for (
int e = 0; e < (B + ny) * S; ++e)
1754 if (condense<NC, canonical>(shape, z, o, A, A_stride, piv, piv_stride, work, work_stride, y,
1755 rhs_stride, xcol_stride, k, nrhs, &so))
1759 const int ow = forward_check ? so.Wsave : o.W;
1760 for (
int i = 0; i < S; ++i) {
1761 for (
int j = 0; j < S; ++j)
1764 for (
int c = 0; c < B; ++c)
1767 for (
int m = 0; m < ny; ++m)
1770 if constexpr (diag) {
1771 for (
int i = 0; i < S; ++i)
1775 for (
int r = 0; r < B; ++r)
1776 for (
int i = 0; i < S; ++i)
1799 template<
typename... Streamed>
1801 border_multipliers(
const ArrowheadShape& shape,
const Sizes& z,
const Offsets& o,
1803 const int work_stride,
const int k,
const Streamed*... so)
noexcept {
1804 constexpr bool streamed =
sizeof...(Streamed) > 0;
1805 const int B = z.B, S = z.S;
1807 if constexpr (col) {
1808 for (
int c = 0; c < B; ++c) {
1809 for (
int i = 0; i < S; ++i) {
1810 if constexpr (streamed)
1816 ok = multipliers_pass(z, o, work, work_stride, o.m, 0) && ok;
1818 }
else if constexpr (diag) {
1820 for (
int i = 0; i < S; ++i) {
1821 for (
int j = 0; j < S; ++j)
1824 ok = multipliers_pass(z, o, work, work_stride, o.m, i) && ok;
1827 for (
int r = 0; r < B; ++r) {
1828 for (
int j = 0; j < S; ++j) {
1829 if constexpr (streamed)
1836 ok = multipliers_pass(z, o, work, work_stride, o.Mb + r * S, 0) && ok;
1861 physical_factor(
const Sizes& z,
const Offsets& o, T*
TDLS_RESTRICT work,
const int work_stride,
1864 z.S, work +
TDLS_STRIDED(o.Dl, work_stride), work_stride, piv, piv_stride,
1865 condensation_pivot_threshold);
1886 physical_solve(
const Sizes& z,
const Offsets& o, T*
TDLS_RESTRICT work,
const int work_stride,
1887 const int*
TDLS_RESTRICT piv,
const int piv_stride,
const int w,
1888 const bool backward = !multiplier_update)
noexcept {
1895 if (col || backward)
1909 TDLS_HOST_DEVICE static constexpr bool multipliers_pass(
const Sizes& z,
const Offsets& o,
1911 const int work_stride,
const int m,
1912 const int first)
noexcept {
1914 const T u = condensation_pivot_threshold;
1916 for (
int l = first; l < S; ++l) {
1919 for (
int j = l + 1; j < S; ++j)
1943 schur_sub([[maybe_unused]]
const ArrowheadShape& shape,
const Sizes& z,
1944 [[maybe_unused]]
const Offsets& o, [[maybe_unused]] T*
TDLS_RESTRICT A,
1945 [[maybe_unused]]
const int A_stride, [[maybe_unused]] T*
TDLS_RESTRICT work,
1946 [[maybe_unused]]
const int work_stride, [[maybe_unused]] T*
TDLS_RESTRICT y,
1947 [[maybe_unused]]
const int rhs_stride, [[maybe_unused]]
const std::size_t xcol_stride,
1948 const int r,
const int c,
const T v)
noexcept {
1949 [[maybe_unused]]
constexpr int ycols = NC;
1950 if constexpr (in_place) {
1991 template<
int NC,
bool canonical,
bool recompute =
false,
typename... Streamed>
1993 condense_pass(
const ArrowheadShape& shape,
const Sizes& z,
const Offsets& o, T*
TDLS_RESTRICT A,
1994 const int A_stride,
const int*
TDLS_RESTRICT piv,
const int piv_stride,
1996 const int rhs_stride, [[maybe_unused]]
const std::size_t xcol_stride,
const int k,
1997 const int c0,
const int w,
const bool solved,
const Streamed*... so)
noexcept {
1998 constexpr bool streamed =
sizeof...(Streamed) > 0;
1999 [[maybe_unused]]
constexpr int ycols = NC;
2000 const int B = z.B, S = z.S, R = z.R;
2001 const T*
const Dl = work +
TDLS_STRIDED(o.Dl, work_stride);
2004 if constexpr (streamed) {
2010 for (
int i = 0; i < S; ++i)
2011 for (
int j = 0; j < w; ++j)
2015 for (
int i = 0; i < S; ++i)
2016 for (
int j = 0; j < w; ++j)
2023 physical_solve(z, o, work, work_stride, piv, piv_stride, w);
2024 }
else if constexpr (multiplier_update) {
2027 }
else if constexpr (Config.gather_rhs) {
2031 for (
int e = 0; e < w * S; ++e)
2038 if constexpr (!canonical && !recompute) {
2039 for (
int i = 0; i < S; ++i)
2040 for (
int j = 0; j < w; ++j) {
2049 if constexpr (multiplier_update) {
2050 for (
int r = 0; r < R; ++r)
2051 for (
int j = 0; j < w; ++j) {
2053 for (
int l = 0; l < S; ++l)
2056 schur_sub<NC>(shape, z, o, A, A_stride, work, work_stride, y, rhs_stride,
2057 xcol_stride, r, c0 + j, sum);
2059 }
else if constexpr (diag) {
2060 for (
int i = 0; i < S; ++i)
2061 for (
int j = 0; j < w; ++j)
2062 schur_sub<NC>(shape, z, o, A, A_stride, work, work_stride, y, rhs_stride,
2063 xcol_stride, i, c0 + j,
2067 for (
int r = 0; r < B; ++r) {
2068 for (
int i = 0; i < S; ++i) {
2069 if constexpr (streamed)
2076 for (
int j = 0; j < w; ++j) {
2078 for (
int i = 0; i < S; ++i)
2081 schur_sub<NC>(shape, z, o, A, A_stride, work, work_stride, y, rhs_stride,
2082 xcol_stride, r, c0 + j, sum);
2105 recover(
const ArrowheadShape& shape,
const Sizes& z,
const Offsets& o,
const T*
TDLS_RESTRICT A,
2107 const int rhs_stride, [[maybe_unused]]
const std::size_t xcol_stride,
2108 [[maybe_unused]]
const int nrhs)
noexcept {
2109 const int B = z.B, S = z.S, NB = z.NB, R = z.R;
2110 const int nc = NC > 0 ? NC : nrhs;
2111 [[maybe_unused]]
constexpr int ycols = NC;
2113 for (
int e = 0; e < R * nc; ++e)
2115 for (
int k = NB - 1; k >= 0; --k) {
2116 for (
int i = 0; i < S; ++i) {
2117 for (
int m = 0; m < nc; ++m)
2120 for (
int c = 0; c < B; ++c) {
2122 for (
int m = 0; m < nc; ++m)
2129 for (
int i = 0; i < S; ++i)
2130 for (
int a = 0; a < R; ++a) {
2133 o.extra + (k * S + i) * z.extra_cols + a - S);
2134 for (
int m = 0; m < nc; ++m)
2138 if constexpr (diag) {
2139 for (
int i = 0; i < S; ++i) {
2141 for (
int m = 0; m < nc; ++m)
2146 for (
int r = 0; r < B; ++r)
2147 for (
int i = 0; i < S; ++i) {
2149 for (
int m = 0; m < nc; ++m)
2154 }
else if constexpr (multiplier_update) {
2156 for (
int l = S - 1; l >= 0; --l) {
2157 for (
int j = l + 1; j < S; ++j) {
2159 for (
int m = 0; m < nc; ++m)
2164 for (
int m = 0; m < nc; ++m)
2168 for (
int i = 0; i < S; ++i)
2169 for (
int m = 0; m < nc; ++m)
2195 template<
int NC,
bool canonical>
2197 second_pass(
const ArrowheadShape& shape,
const Sizes& z,
const Offsets& o, T*
TDLS_RESTRICT A,
2198 const int A_stride, T*
TDLS_RESTRICT work,
const int work_stride,
2200 [[maybe_unused]]
const std::size_t xcol_stride,
2201 [[maybe_unused]]
const int nrhs)
noexcept {
2202 const int B = z.B, S = z.S, NB = z.NB, R = z.R, R0 = z.R0;
2203 const int front_rows = z.front_rows, front_cols = z.front_cols;
2204 const int nc = NC > 0 ? NC : nrhs;
2205 const int rhs0 = S + B + R;
2206 [[maybe_unused]]
constexpr int ycols = NC;
2207 const T u = condensation_pivot_threshold;
2211 for (
int r = 0; r < B; ++r) {
2212 for (
int c = 0; c < B; ++c)
2214 for (
int a = 0; a < R; ++a)
2216 for (
int m = 0; m < nc; ++m)
2219 for (
int k = 0; k < NB; ++k) {
2221 for (
int i = 0; i < S; ++i) {
2222 for (
int j = 0; j < S; ++j)
2225 for (
int c = 0; c < B; ++c)
2228 for (
int a = 0; a < R; ++a)
2230 for (
int m = 0; m < nc; ++m) {
2231 if constexpr (canonical)
2238 for (
int r = 0; r < B; ++r) {
2239 for (
int j = 0; j < S; ++j) {
2241 if constexpr (diag) {
2245 for (
int a = 0; a < B; ++a)
2252 for (
int e = 0; e < front_rows; ++e)
2254 for (
int j = 0; j < S; ++j) {
2255 int pmax = j, pblk = -1;
2256 T vmax = T(0), vblk = T(0);
2257 for (
int e = j; e < front_rows; ++e) {
2268 if (!(vmax >= singular_floor))
return false;
2269 const int p = pblk >= 0 && vblk >= u * vmax && vblk >= singular_floor ? pblk : pmax;
2271 for (
int c = j; c < front_cols; ++c) {
2282 for (
int e = j + 1; e < front_rows; ++e) {
2284 if (l == T(0))
continue;
2285 for (
int c = j + 1; c < front_cols; ++c)
2289 if constexpr (!canonical) {
2290 for (
int c = S; c < front_cols; ++c) {
2291 for (
int i = S - 1; i >= 0; --i) {
2293 for (
int m = i + 1; m < S; ++m)
2298 for (
int i = 0; i < S; ++i) {
2299 for (
int c = 0; c < B; ++c)
2302 for (
int a = 0; a < R; ++a) {
2310 for (
int m = 0; m < nc; ++m)
2316 for (
int r = 0; r < B; ++r) {
2317 for (
int c = 0; c < B; ++c)
2319 for (
int m = 0; m < nc; ++m)