309 bool active =
true) {
310 const int32_t lane =
static_cast<int32_t
>(partition.get_local_linear_id());
312 const int32_t ls = Pad ? sycl::clamp(l, int32_t(0),
static_cast<int32_t
>(P) - 2) : l;
313 const int32_t ms = Pad ? sycl::clamp(m, int32_t(0),
static_cast<int32_t
>(P) - 1) : m;
317 const auto explicit_ql_step_exp = [&]() {
319 T p0 = select_from_group(partition, diag, ls);
320 T e0 = select_from_group(partition, offdiag, ls);
321 T dlp1 = select_from_group(partition, diag, ls + 1);
324 p0 = active ? p0 : T(0);
325 e0 = active ? e0 : T(1);
326 dlp1 = active ? dlp1 : T(0);
337 mu = internal::wilkinson_shift(dlp1, e0, p0);
339 const T gg = (dlp1 - p0) / (T(2) * e0);
340 const T rr = sycl::hypot(gg, T(1));
341 mu = p0 - e0 / (gg + sycl::copysign(rr, gg));
344 const int32_t nrot = Pad ? lockstep_max(partition, active ? m - l : 0) : m - l;
353 T di = select_from_group(partition, diag, ms);
354 T ei = select_from_group(partition, offdiag, std::max(ms - 1, 0));
355 ei = (ms >= 1) ? ei : T(0);
362 const T diag_snap = diag;
363 const T offdiag_snap = offdiag;
373 const int32_t e_hi_limit = std::min(m, n - 1);
375 qcache.chase_begin(ms);
377 for (int32_t v = 0; v < nrot; ++v) {
378 const int32_t hi = m - v;
379 const int32_t lo = m - v - 1;
380 const bool act = !Pad || (active && v < m - l);
382 const T dj = select_from_group(partition, diag_snap, Pad ? std::max(lo, 0) : lo);
386 const T ej_raw = select_from_group(partition, offdiag_snap, std::max(lo - 1, 0));
387 const T ej = (lo >= 1) ? ej_raw : T(0);
389 const auto upd = [&]() {
391 const T x = act ? eprev : T(1);
392 const T y = act ? bulge : T(0);
394 const auto [c1, s1, r1] =
cta_lartg(x, y);
399 const T e_hi_new = x * c1 - y * sigma;
402 const T di_new = c1 * (c1 * di - ei * sigma) - sigma * (ei * c1 - sigma * dj);
403 const T dj_new = c1 * (c1 * dj + ei * sigma) + sigma * (ei * c1 + sigma * di);
404 const T ei_new = c1 * (c1 * ei + sigma * di) - sigma * (c1 * dj + sigma * ei);
406 const T ej_new = c1 * ej;
407 const T bulge_new = -ej * sigma;
410 eprev = act ? ei_new : eprev;
411 bulge = act ? bulge_new : bulge;
414 return std::array<T, 7>{c1, sigma, di_new, dj_new, ei_new, ej_new, e_hi_new};
418 const T sigma = upd[1];
424 const bool owns_hi = act && (lane == hi);
425 diag = owns_hi ? upd[2] : diag;
426 offdiag = (owns_hi && hi < e_hi_limit) ? upd[6] : offdiag;
431 qcache.template chase_step_masked<-1>(c1, sigma, act);
433 qcache.template chase_step<-1>(c1, sigma);
438 di = act ? upd[3] : di;
439 ei = act ? upd[5] : ei;
440 e_own = act ? upd[4] : e_own;
444 if (active && lane == l) {
448 if (active && l >= 1 && lane == (l - 1)) {
452 if (active) qcache.chase_end(l);
456 explicit_ql_step_exp();
461 const T p0 = select_from_group(partition, diag, l);
462 const T e0 = select_from_group(partition, offdiag, l);
463 const T dlp1 = select_from_group(partition, diag, l + 1);
464 const T dm = select_from_group(partition, diag, m);
476 mu = internal::wilkinson_shift(dlp1, e0, p0);
479 const T gg = (dlp1 - p0) / (T(2) * e0);
480 const T rr = sycl::hypot(gg, T(1));
481 mu = p0 - e0 / (gg + sycl::copysign(rr, gg));
486 qcache.chase_begin(m);
488 for (int32_t i = m; i-- > l;) {
490 const T ei = select_from_group(partition, offdiag, i);
491 const T di = select_from_group(partition, diag, i);
492 const T dip1 = select_from_group(partition, diag, i + 1);
495 const bool do_e_upd = (i != (m - 1)) && ((i + 1) < (n - 1));
497 const auto [c1b, s1b, d_ip1_new_b, r1_out_b] = [&]() {
502 const auto [c1, s1, r1] =
cta_lartg(g, f);
509 const T g2 = dip1 - p;
510 const T r2 = (di - g2) * s1 + T(2) * c1 * (c * ei);
513 const T d_ip1_new = g2 + p;
514 g = c1 * r2 - (c * ei);
518 return std::array{c1, s1, d_ip1_new, rout};
522 const bool owns_ip1 = (lane == (i + 1));
523 diag = owns_ip1 ? d_ip1_new_b : diag;
524 offdiag = (owns_ip1 && do_e_upd) ? r1_out_b : offdiag;
527 qcache.template chase_step<-1>(c1b, -s1b);
533 const T d_l_new_b = p0 - p;
534 const T e_l_new_b = g;
555 const int32_t lane =
static_cast<int32_t
>(partition.get_local_linear_id());
559 int32_t sweep_budget = max_sweeps * n;
563 for (int32_t next_block_begin = 0; next_block_begin < n;) {
564 const int32_t block_begin = next_block_begin;
567 if (block_begin > 0 && lane == (block_begin - 1) && lane < (n - 1)) {
572 deflate(partition, offdiag, diag, n, block_begin, n);
575 const int32_t block_end_candidate =
576 (lane >= block_begin && lane < (n - 1) && offdiag == T(0)) ? lane : (n - 1);
580 next_block_begin = block_end + 1;
583 if (block_end <= block_begin) {
590 if (lane >= block_begin && lane <= block_end) {
591 anorm_cand = sycl::fabs(diag);
593 if (lane >= block_begin && lane < block_end) {
594 anorm_cand = sycl::fmax(anorm_cand, sycl::fabs(offdiag));
599 if (anorm > internal::ssfmax<T>()) {
600 scale = internal::ssfmax<T>() / anorm;
601 }
else if (anorm < internal::ssfmin<T>() && anorm != T(0)) {
602 scale = internal::ssfmin<T>() / anorm;
604 const T inv_scale = T(1) /
scale;
607 if (lane >= block_begin && lane <= block_end) {
610 if (lane >= block_begin && lane < block_end) {
619 const T d_first = sycl::fabs(select_from_group(partition, diag, block_begin));
620 const T d_last = sycl::fabs(select_from_group(partition, diag, block_end));
621 const bool rev = d_last < d_first;
622 reverse_block<P>(partition, diag, offdiag, qcache, block_begin, block_end, rev);
625 for (int32_t l = block_begin; l <= block_end && !failed;) {
626 if (l == block_end) {
631 bool advanced =
false;
632 for (int32_t sweep = 0; sweep < max_sweeps; ++sweep) {
634 deflate(partition, offdiag, diag, n, l, block_end + 1);
637 const int32_t m_candidate = (lane >= l && lane < block_end && offdiag == T(0)) ? lane : block_end;
653 if (sweep_budget <= 0) {
667 reverse_block<P>(partition, diag, offdiag, qcache, block_begin, block_end, rev);
671 if (lane >= block_begin && lane <= block_end) {
674 if (lane >= block_begin && lane < block_end) {
675 offdiag *= inv_scale;
699 const int32_t lane =
static_cast<int32_t
>(partition.get_local_linear_id());
700 int32_t sweep_budget = max_sweeps * n;
701 int32_t next_block_begin = 0;
702 int32_t block_begin = 0;
703 int32_t block_end = 0;
706 int32_t sweeps_at_l = 0;
710 bool need_block =
true;
720 const int32_t bb = next_block_begin;
721 if (bb > 0 && lane == (bb - 1) && lane < (n - 1)) {
724 deflate(partition, offdiag, diag, n, bb, n);
726 partition, (lane >= bb && lane < (n - 1) && offdiag == T(0)) ? lane : (n - 1));
727 next_block_begin = be + 1;
729 if (next_block_begin >= n) {
737 if (lane >= bb && lane <= be) {
738 anorm_cand = sycl::fabs(diag);
740 if (lane >= bb && lane < be) {
741 anorm_cand = sycl::fmax(anorm_cand, sycl::fabs(offdiag));
745 if (anorm > internal::ssfmax<T>()) {
746 scale = internal::ssfmax<T>() / anorm;
747 }
else if (anorm < internal::ssfmin<T>() && anorm != T(0)) {
748 scale = internal::ssfmin<T>() / anorm;
750 inv_scale = T(1) /
scale;
752 if (lane >= bb && lane <= be) {
755 if (lane >= bb && lane < be) {
760 const T d_first = sycl::fabs(select_from_group(partition, diag, bb));
761 const T d_last = sycl::fabs(select_from_group(partition, diag, be));
762 rev = d_last < d_first;
774 bool closing =
false;
775 if (sweeps_at_l >= max_sweeps) {
779 deflate(partition, offdiag, diag, n, l, block_end + 1);
781 partition, (lane >= l && lane < block_end && offdiag == T(0)) ? lane : block_end);
784 }
else if (m == l + 1) {
787 }
else if (sweep_budget <= 0) {
793 closing = failed || l >= block_end;
798 reverse_block<P>(partition, diag, offdiag, qcache, block_begin, block_end, rev);
800 if (lane >= block_begin && lane <= block_end) {
803 if (lane >= block_begin && lane < block_end) {
804 offdiag *= inv_scale;
808 if (failed || next_block_begin >= n) {
817 cta_shift_strategy, cta_update_scheme);
836 const int32_t lane =
static_cast<int32_t
>(partition.get_local_linear_id());
838 int32_t sweep_budget = max_sweeps * n;
839 int32_t next_block_begin = 0;
840 int32_t block_begin = 0;
841 int32_t block_end = 0;
844 int32_t sweeps_at_l = 0;
848 bool need_block =
true;
853 while (lockstep_any(partition, !done)) {
854 while (lockstep_any(partition, !done && !ready)) {
856 const bool opening = !done && !ready && need_block;
857 if (lockstep_any(partition, opening)) {
858 const int32_t bb = opening ? next_block_begin : 0;
859 if (opening && bb > 0 && lane == (bb - 1) && lane < (n - 1)) {
862 deflate(partition, offdiag, diag, n, opening ? bb : n, n);
864 partition, (opening && lane >= bb && lane < (n - 1) && offdiag == T(0)) ? lane : (n - 1));
865 const bool opened = opening && be > bb;
868 if (opened && lane >= bb && lane <= be) {
869 anorm_cand = sycl::fabs(diag);
871 if (opened && lane >= bb && lane < be) {
872 anorm_cand = sycl::fmax(anorm_cand, sycl::fabs(offdiag));
876 if (anorm > internal::ssfmax<T>()) {
877 sc = internal::ssfmax<T>() / anorm;
878 }
else if (anorm < internal::ssfmin<T>() && anorm != T(0)) {
879 sc = internal::ssfmin<T>() / anorm;
881 if (opened && sc != T(1)) {
882 if (lane >= bb && lane <= be) {
885 if (lane >= bb && lane < be) {
890 const T d_first = sycl::fabs(select_from_group(partition, diag, bb));
891 const T d_last = sycl::fabs(select_from_group(partition, diag, be));
892 const bool rv = opened && (d_last < d_first);
896 next_block_begin = opening ? be + 1 : next_block_begin;
904 inv_scale = T(1) / sc;
907 done = done || (opening && !opened && be + 1 >= n);
911 const bool testing = !done && !ready && !need_block;
914 const bool cap = testing && sweeps_at_l >= max_sweeps;
915 const bool active = testing && !cap;
916 if (lockstep_any(partition, active)) {
917 deflate(partition, offdiag, diag, n, active ? l : n, block_end + 1);
919 partition, (active && lane >= l && lane < block_end && offdiag == T(0)) ? lane : block_end);
920 const bool adv1 = active && mm == l;
921 const bool adv2 = active && mm == l + 1;
922 const bool want = active && !adv1 && !adv2;
923 failed = failed || (want && sweep_budget <= 0);
924 m = (want && sweep_budget > 0) ? mm : m;
925 ready = ready || (want && sweep_budget > 0);
927 if (lockstep_any(partition, adv2)) {
928 const int32_t l0 = sycl::clamp(l, int32_t(0),
static_cast<int32_t
>(P) - 2);
931 l += adv1 ? 1 : (adv2 ? 2 : 0);
932 sweeps_at_l = (adv1 || adv2) ? 0 : sweeps_at_l;
934 failed = failed || cap;
937 const bool closing = testing && (l >= block_end || failed);
938 if (lockstep_any(partition, closing)) {
939 reverse_block<P>(partition, diag, offdiag, qcache, block_begin, block_end, closing && rev);
940 if (closing &&
scale != T(1)) {
941 if (lane >= block_begin && lane <= block_end) {
944 if (lane >= block_begin && lane < block_end) {
945 offdiag *= inv_scale;
948 need_block = need_block || closing;
949 done = done || (closing && (failed || next_block_begin >= n));
954 if (lockstep_any(partition, ready)) {
956 cta_shift_strategy, cta_update_scheme, ready);
958 sweep_budget -= ready ? 1 : 0;
959 sweeps_at_l += ready ? 1 : 0;
990 if constexpr (lockstep_spans_subgroup_v<Partition> && P < 32) {
991 if constexpr (batchlas::sgp::kMaskedByDefault) {
992 const auto chunk = make_partition<P, true>(partition.sg);
994 cta_shift_strategy, cta_update_scheme);
997 cta_shift_strategy, cta_update_scheme);
1001 cta_shift_strategy, cta_update_scheme);
1004 cta_shift_strategy, cta_update_scheme);