sytrd_cta_device.hh
Go to the documentation of this file.
1#pragma once
2
3// Device-side CTA SYTRD, shared by sytrd_cta.cc and syev_cta_fused.cc: one definition keeps
4// the fused and partitioned syev numerically identical, so comparing them measures fusion only.
5
8#include <src/kernels/common/sg_partition/sg_partition.hh>
9#include <src/math-helpers.hh>
10
11#include <cstdint>
13
14namespace batchlas {
15
16 // Shuffles, not reduce_over_group: DPC++'s CUDA path cannot reduce floating point over a
17 // chunked partition. The result is replicated in every lane.
18 template <typename T, typename Group>
19 inline T group_reduce_sum_select_from_group(const Group& g, T v) {
20 const uint32_t lanes = static_cast<uint32_t>(g.get_local_linear_range());
21 (void)lanes;
22
23 if constexpr (internal::is_complex<T>::value) {
24 using Real = typename base_type<T>::type;
25 Real re = v.real();
26 Real im = v.imag();
27 for (uint32_t offset = lanes / 2; offset > 0; offset >>= 1) {
28 re += permute_group_by_xor(g, re, offset);
29 im += permute_group_by_xor(g, im, offset);
30 }
31 return T(re, im);
32 } else {
33 for (uint32_t offset = lanes / 2; offset > 0; offset >>= 1) {
34 v += permute_group_by_xor(g, v, offset);
35 }
36 return v;
37 }
38 }
39
40 // DLARFG over a partition: alpha lives in lane alpha_lane, x in the others (inactive lanes
41 // pass 0). Overwrites alpha with beta and x with the scaled v (implicit 1); returns tau.
42 template <typename T, typename Partition>
43 inline T larfg_small(const Partition& part,
44 int32_t len,
45 int32_t lane,
46 int32_t alpha_lane,
47 T& alpha,
48 T& x,
49 bool x_active) {
50 using Real = typename base_type<T>::type;
51
52 const Real xsq = x_active ? internal::abs2_if_complex(x) : Real(0);
53 const Real sumsq = group_reduce_sum_select_from_group(part, xsq);
54 // sumsq is replicated, so every lane computes the scalars instead of serialising on a leader.
55 const Real xnorm = sycl::sqrt(sumsq);
56
57 T tau = T(0);
58
59 const T alpha_leader = select_from_group(part, alpha, static_cast<uint32_t>(alpha_lane));
60
61 T beta_b = alpha_leader;
62 T tau_b = T(0);
63 T scale_b = T(0);
64 if (len > 1) {
65 const auto scalars = internal::larfg(alpha_leader, xnorm, len);
66 beta_b = scalars.beta;
67 tau_b = scalars.tau;
68 scale_b = scalars.scale;
69 }
70
71 tau = tau_b;
72
73 if (lane == alpha_lane) {
74 alpha = beta_b;
75 } else if (x_active && tau != T(0)) {
76 x *= scale_b;
77 }
78
79 return tau;
80 }
81
82 // SYTD2 on the UPPER triangle of a partition-resident P x P tile (column-major, LDA), which
83 // must hold the full Hermitian matrix zero-padded past n; V_local/W_local are length-P
84 // scratch. Leaves {s,d}sytd2 / {c,z}hetd2 packing: d(i) = A[i,i], e(i) = A[i,i+1], reflector
85 // i in rows 0..i-1 of column i+1. Returns this lane's tau(lane) (zero for lane >= n-1).
86 // Step k touches only the leading k x k block, so column k is final once step k has run.
87 template <typename T, int32_t LDA, typename LocalPtr, typename Partition>
88 inline T sytd2_cta_upper_partition(const Partition& part,
89 LocalPtr A_local,
90 LocalPtr V_local,
91 LocalPtr W_local,
92 int32_t n,
93 int32_t lane) {
94 T tau_lane = T(0);
95
96 // Step k annihilates A(0:k-2, k); [x; alpha] is column k, rows 0..k-1.
97 for (int32_t k = n - 1; k >= 1; --k) {
98 const int32_t m = k;
99 const int32_t alpha_row = k - 1;
100 const int32_t col = k;
101
102 const bool in_vec = (lane < m);
103 const bool is_alpha = (lane == alpha_row);
104 const bool x_active = (lane < (m - 1));
105
106 T alpha = T(0);
107 T x = T(0);
108 if (in_vec) {
109 const T a_val = A_local[lane + col * LDA];
110 if (is_alpha) {
111 alpha = a_val;
112 } else {
113 x = a_val;
114 }
115 }
116
117 const T taui = larfg_small<T>(part, m, lane, alpha_row, alpha, x, x_active);
118
119 // Both triangles are written: the rank-2 update below reads the full block.
120 if (x_active) {
121 A_local[lane + col * LDA] = x;
122 A_local[col + lane * LDA] = batchlas::device::detail::conj(x);
123 }
124 if (is_alpha) {
125 A_local[lane + col * LDA] = alpha;
126 A_local[col + lane * LDA] = batchlas::device::detail::conj(alpha);
127 tau_lane = taui;
128 }
129
130 if (taui != T(0)) {
131 const T v_lane = (lane < m)
132 ? ((lane == alpha_row) ? T(1) : A_local[lane + col * LDA])
133 : T(0);
134 V_local[lane] = v_lane;
135 group_barrier(part);
136
137 // Temporarily set A(alpha_row, col) = 1 (LAPACK convention) for the math.
138 if (is_alpha) {
139 A_local[alpha_row + col * LDA] = T(1);
140 A_local[col + alpha_row * LDA] = T(1);
141 }
142 group_barrier(part);
143
144 // DSYTD2: x = tau*A*v, w = x - (tau/2)(v^H x) v, A -= v w^H + w v^H.
145 T y = T(0);
146 if (lane < m) {
147 for (int32_t c = 0; c < m; ++c) {
148 const T a_rc = A_local[lane + c * LDA];
149 const T v_c = V_local[c];
150 y += a_rc * v_c;
151 }
152 y *= taui;
153 }
154 W_local[lane] = y;
155 group_barrier(part);
156
157 const T dot_lane = (lane < m) ? (batchlas::device::detail::conj(V_local[lane]) * W_local[lane]) : T(0);
158 const T dot = group_reduce_sum_select_from_group(part, dot_lane);
159 const T alpha2 = T(-0.5) * taui * dot;
160
161 if (lane < m) {
162 W_local[lane] = W_local[lane] + alpha2 * V_local[lane];
163 }
164 group_barrier(part);
165
166 if (lane < m) {
167 const T v_r = V_local[lane];
168 const T w_r = W_local[lane];
169 for (int32_t c = 0; c < m; ++c) {
170 const T v_c = V_local[c];
171 const T w_c = W_local[c];
172 const int32_t idx = lane + c * LDA;
173 A_local[idx] = A_local[idx] - (v_r * batchlas::device::detail::conj(w_c) + w_r * batchlas::device::detail::conj(v_c));
174 }
175 }
176 group_barrier(part);
177
178 if (is_alpha) {
179 A_local[alpha_row + col * LDA] = alpha;
180 A_local[col + alpha_row * LDA] = batchlas::device::detail::conj(alpha);
181 }
182 group_barrier(part);
183 } else {
184 if (is_alpha) {
185 A_local[col + alpha_row * LDA] = batchlas::device::detail::conj(alpha);
186 }
187 }
188
189 group_barrier(part);
190 }
191
192 return tau_lane;
193 }
194
195} // namespace batchlas
Leader-only invocation and leader broadcast for SYCL groups and sub-group partitions.
The batched containers: Matrix (owning), MatrixView (non-owning), KernelMatrixView (device-side),...
constexpr T conj(const T &value)
T sytd2_cta_upper_partition(const Partition &part, LocalPtr A_local, LocalPtr V_local, LocalPtr W_local, int32_t n, int32_t lane)
T larfg_small(const Partition &part, int32_t len, int32_t lane, int32_t alpha_lane, T &alpha, T &x, bool x_active)
T group_reduce_sum_select_from_group(const Group &g, T v)
T type
The real type.
Definition enums.hh:30