stedc_merge_kernels.hh
Go to the documentation of this file.
1#pragma once
6#include <sycl/sycl.hpp>
7
8namespace batchlas {
9
11 sycl::group<1> wg;
12 int32_t tid;
13 int32_t bdim;
14
15 inline int32_t lane_id() const {
16 return tid;
17 }
18
19 inline int32_t width() const {
20 return bdim;
21 }
22
23 template <typename T>
24 inline T reduce_product(T value) const {
25 return batchlas::portable::reduce_over_group(wg, value, sycl::multiplies<T>());
26 }
27
28 inline void sync() const {
29 sycl::group_barrier(wg);
30 }
31
32 template <typename T>
33 inline T reduce_sum(T value) const {
34 return batchlas::portable::reduce_over_group(wg, value, sycl::plus<T>());
35 }
36
37 template <typename T>
38 inline T broadcast(T value) const {
40 }
41};
42
43// Löwner rescale. `first`/`stride` select which eigen-indices this reduction group
44// owns: (0, 1) walks every index (WG reference variant), (part_id, parts_per_wg)
45// gives one index per partition with no work-group barrier. Iteration `eid` reads
46// row `eid` of Q (never written here) and writes only v(eid).
47//
48// The product is a (mantissa, exponent) pair, REQUIRED: narrow partitions lengthen
49// each serial product and the naive one leaves float range at n=64. frexp scaling is
50// by exact powers of two, so in-range results are bit-identical to the naive product.
51// evidence: docs/perf/stedc.md#stedc-partition-parallel-rescale-and-normalize
52template <typename T, typename Adapter, typename QBatch, typename VView>
53inline void maybe_rescale_vectors(bool do_rescale,
54 const Adapter& adapter,
55 int32_t first,
56 int32_t stride,
57 int32_t dd,
58 QBatch& Q_bid,
59 const VectorView<T>& d_prob,
60 const VView& v,
61 int32_t bid) {
62 if (!do_rescale) {
63 return;
64 }
65
66 const int32_t lane = adapter.lane_id();
67 const int32_t width = adapter.width();
68
69 // One trip count for every reduction group, work masked: the reductions are sub-group
70 // shuffles, and a partition that left the loop early makes them read garbage.
71 const int32_t iters = (dd + stride - 1) / stride;
72
73 for (int32_t it = 0; it < iters; ++it) {
74 const int32_t eid = first + it * stride;
75 const bool active = (eid < dd);
76 const T Di = active ? d_prob(eid) : T(0);
77 T mant = T(1);
78 int32_t expo = 0;
79 for (int32_t j = lane; active && j < dd; j += width) {
80 const T q_elem = Q_bid(eid, j);
81 T ratio;
82 if (j == eid) {
83 ratio = q_elem;
84 } else {
85 const T denom = Di - d_prob(j);
86 ratio = q_elem / denom;
87 }
88 mant *= ratio;
89 // Renormalize every factor so |mant| stays in [0.5, 1); exact,
90 // since frexp only rescales by a power of two.
91 if (mant != T(0) && sycl::isfinite(mant)) {
92 int e = 0;
93 mant = sycl::frexp(mant, &e);
94 expo += e;
95 }
96 }
97
98 // Each lane's |mant| is in [0.5, 1), so one product over a wide group bottoms out at
99 // 0.5^width (2^-256 at width 256 is zero in float). Reduce 32 lanes per round and
100 // renormalize between rounds: every partial stays >= 2^-33.
101 T mant_all = T(1);
102 int32_t expo_all = adapter.template reduce_sum<int32_t>(expo);
103 for (int32_t r0 = 0; r0 < width; r0 += 32) {
104 const bool mine = lane >= r0 && lane < r0 + 32;
105 mant_all *= adapter.reduce_product(mine ? mant : T(1));
106 if (mant_all != T(0) && sycl::isfinite(mant_all)) {
107 int e = 0;
108 mant_all = sycl::frexp(mant_all, &e);
109 expo_all += e;
110 }
111 }
112
113 if (active && lane == 0) {
114 // mag = sqrt(|mant_all| * 2^expo_all), split so neither the square
115 // root's argument nor its result can leave range.
116 const int32_t half = expo_all >> 1; // floor(expo_all / 2)
117 const int32_t rem = expo_all - 2 * half; // 0 or 1
118 T mag = sycl::sqrt(sycl::fabs(mant_all) * (rem ? T(2) : T(1)));
119 mag = sycl::ldexp(mag, half);
120 const T sgn = (v(eid, bid) >= T(0)) ? T(1) : T(-1);
121 v(eid, bid) = sgn * mag;
122 }
123 adapter.sync();
124 }
125}
126
127
128template <Backend B, typename T>
130 const VectorView<T>& eigenvalues,
131 const VectorView<T>& v,
132 const Span<T>& rho,
133 const Span<int32_t>& n_reduced,
135 const VectorView<T>& temp_lambdas,
136 const StedcParams<T>& params,
137 int32_t* info,
138 int64_t info_nodes_per_item);
139
140template <Backend B, typename T>
142 const VectorView<T>& eigenvalues,
143 const VectorView<T>& v,
144 const Span<T>& rho,
145 const Span<int32_t>& n_reduced,
147 const VectorView<T>& temp_lambdas,
148 const StedcParams<T>& params,
149 int32_t* info,
150 int64_t info_nodes_per_item);
151
152// Merge step (secular solve + eigenvector formation), dispatched on params.merge_variant.
153// eigenvalues – sorted poles D[0..dd-1] per batch item (dd = n_reduced[bid])
154// v – secular vector z (already permuted, squared weights for Legacy path)
155// rho – signed rank-1 update coefficient per batch item
156// n_reduced – number of non-deflated poles per batch item
157// Outputs: Qprime (n×n, identity for deflated columns), temp_lambdas (unsorted),
158// info (per-item status or nullptr; divide the node index by info_nodes_per_item).
159template <Backend B, typename T>
161 const VectorView<T>& eigenvalues,
162 const VectorView<T>& v,
163 const Span<T>& rho,
164 const Span<int32_t>& n_reduced,
166 const VectorView<T>& temp_lambdas,
167 const StedcParams<T>& params,
168 // Per-item status or nullptr; see info_nodes_per_item above.
169 int32_t* info,
170 int64_t info_nodes_per_item);
171
172} // namespace batchlas
Non-owning view of a batch of matrices: the argument type of every entry point.
Definition matrix.hh:485
Non-owning view of a batch of strided vectors: the vector argument type of the entry points.
Definition matrix.hh:1754
All positional dense entry points (blas/functions/*.hh) plus their option-struct spellings.
batchlas::portable:: group broadcast, shuffles and sums for any trivially copyable or complex T.
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...
T group_broadcast(Group g, T x, Id... id)
sycl::group_broadcast for any trivially copyable T. Collective.
The batched containers: Matrix (owning), MatrixView (non-owning), KernelMatrixView (device-side),...
void maybe_rescale_vectors(bool do_rescale, const Adapter &adapter, int32_t first, int32_t stride, int32_t dd, QBatch &Q_bid, const VectorView< T > &d_prob, const VView &v, int32_t bid)
void stedc_merge_fused(Queue &ctx, const VectorView< T > &eigenvalues, const VectorView< T > &v, const Span< T > &rho, const Span< int32_t > &n_reduced, const MatrixView< T, MatrixFormat::Dense > &Qprime, const VectorView< T > &temp_lambdas, const StedcParams< T > &params, int32_t *info, int64_t info_nodes_per_item)
void stedc_merge_fused_cta(Queue &ctx, const VectorView< T > &eigenvalues, const VectorView< T > &v, const Span< T > &rho, const Span< int32_t > &n_reduced, const MatrixView< T, MatrixFormat::Dense > &Qprime, const VectorView< T > &temp_lambdas, const StedcParams< T > &params, int32_t *info, int64_t info_nodes_per_item)
void stedc_merge_dispatch(Queue &ctx, const VectorView< T > &eigenvalues, const VectorView< T > &v, const Span< T > &rho, const Span< int32_t > &n_reduced, const MatrixView< T, MatrixFormat::Dense > &Qprime, const VectorView< T > &temp_lambdas, const StedcParams< T > &params, int32_t *info, int64_t info_nodes_per_item)
Where BatchLAS work runs: a device, a backend, an ordered SYCL queue and a workspace arena.
Non-owning view of size() contiguous elements of type T.
Definition sycl-span.hh:39
Parameters for stedc().