group_blas_common.hh
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <array>
5#include <cassert>
6#include <complex>
7#include <tuple>
8#include <type_traits>
9#include <utility>
10
11#include <batchlas/device_limits.hh>
12
16
17#include <sycl/sycl.hpp>
18
20
21/// @addtogroup api_device_blas
22/// @{
23
24/// @brief Which implementation family a device BLAS call may use.
25///
26/// Level-1 operations, `ger` and `trmv` have one implementation and ignore it.
27/// @see @ref design_device_group_blas
28enum class DeviceBlasPolicy {
29 Auto, ///< any eligible path; the sub-group fast paths accept sub-group size 16 or 32
30 Generic, ///< the portable group-reduction path only; never stages through local memory
31 Subgroup16, ///< fast paths only when the actual sub-group size is 16
32 Subgroup32, ///< fast paths only when the actual sub-group size is 32
33};
34
35/// @brief Kind of launch a DeviceBlasLaunchInfo describes.
37 Group, ///< the call receives a `sycl::group` (or `sycl::sub_group`)
38 NdItem1D, ///< the call receives a `sycl::nd_item<1>`
39 NdItem3D, ///< the call receives a `sycl::nd_item<3>` whose dimensions 1 and 2 index output tiles
40};
41
42/// @brief Host-side description of a launch, for the `*_workspace_elements` queries.
43///
44/// A query evaluates the same eligibility predicates as the call, so the
45/// description must match the launch actually made. Build it with
46/// make_group_launch_info(), make_nd_item_1d_launch_info() or
47/// make_nd_item_3d_launch_info().
49 int local_size = 1; ///< work-items per work-group (per sub-group for a sub-group executor)
50 int subgroup_size = 1; ///< sub-group size of the kernel; 1 for DeviceBlasLaunchKind::Group
51 DeviceBlasLaunchKind kind = DeviceBlasLaunchKind::Group; ///< executor the call receives
52};
53
54/// @brief Launch description for a call that receives a `sycl::group`.
55/// @param local_size work-items in the executor; clamped to at least 1
56/// @ingroup api_device_blas_lowlevel
57inline constexpr DeviceBlasLaunchInfo make_group_launch_info(int local_size) {
58 return DeviceBlasLaunchInfo{std::max(1, local_size), 1, DeviceBlasLaunchKind::Group};
59}
60
61/// @brief Launch description for a call that receives a `sycl::nd_item<1>`.
62/// @param local_size work-group size; clamped to at least 1
63/// @param subgroup_size sub-group size the kernel runs with; clamped to at least 1
64/// @ingroup api_device_blas_lowlevel
65inline constexpr DeviceBlasLaunchInfo make_nd_item_1d_launch_info(int local_size, int subgroup_size) {
66 return DeviceBlasLaunchInfo{std::max(1, local_size), std::max(1, subgroup_size), DeviceBlasLaunchKind::NdItem1D};
67}
68
69/// @brief Launch description for a call that receives a `sycl::nd_item<3>` (tiled output).
70/// @param local_size work-group size; the register-tiled paths require 256
71/// @param subgroup_size sub-group size the kernel runs with; clamped to at least 1
72/// @ingroup api_device_blas_lowlevel
73inline constexpr DeviceBlasLaunchInfo make_nd_item_3d_launch_info(int local_size, int subgroup_size) {
74 return DeviceBlasLaunchInfo{std::max(1, local_size), std::max(1, subgroup_size), DeviceBlasLaunchKind::NdItem3D};
75}
76
77/// @brief Operands of a matrix-vector operation: \f$ y := \alpha\,\mathrm{op}(A)\,x + \beta\,y \f$.
78/// @see make_matvec_operand()
79template <typename T>
81 VectorView<T> x{}; ///< input vector
82 VectorView<T> y{}; ///< output vector; read (scaled by `beta`) and overwritten
83 T alpha = T(1); ///< scale of the product
84 T beta = T(0); ///< scale of the input `y`; 0 still reads `y`
85};
86
87/// @brief Operands of a matrix-matrix operation: \f$ C := \alpha\,(\ldots B \ldots) + \beta\,C \f$.
88/// @see make_matmat_operand()
89template <typename T>
91 KernelMatrixView<T, MatrixFormat::Dense> b{}; ///< second input matrix
92 KernelMatrixView<T, MatrixFormat::Dense> c{}; ///< output matrix; read (scaled by `beta`) and overwritten
93 T alpha = T(1); ///< scale of the product
94 T beta = T(0); ///< scale of the input `C`; 0 still reads `C`
95};
96
97/// @brief Operands of a rank-k update: \f$ C := \alpha\,\mathrm{op}(A)\,\mathrm{op}(A)^{T|H} + \beta\,C \f$.
98/// @see make_rankk_operand()
99template <typename T>
101 KernelMatrixView<T, MatrixFormat::Dense> c{}; ///< square output; only the `uplo` triangle is touched
102 T alpha = T(1); ///< scale of the product
103 T beta = T(0); ///< scale of the input `C`; 0 still reads `C`
104};
105
106/// @brief Operands of a rank-1 update: \f$ A := A + \alpha\,x\,y^{T} \f$ (conjugations per call).
107/// @see make_rank1_update_operand()
108template <typename T>
110 VectorView<T> y{}; ///< right vector, length `a.cols()`
111 KernelMatrixView<T, MatrixFormat::Dense> a{}; ///< matrix updated in place
112 T alpha = T(1); ///< scale of the outer product
113};
114
115/// @brief Runtime transpose mode of a matrix-vector operation.
117 Transpose trans = Transpose::NoTrans; ///< op() applied to `A`
118};
119
120/// @brief Compile-time transpose mode of a matrix-vector operation.
121template <Transpose TransV>
123 static constexpr Transpose trans = TransV; ///< op() applied to `A`
124};
125
126/// @brief Runtime transpose modes of a general matrix-matrix product.
128 Transpose trans_a = Transpose::NoTrans; ///< op() applied to `A`
129 Transpose trans_b = Transpose::NoTrans; ///< op() applied to `B`
130};
131
132/// @brief Compile-time transpose modes of a general matrix-matrix product.
133template <Transpose TransAV, Transpose TransBV>
135 static constexpr Transpose trans_a = TransAV; ///< op() applied to `A`
136 static constexpr Transpose trans_b = TransBV; ///< op() applied to `B`
137};
138
139/// @brief Mode of a triangular product (trmv, trmm).
141 Side side = Side::Left; ///< `A` multiplies from the left or the right
142 Uplo uplo = Uplo::Upper; ///< which triangle of `A` is stored
143 Transpose trans = Transpose::NoTrans; ///< op() applied to `A`
144 Diag diag = Diag::NonUnit; ///< Unit: the diagonal is taken as 1 and not read
145};
146
147/// @brief Mode of a symmetric or Hermitian product (symv, hemv, symm).
149 Side side = Side::Left; ///< `A` multiplies from the left or the right
150 Uplo uplo = Uplo::Upper; ///< which triangle of `A` is stored and read
151 bool hermitian = false; ///< mirror with conjugation
152};
153
154/// @brief Conjugation mode of a rank-1 update (ger, geru, gerc).
156 bool conjugate_x = false; ///< use \f$\bar{x}\f$
157 bool conjugate_y = false; ///< use \f$\bar{y}\f$
158};
159
160/// @brief Compile-time conjugation mode of a rank-1 update.
161template <bool ConjugateXV, bool ConjugateYV>
163 static constexpr bool conjugate_x = ConjugateXV; ///< use \f$\bar{x}\f$
164 static constexpr bool conjugate_y = ConjugateYV; ///< use \f$\bar{y}\f$
165};
166
167/// @brief Mode of a symmetric or Hermitian rank-2k update (syr2k, her2k).
169 Uplo uplo = Uplo::Upper; ///< triangle of `C` that is updated
170 Transpose trans = Transpose::NoTrans; ///< NoTrans: \f$A B^{T}\f$; otherwise \f$A^{T} B\f$
171 bool hermitian = false; ///< conjugate transposes and conjugate `alpha` on the second term
172};
173
174/// @brief Mode of a symmetric or Hermitian rank-k update (syrk, herk).
176 Uplo uplo = Uplo::Upper; ///< triangle of `C` that is updated
177 Transpose trans = Transpose::NoTrans; ///< NoTrans: \f$A A^{T}\f$; otherwise \f$A^{T} A\f$
178 bool hermitian = false; ///< use conjugate transposes
179};
180
181/// @brief Builds a MatrixVectorOperand.
182/// @param x input vector
183/// @param y output vector
184/// @param alpha scale of the product
185/// @param beta scale of the input `y`
186/// @ingroup api_device_blas_lowlevel
187template <typename T>
189 const VectorView<T>& y,
190 T alpha = T(1),
191 T beta = T(0)) {
192 return MatrixVectorOperand<T>{x, y, alpha, beta};
193}
194
195/// @brief Builds a MatrixMatrixOperand.
196/// @param b second input matrix
197/// @param c output matrix
198/// @param alpha scale of the product
199/// @param beta scale of the input `C`
200/// @ingroup api_device_blas_lowlevel
201template <typename T>
204 T alpha = T(1),
205 T beta = T(0)) {
206 return MatrixMatrixOperand<T>{b, c, alpha, beta};
207}
208
209/// @brief Builds a RankKOperand.
210/// @param c square output matrix
211/// @param alpha scale of the product
212/// @param beta scale of the input `C`
213/// @ingroup api_device_blas_lowlevel
214template <typename T>
216 T alpha = T(1),
217 T beta = T(0)) {
218 return RankKOperand<T>{c, alpha, beta};
219}
220
221/// @brief Builds a Rank1UpdateOperand.
222/// @param y right vector
223/// @param a matrix updated in place
224/// @param alpha scale of the outer product
225/// @ingroup api_device_blas_lowlevel
226template <typename T>
229 T alpha = T(1)) {
230 return Rank1UpdateOperand<T>{y, a, alpha};
231}
232
233/// @}
234
235namespace detail {
236
237template <typename Item>
238concept NdItemLike = requires(const Item& item) {
239 item.get_group();
240 item.get_sub_group();
241 item.get_local_linear_id();
242 item.get_local_range().size();
243};
244
245template <NdItemLike Item>
246inline constexpr int item_local_linear_id(const Item& item) {
247 return static_cast<int>(item.get_local_linear_id());
248}
249
250template <NdItemLike Item>
251inline constexpr int item_local_linear_range(const Item& item) {
252 return static_cast<int>(item.get_local_range().size());
253}
254
255template <typename T, typename Workspace>
256inline constexpr std::size_t workspace_elements_v = sizeof(Workspace) / sizeof(T);
257
258template <typename Workspace, typename T>
259inline constexpr Workspace* workspace_ptr_cast(T* workspace) {
260 static_assert(sizeof(Workspace) % sizeof(T) == 0);
261 return reinterpret_cast<Workspace*>(workspace);
262}
263
264template <typename Group, typename T>
265inline constexpr T reduce_sum_group(const Group& group, const T& value) {
266 if constexpr (ComplexScalar<T>) {
267 using Real = typename T::value_type;
268 const Real re = batchlas::portable::reduce_over_group(group, value.real(), sycl::plus<Real>());
269 const Real im = batchlas::portable::reduce_over_group(group, value.imag(), sycl::plus<Real>());
270 return T(re, im);
271 } else {
272 return batchlas::portable::reduce_over_group(group, value, sycl::plus<T>());
273 }
274}
275
276template <NdItemLike Item, typename T>
277inline constexpr T reduce_sum_group(const Item& item, const T& value) {
278 return reduce_sum_group(item.get_group(), value);
279}
280
281template <typename T>
282inline constexpr T conj(const T& value) {
283 if constexpr (ComplexScalar<T>) {
284 return std::conj(value);
285 } else {
286 return value;
287 }
288}
289
290template <typename Group>
291inline constexpr int group_local_linear_id(const Group& group) {
292 return static_cast<int>(group.get_local_linear_id());
293}
294
295template <NdItemLike Item>
296inline constexpr int group_local_linear_id(const Item& item) {
297 return item_local_linear_id(item);
298}
299
300template <typename Group>
301inline constexpr int group_local_linear_range(const Group& group) {
302 return static_cast<int>(group.get_local_range().size());
303}
304
305template <NdItemLike Item>
306inline constexpr int group_local_linear_range(const Item& item) {
307 return item_local_linear_range(item);
308}
309
310inline constexpr int group_local_linear_range(const DeviceBlasLaunchInfo& launch) {
311 return std::max(1, launch.local_size);
312}
313
314template <typename Group>
315inline constexpr bool group_is_leader(const Group& group) {
316 return group_local_linear_id(group) == 0;
317}
318
319template <typename T, typename Op>
320concept MatrixVectorOperandFor = std::same_as<std::remove_cvref_t<Op>, MatrixVectorOperand<T>>;
321
322template <typename T, typename Op>
323concept MatrixMatrixOperandFor = std::same_as<std::remove_cvref_t<Op>, MatrixMatrixOperand<T>>;
324
325template <typename T, typename Op>
326concept VectorOperandFor = std::same_as<std::remove_cvref_t<Op>, VectorView<T>>;
327
328template <typename T>
329inline constexpr T maybe_conjugate(const T& value, bool conjugate) {
330 return conjugate ? conj(value) : value;
331}
332
333template <typename T>
334inline constexpr bool views_overlap(const VectorView<T>& lhs,
335 const VectorView<T>& rhs) {
336 if (lhs.size() <= 0 || rhs.size() <= 0) {
337 return false;
338 }
339
340 auto* lhs_begin = lhs.data_ptr();
341 auto* lhs_end = lhs_begin + (lhs.size() - 1) * lhs.inc();
342 if (lhs_end < lhs_begin) {
343 std::swap(lhs_begin, lhs_end);
344 }
345
346 auto* rhs_begin = rhs.data_ptr();
347 auto* rhs_end = rhs_begin + (rhs.size() - 1) * rhs.inc();
348 if (rhs_end < rhs_begin) {
349 std::swap(rhs_begin, rhs_end);
350 }
351
352 return !(lhs_end < rhs_begin || rhs_end < lhs_begin);
353}
354
355template <typename T>
358 if (lhs.rows() <= 0 || lhs.cols() <= 0 || rhs.rows() <= 0 || rhs.cols() <= 0) {
359 return false;
360 }
361
362 auto* lhs_begin = lhs.data();
363 auto* lhs_end = lhs_begin + (lhs.cols() - 1) * lhs.ld() + (lhs.rows() - 1);
364 if (lhs_end < lhs_begin) {
365 std::swap(lhs_begin, lhs_end);
366 }
367
368 auto* rhs_begin = rhs.data();
369 auto* rhs_end = rhs_begin + (rhs.cols() - 1) * rhs.ld() + (rhs.rows() - 1);
370 if (rhs_end < rhs_begin) {
371 std::swap(rhs_begin, rhs_end);
372 }
373
374 return !(lhs_end < rhs_begin || rhs_end < lhs_begin);
375}
376
377template <typename T>
379 int row,
380 int col,
381 Transpose trans) {
382 if (trans == Transpose::NoTrans) {
383 return a(row, col);
384 }
385 if (trans == Transpose::Trans) {
386 return a(col, row);
387 }
388 return conj(a(col, row));
389}
390
391template <Transpose TransV, typename T>
393 int row,
394 int col) {
395 if constexpr (TransV == Transpose::NoTrans) {
396 return a(row, col);
397 } else if constexpr (TransV == Transpose::Trans) {
398 return a(col, row);
399 } else {
400 return conj(a(col, row));
401 }
402}
403
404template <typename T>
405inline constexpr int input_size(const KernelMatrixView<T, MatrixFormat::Dense>& a, Transpose trans) {
406 return trans == Transpose::NoTrans ? a.cols() : a.rows();
407}
408
409inline constexpr int input_size(int rows, int cols, Transpose trans) {
410 return trans == Transpose::NoTrans ? cols : rows;
411}
412
413template <Transpose TransV, typename T>
415 if constexpr (TransV == Transpose::NoTrans) {
416 return a.cols();
417 } else {
418 return a.rows();
419 }
420}
421
422template <typename T>
424 return trans == Transpose::NoTrans ? a.rows() : a.cols();
425}
426
427inline constexpr int output_size(int rows, int cols, Transpose trans) {
428 return trans == Transpose::NoTrans ? rows : cols;
429}
430
431template <Transpose TransV, typename T>
433 if constexpr (TransV == Transpose::NoTrans) {
434 return a.rows();
435 } else {
436 return a.cols();
437 }
438}
439
440template <typename T>
442 Transpose trans) {
443 (void)trans;
444 assert(a.batch_size() == 1 && "device BLAS expects a single logical matrix; pass batch_item() for batched data");
445}
446
447template <typename T>
449 const MatrixVectorOperand<T>& operand,
450 Transpose trans) {
451 validate_single_problem(a, trans);
452 assert(operand.x.batch_size() == 1 && "device::gemv expects a single logical input vector; pass batch_item() for batched data");
453 assert(operand.y.batch_size() == 1 && "device::gemv expects a single logical output vector; pass batch_item() for batched data");
454 assert(operand.x.size() >= input_size(a, trans) && "device::gemv input vector is too small for the requested transpose mode");
455 assert(operand.y.size() >= output_size(a, trans) && "device::gemv output vector is too small for the requested transpose mode");
456}
457
458template <typename T>
460 const MatrixMatrixOperand<T>& operand,
461 GeneralMatrixTransform transform) {
462 validate_single_problem(a, transform.trans_a);
463 assert(operand.b.batch_size() == 1 && "device::gemm expects a single logical input matrix; pass batch_item() for batched data");
464 assert(operand.c.batch_size() == 1 && "device::gemm expects a single logical output matrix; pass batch_item() for batched data");
465
466 const int m = output_size(a, transform.trans_a);
467 const int k = input_size(a, transform.trans_a);
468 const int b_rows = output_size(operand.b, transform.trans_b);
469 const int n = input_size(operand.b, transform.trans_b);
470
471 assert(b_rows == k && "device::gemm operand contract dimension mismatch");
472 assert(operand.c.rows() == m && "device::gemm output matrix row count does not match op(A)");
473 assert(operand.c.cols() == n && "device::gemm output matrix column count does not match op(B)");
474}
475
476template <typename T>
478 const MatrixVectorOperand<T>& operand,
479 TriangularTransform transform) {
480 validate_single_problem(a, transform.trans);
481 assert(transform.side == Side::Left && "device::trmv currently supports only Side::Left");
482 assert(a.rows() == a.cols() && "device::trmv expects a square triangular matrix");
483 assert(operand.x.batch_size() == 1 && "device::trmv expects a single logical input vector; pass batch_item() for batched data");
484 assert(operand.y.batch_size() == 1 && "device::trmv expects a single logical output vector; pass batch_item() for batched data");
485 assert(operand.x.size() >= a.rows() && "device::trmv input vector is too small for the triangular matrix");
486 assert(operand.y.size() >= a.rows() && "device::trmv output vector is too small for the triangular matrix");
487}
488
489template <typename T>
491 const MatrixVectorOperand<T>& operand,
492 SymmetricTransform transform) {
494 assert(transform.side == Side::Left && "device::symv currently supports only Side::Left");
495 assert(a.rows() == a.cols() && "device::symv expects a square symmetric matrix");
496 assert(operand.x.batch_size() == 1 && "device::symv expects a single logical input vector; pass batch_item() for batched data");
497 assert(operand.y.batch_size() == 1 && "device::symv expects a single logical output vector; pass batch_item() for batched data");
498 assert(operand.x.size() >= a.rows() && "device::symv input vector is too small for the symmetric matrix");
499 assert(operand.y.size() >= a.rows() && "device::symv output vector is too small for the symmetric matrix");
500}
501
502template <typename T>
504 const MatrixMatrixOperand<T>& operand,
505 TriangularTransform transform) {
506 validate_single_problem(a, transform.trans);
507 assert(operand.b.batch_size() == 1 && "device::trmm expects a single logical input matrix; pass batch_item() for batched data");
508 assert(operand.c.batch_size() == 1 && "device::trmm expects a single logical output matrix; pass batch_item() for batched data");
509 assert(operand.b.rows() == operand.c.rows() && "device::trmm input and output matrices must have matching row counts");
510 assert(operand.b.cols() == operand.c.cols() && "device::trmm input and output matrices must have matching column counts");
511 assert(a.rows() == a.cols() && "device::trmm expects a square triangular matrix");
512 if (transform.side == Side::Left) {
513 assert(a.rows() == operand.b.rows() && "device::trmm left-side triangular matrix must match input rows");
514 } else {
515 assert(a.rows() == operand.b.cols() && "device::trmm right-side triangular matrix must match input columns");
516 }
517}
518
519template <typename T>
521 const MatrixMatrixOperand<T>& operand,
522 SymmetricTransform transform) {
524 assert(a.rows() == a.cols() && "device::symm expects a square symmetric matrix");
525 assert(operand.b.batch_size() == 1 && "device::symm expects a single logical input matrix; pass batch_item() for batched data");
526 assert(operand.c.batch_size() == 1 && "device::symm expects a single logical output matrix; pass batch_item() for batched data");
527 assert(operand.b.rows() == operand.c.rows() && "device::symm input and output matrices must have matching row counts");
528 assert(operand.b.cols() == operand.c.cols() && "device::symm input and output matrices must have matching column counts");
529 if (transform.side == Side::Left) {
530 assert(a.rows() == operand.b.rows() && "device::symm left-side symmetric matrix must match input rows");
531 } else {
532 assert(a.rows() == operand.b.cols() && "device::symm right-side symmetric matrix must match input columns");
533 }
534}
535
536template <typename T>
537inline constexpr void validate_rank1_operand(const VectorView<T>& x,
538 const Rank1UpdateOperand<T>& operand) {
539 assert(x.batch_size() == 1 && "device::ger expects a single logical input vector; pass batch_item() for batched data");
540 assert(operand.y.batch_size() == 1 && "device::ger expects a single logical input vector; pass batch_item() for batched data");
542 assert(operand.a.rows() == x.size() && "device::ger matrix row count must match x size");
543 assert(operand.a.cols() == operand.y.size() && "device::ger matrix column count must match y size");
544}
545
546template <typename T>
548 const MatrixMatrixOperand<T>& operand,
549 SymmetricRank2kTransform transform) {
550 validate_single_problem(a, transform.trans);
551 assert(operand.b.batch_size() == 1 && "device::syr2k expects a single logical input matrix; pass batch_item() for batched data");
552 assert(operand.c.batch_size() == 1 && "device::syr2k expects a single logical output matrix; pass batch_item() for batched data");
553 assert(a.rows() == operand.b.rows() && "device::syr2k input matrices must have matching row counts");
554 assert(a.cols() == operand.b.cols() && "device::syr2k input matrices must have matching column counts");
555 const int extent = output_size(a, transform.trans);
556 assert(operand.c.rows() == extent && "device::syr2k output matrix row count does not match op(A)");
557 assert(operand.c.cols() == extent && "device::syr2k output matrix column count does not match op(A)");
558}
559
560template <typename T>
562 const RankKOperand<T>& operand,
563 SymmetricRankKTransform transform) {
564 validate_single_problem(a, transform.trans);
565 assert(operand.c.batch_size() == 1 && "device::syrk expects a single logical output matrix; pass batch_item() for batched data");
566 const int extent = output_size(a, transform.trans);
567 assert(operand.c.rows() == extent && "device::syrk output matrix row count does not match op(A)");
568 assert(operand.c.cols() == extent && "device::syrk output matrix column count does not match op(A)");
569}
570
571template <typename T>
572inline constexpr void validate_vector_operand(const VectorView<T>& x,
573 const char* op_name) {
574 (void)op_name;
575 assert(x.batch_size() == 1 && "device vector BLAS expects a single logical vector; pass batch_item() for batched data");
576}
577
578template <typename T>
579inline constexpr void validate_vector_operands(const VectorView<T>& x,
580 const VectorView<T>& y,
581 const char* op_name) {
584 assert(x.size() == y.size() && "device vector BLAS operands must have matching sizes");
585}
586
587template <typename T>
588inline constexpr void validate_vector_operands(const VectorView<T>& x,
589 const VectorView<T>& y,
590 const VectorView<T>& z,
591 const char* op_name) {
594 assert(x.size() == z.size() && "device vector BLAS operands must have matching sizes");
595}
596
597template <typename T, typename... Views>
598 requires(sizeof...(Views) > 0 && (VectorOperandFor<T, Views> && ...))
599inline constexpr void validate_hadamard_operands(const VectorView<T>& z,
600 const char* op_name,
601 const Views&... inputs) {
604 assert(inputs.size() == z.size() && "device hadamard operands must have matching sizes")),
605 ...);
606}
607
608template <Side SideV, Uplo UploV, Transpose TransposeV, Diag DiagV>
610 static constexpr Side side = SideV;
611 static constexpr Uplo uplo = UploV;
612 static constexpr Transpose trans = TransposeV;
613 static constexpr Diag diag = DiagV;
614};
615
616template <Side SideV, Uplo UploV, bool HermitianV>
618 static constexpr Side side = SideV;
619 static constexpr Uplo uplo = UploV;
620 static constexpr bool hermitian = HermitianV;
621};
622
623template <Uplo UploV, Transpose TransposeV, bool HermitianV>
625 static constexpr Uplo uplo = UploV;
626 static constexpr Transpose trans = TransposeV;
627 static constexpr bool hermitian = HermitianV;
628};
629
630template <typename Tag>
631inline constexpr bool triangular_storage_contains(int row, int col) {
632 if constexpr (Tag::uplo == Uplo::Lower) {
633 return row >= col;
634 }
635 return row <= col;
636}
637
638inline constexpr bool triangular_storage_contains(Uplo uplo, int row, int col) {
639 return uplo == Uplo::Lower ? row >= col : row <= col;
640}
641
642template <typename Tag, typename T>
644 int row,
645 int col) {
646 int src_row = row;
647 int src_col = col;
648 if constexpr (Tag::trans != Transpose::NoTrans) {
649 src_row = col;
650 src_col = row;
651 }
652 if constexpr (Tag::diag == Diag::Unit) {
653 if (src_row == src_col) {
654 return T(1);
655 }
656 }
657 if (!triangular_storage_contains<Tag>(src_row, src_col)) {
658 return T(0);
659 }
660
661 T value = a(src_row, src_col);
662 if constexpr (Tag::trans == Transpose::ConjTrans) {
663 value = conj(value);
664 }
665 return value;
666}
667
668template <typename T>
670 int row,
671 int col,
672 TriangularTransform transform) {
673 int src_row = row;
674 int src_col = col;
675 if (transform.trans != Transpose::NoTrans) {
676 src_row = col;
677 src_col = row;
678 }
679 if (src_row == src_col && transform.diag == Diag::Unit) {
680 return T(1);
681 }
682 if (!triangular_storage_contains(transform.uplo, src_row, src_col)) {
683 return T(0);
684 }
685
686 T value = a(src_row, src_col);
687 if (transform.trans == Transpose::ConjTrans) {
688 value = conj(value);
689 }
690 return value;
691}
692
693template <typename Tag, typename T>
695 int row,
696 int col) {
697 if constexpr (Tag::uplo == Uplo::Lower) {
698 if (row >= col) {
699 return a(row, col);
700 }
701 const T value = a(col, row);
702 if constexpr (Tag::hermitian) {
703 return conj(value);
704 }
705 return value;
706 }
707 if (row <= col) {
708 return a(row, col);
709 }
710 const T value = a(col, row);
711 if constexpr (Tag::hermitian) {
712 return conj(value);
713 }
714 return value;
715}
716
717template <typename T>
719 int row,
720 int col,
721 SymmetricTransform transform) {
722 if (transform.uplo == Uplo::Lower) {
723 if (row >= col) {
724 return a(row, col);
725 }
726 const T value = a(col, row);
727 return transform.hermitian ? conj(value) : value;
728 }
729 if (row <= col) {
730 return a(row, col);
731 }
732 const T value = a(col, row);
733 return transform.hermitian ? conj(value) : value;
734}
735
736template <typename T>
737inline constexpr void write_matrix_output(const MatrixMatrixOperand<T>& operand,
738 int row,
739 int col,
740 const T& value) {
741 operand.c(row, col) = operand.alpha * value + operand.beta * operand.c(row, col);
742}
743
744template <typename T>
745inline constexpr void accumulate_rank1_output(const Rank1UpdateOperand<T>& operand,
746 int row,
747 int col,
748 const T& value) {
749 operand.a(row, col) += operand.alpha * value;
750}
751
752template <typename Tag>
753inline constexpr Transpose rank2k_rhs_transform() {
754 if constexpr (Tag::trans == Transpose::NoTrans) {
755 return Tag::hermitian ? Transpose::ConjTrans : Transpose::Trans;
756 }
757 return Transpose::NoTrans;
758}
759
761 if (transform.trans == Transpose::NoTrans) {
763 }
764 return Transpose::NoTrans;
765}
766
767template <typename Tag>
768inline constexpr Transpose rankk_rhs_transform() {
769 if constexpr (Tag::trans == Transpose::NoTrans) {
770 return Tag::hermitian ? Transpose::ConjTrans : Transpose::Trans;
771 }
772 return Transpose::NoTrans;
773}
774
776 if (transform.trans == Transpose::NoTrans) {
778 }
779 return Transpose::NoTrans;
780}
781
782template <typename Tag, typename T>
783inline constexpr T secondary_rank2k_alpha(const T& alpha) {
784 if constexpr (Tag::hermitian) {
785 return conj(alpha);
786 }
787 return alpha;
788}
789
790template <typename T>
791inline constexpr T secondary_rank2k_alpha(const T& alpha, bool hermitian) {
792 return hermitian ? conj(alpha) : alpha;
793}
794
795template <typename T>
797 return SymmetricTransform{
798 .side = transform.side,
799 .uplo = transform.uplo,
800 .hermitian = ComplexScalar<T>,
801 };
802}
803
804template <typename T>
807 .uplo = transform.uplo,
808 .trans = transform.trans,
809 .hermitian = ComplexScalar<T>,
810 };
811}
812
813template <typename T>
816 .uplo = transform.uplo,
817 .trans = transform.trans,
818 .hermitian = ComplexScalar<T>,
819 };
820}
821
822} // namespace detail
823
824} // namespace batchlas::device
Non-owning view of a batch of strided vectors: the vector argument type of the entry points.
Definition matrix.hh:1754
int size() const
Entries per item.
Definition matrix.hh:1837
T * data_ptr() const
Pointer to entry 0 of item 0.
Definition matrix.hh:1836
int batch_size() const
Number of batch items.
Definition matrix.hh:1842
int inc() const
Element distance between entries.
Definition matrix.hh:1839
A std::complex scalar (std::complex<float>, std::complex<double>).
Definition enums.hh:61
Enumerations, scalar traits and scalar concepts shared by every public header.
batchlas::portable:: group broadcast, shuffles and sums for any trivially copyable or complex T.
constexpr Rank1UpdateOperand< T > make_rank1_update_operand(const VectorView< T > &y, const KernelMatrixView< T, MatrixFormat::Dense > &a, T alpha=T(1))
Builds a Rank1UpdateOperand.
constexpr DeviceBlasLaunchInfo make_group_launch_info(int local_size)
Launch description for a call that receives a sycl::group.
constexpr MatrixVectorOperand< T > make_matvec_operand(const VectorView< T > &x, const VectorView< T > &y, T alpha=T(1), T beta=T(0))
Builds a MatrixVectorOperand.
constexpr DeviceBlasLaunchInfo make_nd_item_1d_launch_info(int local_size, int subgroup_size)
Launch description for a call that receives a sycl::nd_item<1>.
constexpr DeviceBlasLaunchInfo make_nd_item_3d_launch_info(int local_size, int subgroup_size)
Launch description for a call that receives a sycl::nd_item<3> (tiled output).
constexpr MatrixMatrixOperand< T > make_matmat_operand(const KernelMatrixView< T, MatrixFormat::Dense > &b, const KernelMatrixView< T, MatrixFormat::Dense > &c, T alpha=T(1), T beta=T(0))
Builds a MatrixMatrixOperand.
constexpr RankKOperand< T > make_rankk_operand(const KernelMatrixView< T, MatrixFormat::Dense > &c, T alpha=T(1), T beta=T(0))
Builds a RankKOperand.
DeviceBlasPolicy
Which implementation family a device BLAS call may use.
DeviceBlasLaunchKind
Kind of launch a DeviceBlasLaunchInfo describes.
@ Subgroup16
fast paths only when the actual sub-group size is 16
@ Auto
any eligible path; the sub-group fast paths accept sub-group size 16 or 32
@ Subgroup32
fast paths only when the actual sub-group size is 32
@ Generic
the portable group-reduction path only; never stages through local memory
@ Group
the call receives a sycl::group (or sycl::sub_group)
@ NdItem1D
the call receives a sycl::nd_item<1>
@ NdItem3D
the call receives a sycl::nd_item<3> whose dimensions 1 and 2 index output tiles
Transpose
The operator op() applied to an operand: op(A) = A, A^T or A^H.
Definition enums.hh:171
Diag
Whether a triangular operand's diagonal is read or assumed to be one.
Definition enums.hh:303
Uplo
Which triangle of a symmetric, Hermitian or triangular operand is referenced.
Definition enums.hh:287
Side
Side on which a special operand multiplies: op(A) * B or B * op(A).
Definition enums.hh:319
@ Trans
op(A) = A^T.
Definition enums.hh:173
@ NoTrans
op(A) = A.
Definition enums.hh:172
@ ConjTrans
op(A) = A^H (the same as Trans for real scalars).
Definition enums.hh:174
@ Unit
The diagonal is taken as 1 and not read.
Definition enums.hh:305
@ NonUnit
The stored diagonal is used.
Definition enums.hh:304
@ Upper
The upper triangle (i <= j).
Definition enums.hh:288
@ Lower
The lower triangle (i >= j).
Definition enums.hh:289
@ Left
The special operand is on the left.
Definition enums.hh:320
T reduce_over_group(Group g, T x, Op op)
sycl::reduce_over_group, also for a std::complex sum; a work-group floating result is exact (see deta...
The batched containers: Matrix (owning), MatrixView (non-owning), KernelMatrixView (device-side),...
constexpr bool views_overlap(const VectorView< T > &lhs, const VectorView< T > &rhs)
constexpr void validate_rank1_operand(const VectorView< T > &x, const Rank1UpdateOperand< T > &operand)
constexpr int output_size(const KernelMatrixView< T, MatrixFormat::Dense > &a, Transpose trans)
constexpr void write_matrix_output(const MatrixMatrixOperand< T > &operand, int row, int col, const T &value)
constexpr Transpose rank2k_rhs_transform()
constexpr void validate_single_problem(const KernelMatrixView< T, MatrixFormat::Dense > &a, Transpose trans)
constexpr int group_local_linear_id(const Group &group)
constexpr SymmetricTransform canonical_hermitian_transform(SymmetricTransform transform)
constexpr void validate_operand(const KernelMatrixView< T, MatrixFormat::Dense > &a, const MatrixVectorOperand< T > &operand, Transpose trans)
constexpr void validate_vector_operands(const VectorView< T > &x, const VectorView< T > &y, const char *op_name)
constexpr int input_size(const KernelMatrixView< T, MatrixFormat::Dense > &a, Transpose trans)
constexpr T triangular_matrix_entry(const KernelMatrixView< T, MatrixFormat::Dense > &a, int row, int col)
constexpr void validate_gemm_operand(const KernelMatrixView< T, MatrixFormat::Dense > &a, const MatrixMatrixOperand< T > &operand, GeneralMatrixTransform transform)
constexpr void accumulate_rank1_output(const Rank1UpdateOperand< T > &operand, int row, int col, const T &value)
constexpr void validate_symmetric_operand(const KernelMatrixView< T, MatrixFormat::Dense > &a, const MatrixVectorOperand< T > &operand, SymmetricTransform transform)
constexpr int group_local_linear_range(const Group &group)
constexpr Workspace * workspace_ptr_cast(T *workspace)
constexpr T maybe_conjugate(const T &value, bool conjugate)
constexpr Transpose rankk_rhs_transform()
constexpr T symmetric_matrix_entry(const KernelMatrixView< T, MatrixFormat::Dense > &a, int row, int col)
constexpr void validate_rank2k_operand(const KernelMatrixView< T, MatrixFormat::Dense > &a, const MatrixMatrixOperand< T > &operand, SymmetricRank2kTransform transform)
constexpr T matrix_entry(const KernelMatrixView< T, MatrixFormat::Dense > &a, int row, int col, Transpose trans)
constexpr T reduce_sum_group(const Group &group, const T &value)
constexpr T conj(const T &value)
constexpr int item_local_linear_id(const Item &item)
constexpr void validate_vector_operand(const VectorView< T > &x, const char *op_name)
constexpr std::size_t workspace_elements_v
constexpr void validate_rankk_operand(const KernelMatrixView< T, MatrixFormat::Dense > &a, const RankKOperand< T > &operand, SymmetricRankKTransform transform)
constexpr void validate_hadamard_operands(const VectorView< T > &z, const char *op_name, const Views &... inputs)
constexpr void validate_triangular_operand(const KernelMatrixView< T, MatrixFormat::Dense > &a, const MatrixVectorOperand< T > &operand, TriangularTransform transform)
constexpr bool triangular_storage_contains(int row, int col)
constexpr bool group_is_leader(const Group &group)
constexpr int item_local_linear_range(const Item &item)
constexpr T secondary_rank2k_alpha(const T &alpha)
constexpr std::string_view op_name(Op o)
Definition no_route.hh:47
Trivially copyable view of a MatrixView for use inside a SYCL kernel.
Definition matrix.hh:145
auto data() const
Base pointer of item 0.
Definition matrix.hh:217
auto batch_size() const
Number of batch items.
Definition matrix.hh:226
auto rows() const
Row count (the capacity on a heterogeneous batch).
Definition matrix.hh:219
auto ld() const
Dense leading dimension, in elements.
Definition matrix.hh:227
auto cols() const
Column count (the capacity on a heterogeneous batch).
Definition matrix.hh:223
Host-side description of a launch, for the *_workspace_elements queries.
DeviceBlasLaunchKind kind
executor the call receives
int subgroup_size
sub-group size of the kernel; 1 for DeviceBlasLaunchKind::Group
int local_size
work-items per work-group (per sub-group for a sub-group executor)
Compile-time transpose modes of a general matrix-matrix product.
static constexpr Transpose trans_a
op() applied to A
static constexpr Transpose trans_b
op() applied to B
Runtime transpose modes of a general matrix-matrix product.
Operands of a matrix-matrix operation: .
KernelMatrixView< T, MatrixFormat::Dense > c
output matrix; read (scaled by beta) and overwritten
T beta
scale of the input C; 0 still reads C
KernelMatrixView< T, MatrixFormat::Dense > b
second input matrix
Operands of a matrix-vector operation: .
T beta
scale of the input y; 0 still reads y
VectorView< T > y
output vector; read (scaled by beta) and overwritten
Compile-time transpose mode of a matrix-vector operation.
static constexpr Transpose trans
op() applied to A
Runtime transpose mode of a matrix-vector operation.
Compile-time conjugation mode of a rank-1 update.
Conjugation mode of a rank-1 update (ger, geru, gerc).
Operands of a rank-1 update: (conjugations per call).
KernelMatrixView< T, MatrixFormat::Dense > a
matrix updated in place
VectorView< T > y
right vector, length a.cols()
Operands of a rank-k update: .
KernelMatrixView< T, MatrixFormat::Dense > c
square output; only the uplo triangle is touched
T beta
scale of the input C; 0 still reads C
Mode of a symmetric or Hermitian rank-2k update (syr2k, her2k).
bool hermitian
conjugate transposes and conjugate alpha on the second term
Uplo uplo
triangle of C that is updated
Mode of a symmetric or Hermitian rank-k update (syrk, herk).
Uplo uplo
triangle of C that is updated
Transpose trans
NoTrans: ; otherwise .
Mode of a symmetric or Hermitian product (symv, hemv, symm).
Uplo uplo
which triangle of A is stored and read
Side side
A multiplies from the left or the right
bool hermitian
mirror with conjugation
Mode of a triangular product (trmv, trmm).
Uplo uplo
which triangle of A is stored
Diag diag
Unit: the diagonal is taken as 1 and not read.
Side side
A multiplies from the left or the right