Automatic Differentiation
 
Loading...
Searching...
No Matches
tridiagonalization.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_GPU_KERNELS_TRIDIAGONALIZATION_HPP
2#define STAN_MATH_GPU_KERNELS_TRIDIAGONALIZATION_HPP
3
4#ifdef STAN_OPENCL
5
7
8namespace stan {
9namespace math {
10namespace opencl_kernels {
11
12// \cond
13static constexpr const char* tridiagonalization_householder_kernel_code
14 = STRINGIFY(
15 // \endcond
28 __global double* P, __global double* V, __global double* q_glob,
29 const int P_rows, const int V_rows, const int j, const int k) {
30 const int lid = get_local_id(0);
31 const int gid = get_global_id(0);
32 const int gsize = get_global_size(0);
33 const int lsize = get_local_size(0);
34 const int ngroups = get_num_groups(0);
35 const int wgid = get_group_id(0);
36
37 double q = 0;
38
39 const int P_start = P_rows * (k + j) + k + j;
40 const int P_span = P_rows * (k + j + 1) - P_start;
41 for (int i = lid; i < P_span; i += lsize) {
42 double acc = 0;
43 // apply previous householder reflections from current block to the
44 // column we are making the Householder vector from
45 for (int l = 0; l < j; l++) {
46 acc += P[P_rows * (k + l) + k + j + i] * V[V_rows * l + j - 1]
47 + V[V_rows * l + j - 1 + i] * P[P_rows * (k + l) + k + j];
48 }
49 double tmp = P[P_start + i] - acc;
50 P[P_start + i] = tmp;
51 if (i != 0) {
52 q += tmp * tmp;
53 }
54 }
55 // calculate column norm between threads
56 __local double q_local[LOCAL_SIZE_];
57 q_local[lid] = q;
58 // Work items below read and write entries of P that other work
59 // items wrote above, so this barrier also fences global memory.
60 barrier(CLK_LOCAL_MEM_FENCE | CLK_GLOBAL_MEM_FENCE);
61 for (int step = lsize / REDUCTION_STEP_SIZE; step > 0;
62 step /= REDUCTION_STEP_SIZE) {
63 if (lid < step) {
64 for (int i = 1; i < REDUCTION_STEP_SIZE; i++) {
65 q_local[lid] += q_local[lid + step * i];
66 }
67 }
68 barrier(CLK_LOCAL_MEM_FENCE);
69 }
70
71 double alpha;
72 if (lid == 0) {
73 q = q_local[0];
74 double p1 = P[P_start + 1];
75 // make Householder vector
76 alpha = -copysign(sqrt(q), P[P_start]);
77 q -= p1 * p1;
78 p1 -= alpha;
79 P[P_start + 1] = p1;
80 q += p1 * p1;
81 q = sqrt(q);
82 q_local[0] = q;
83 q_local[1] = alpha;
84 *q_glob = q;
85 }
86 barrier(CLK_LOCAL_MEM_FENCE);
87 q = q_local[0];
88 alpha = q_local[1];
89 if (q != 0) {
90 double multi = M_SQRT2 / q;
91 // normalize the Householder vector
92 for (int i = lid + 1; i < P_span; i += lsize) {
93 P[P_start + i] *= multi;
94 }
95 }
96 if (gid == 0) {
97 P[P_rows * (k + j + 1) + k + j]
98 = P[P_rows * (k + j) + k + j + 1] * q / M_SQRT2 + alpha;
99 }
100 }); // \cond
101// \endcond
102
103// \cond
104static constexpr const char* tridiagonalization_v_step_1_kernel_code
105 = STRINGIFY(
106 // \endcond
122 const __global double* P, const __global double* V,
123 __global double* Uu, __global double* Vu, const int P_rows,
124 const int V_rows, const int k) {
125 const int lid = get_local_id(0);
126 const int gid = get_global_id(0);
127 const int gsize = get_global_size(0);
128 const int lsize = get_local_size(0);
129 const int ngroups = get_num_groups(0);
130 const int wgid = get_group_id(0);
131
132 __local double res_loc1[LOCAL_SIZE_];
133 __local double res_loc2[LOCAL_SIZE_];
134 double acc1 = 0;
135 double acc2 = 0;
136
137 const __global double* vec
138 = P + P_rows * (k + ngroups) + k + ngroups + 1;
139 const __global double* M1 = P + P_rows * (k + wgid) + k + ngroups + 1;
140 const __global double* M2 = V + V_rows * wgid + ngroups;
141 for (int i = lid; i < P_rows - k - ngroups - 1;
142 i
143 += LOCAL_SIZE_) { // go over column of the matrix in steps of 64
144 double v = vec[i];
145 acc1 += M1[i] * v;
146 acc2 += M2[i] * v;
147 }
148 res_loc1[lid] = acc1;
149 res_loc2[lid] = acc2;
150 barrier(CLK_LOCAL_MEM_FENCE);
151
152 for (int step = lsize / REDUCTION_STEP_SIZE; step > 0;
153 step /= REDUCTION_STEP_SIZE) {
154 if (lid < step) {
155 for (int i = 1; i < REDUCTION_STEP_SIZE; i++) {
156 res_loc1[lid] += res_loc1[lid + step * i];
157 res_loc2[lid] += res_loc2[lid + step * i];
158 }
159 }
160 barrier(CLK_LOCAL_MEM_FENCE);
161 }
162 if (lid == 0) {
163 Uu[wgid] = res_loc1[0];
164 Vu[wgid] = res_loc2[0];
165 }
166 }); // \cond
167// \endcond
168
169// \cond
170static constexpr const char* tridiagonalization_v_step_2_kernel_code
171 = STRINGIFY(
172 // \endcond
190 const __global double* P, __global double* V,
191 const __global double* Uu, const __global double* Vu,
192 const int P_rows, const int V_rows, const int k, const int j) {
193 const int lid = get_local_id(0);
194 const int gid = get_global_id(0);
195 const int gsize = get_global_size(0);
196 const int lsize = get_local_size(0);
197 const int ngroups = get_num_groups(0);
198 const int wgid = get_group_id(0);
199
200 int work = P_rows - k - j - 1;
201 double acc = 0;
202
203 const __global double* vec = P + P_rows * (k + j) + k + j + 1;
204 const __global double* M1 = P + P_rows * (k + j + 1) + k + j + 1;
205 const __global double* M2 = P + P_rows * k + k + j + 1;
206 const __global double* M3 = V + j;
207 int i;
208 if (gid < work) {
209 for (i = 0; i <= gid; i++) {
210 acc += M1[P_rows * i + gid] * vec[i];
211 }
212 for (int i = 0; i < j; i++) {
213 acc -= M2[P_rows * i + gid] * Vu[i];
214 acc -= M3[V_rows * i + gid] * Uu[i];
215 }
216 V[V_rows * j + gid + j] = acc;
217 }
218 float work_per_group
219 = (float)work / ngroups; // NOLINT(readability/casting)
220 int start = work_per_group * wgid;
221 int end = work_per_group * (wgid + 1);
222 __local double res_loc[LOCAL_SIZE_];
223 for (int i = start; i < end; i += 1) {
224 acc = 0;
225 for (int l = i + 1 + lid; l < work; l += LOCAL_SIZE_) {
226 acc += M1[P_rows * i + l] * vec[l];
227 }
228 res_loc[lid] = acc;
229 barrier(CLK_LOCAL_MEM_FENCE);
230 for (int step = lsize / REDUCTION_STEP_SIZE; step > 0;
231 step /= REDUCTION_STEP_SIZE) {
232 if (lid < step) {
233 for (int i = 1; i < REDUCTION_STEP_SIZE; i++) {
234 res_loc[lid] += res_loc[lid + step * i];
235 }
236 }
237 barrier(CLK_LOCAL_MEM_FENCE);
238 }
239 if (lid == 0) {
240 V[V_rows * (j + 1) + i + j] = res_loc[lid];
241 }
242 barrier(CLK_LOCAL_MEM_FENCE);
243 }
244 }); // \cond
245// \endcond
246
247// \cond
248static constexpr const char* tridiagonalization_v_step_3_kernel_code
249 = STRINGIFY(
250 // \endcond
263 __global double* P, __global double* V, __global double* q,
264 const int P_rows, const int V_rows, const int k, const int j) {
265 const int lid = get_local_id(0);
266 const int gid = get_global_id(0);
267 const int gsize = get_global_size(0);
268 const int lsize = get_local_size(0);
269 const int ngroups = get_num_groups(0);
270 const int wgid = get_group_id(0);
271
272 __global double* u = P + P_rows * (k + j) + k + j + 1;
273 __global double* v = V + V_rows * j + j;
274 double acc = 0;
275
276 for (int i = lid; i < P_rows - k - j - 1; i += LOCAL_SIZE_) {
277 double vi = v[i] + v[i + V_rows];
278 v[i] = vi;
279 acc += u[i] * vi;
280 }
281 __local double res_loc[LOCAL_SIZE_];
282 res_loc[lid] = acc;
283 barrier(CLK_LOCAL_MEM_FENCE);
284 for (int step = lsize / REDUCTION_STEP_SIZE; step > 0;
285 step /= REDUCTION_STEP_SIZE) {
286 if (lid < step) {
287 for (int i = 1; i < REDUCTION_STEP_SIZE; i++) {
288 res_loc[lid] += res_loc[lid + step * i];
289 }
290 }
291 barrier(CLK_LOCAL_MEM_FENCE);
292 }
293 acc = res_loc[0] * 0.5;
294 for (int i = lid; i < P_rows - k - j - 1; i += LOCAL_SIZE_) {
295 v[i] -= acc * u[i];
296 }
297 if (gid == 0) {
298 P[P_rows * (k + j + 1) + k + j] -= *q / M_SQRT2 * u[0];
299 }
300 }); // \cond
301// \endcond
302
303const kernel_cl<in_out_buffer, in_out_buffer, out_buffer, int, int, int, int>
304 tridiagonalization_householder("tridiagonalization_householder",
305 {tridiagonalization_householder_kernel_code},
306 {{"REDUCTION_STEP_SIZE", 4},
307 {"LOCAL_SIZE_", 1024}});
308
309const kernel_cl<in_buffer, in_buffer, out_buffer, out_buffer, int, int, int>
310 tridiagonalization_v_step_1("tridiagonalization_v_step_1",
311 {tridiagonalization_v_step_1_kernel_code},
312 {{"REDUCTION_STEP_SIZE", 4},
313 {"LOCAL_SIZE_", 64}});
314
315const kernel_cl<in_buffer, out_buffer, in_buffer, in_buffer, int, int, int, int>
316 tridiagonalization_v_step_2("tridiagonalization_v_step_2",
317 {tridiagonalization_v_step_2_kernel_code},
318 {{"REDUCTION_STEP_SIZE", 4},
319 {"LOCAL_SIZE_", 64}});
320
321const kernel_cl<in_out_buffer, in_out_buffer, out_buffer, int, int, int, int>
322 tridiagonalization_v_step_3("tridiagonalization_v_step_3",
323 {tridiagonalization_v_step_3_kernel_code},
324 {{"REDUCTION_STEP_SIZE", 4},
325 {"LOCAL_SIZE_", 1024}});
326
327} // namespace opencl_kernels
328} // namespace math
329} // namespace stan
330#endif
331#endif
const kernel_cl< in_buffer, in_buffer, out_buffer, out_buffer, int, int, int > tridiagonalization_v_step_1("tridiagonalization_v_step_1", {tridiagonalization_v_step_1_kernel_code}, {{"REDUCTION_STEP_SIZE", 4}, {"LOCAL_SIZE_", 64}})
const kernel_cl< in_buffer, out_buffer, in_buffer, in_buffer, int, int, int, int > tridiagonalization_v_step_2("tridiagonalization_v_step_2", {tridiagonalization_v_step_2_kernel_code}, {{"REDUCTION_STEP_SIZE", 4}, {"LOCAL_SIZE_", 64}})
const kernel_cl< in_out_buffer, in_out_buffer, out_buffer, int, int, int, int > tridiagonalization_v_step_3("tridiagonalization_v_step_3", {tridiagonalization_v_step_3_kernel_code}, {{"REDUCTION_STEP_SIZE", 4}, {"LOCAL_SIZE_", 1024}})
const kernel_cl< in_out_buffer, in_out_buffer, out_buffer, int, int, int, int > tridiagonalization_householder("tridiagonalization_householder", {tridiagonalization_householder_kernel_code}, {{"REDUCTION_STEP_SIZE", 4}, {"LOCAL_SIZE_", 1024}})
T step(const T &y)
The step, or Heaviside, function.
Definition step.hpp:31
fvar< T > sqrt(const fvar< T > &x)
Definition sqrt.hpp:18
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...
#define STRINGIFY(...)
Definition stringify.hpp:9