dspk_ops/spatial/kernels/
car.rs1use cubecl::prelude::*;
2use dspk_core::compute::{element_position, sample_position};
3
4use crate::core::kernels::{load_lanes, store_lanes};
5
6#[cube(launch)]
10pub fn direct_car_kernel<F: Float>(input: &[F], output: &mut [F], num_channels: u32, num_samples: u32) {
11 let sample_idx = sample_position();
12
13 if sample_idx < num_samples {
14 let mut sum = F::new(0.0f32);
15 let mut c = 0u32;
16 while c < num_channels {
17 sum += input[(c * num_samples + sample_idx) as usize];
18 c += 1u32;
19 }
20
21 let avg = sum / F::cast_from(num_channels);
22
23 c = 0u32;
24 while c < num_channels {
25 let idx = (c * num_samples + sample_idx) as usize;
26 output[idx] = input[idx] - avg;
27 c += 1u32;
28 }
29 }
30}
31
32#[cube(launch)]
37pub fn common_median_kernel<F: Float>(
38 input: &[F],
39 output: &mut [F],
40 num_channels: u32,
41 num_samples: u32,
42 #[comptime] max_channels: u32,
43 #[comptime] units: u32,
44) {
45 let s = dspk_core::compute::row_position();
46 if s < num_samples {
47 let unit = UNIT_POS_X;
48 let mut col = Shared::<[F]>::new_slice(comptime!(max_channels as usize));
49 let mut mid = Shared::<[F]>::new_slice(2usize);
50 let mut c = unit;
51 while c < num_channels {
52 col[c as usize] = input[(c * num_samples + s) as usize];
53 c += units;
54 }
55 sync_cube();
56 let k1 = (num_channels - 1u32) / 2u32;
57 let k2 = num_channels / 2u32;
58 c = unit;
59 while c < num_channels {
60 let x = col[c as usize];
61 let mut less = 0u32;
62 let mut equal = 0u32;
63 let mut j = 0u32;
64 while j < num_channels {
65 let y = col[j as usize];
66 if y < x {
67 less += 1u32;
68 }
69 if y == x {
70 equal += 1u32;
71 }
72 j += 1u32;
73 }
74 if k1 >= less && k1 < less + equal {
75 mid[0] = x;
76 }
77 if k2 >= less && k2 < less + equal {
78 mid[1] = x;
79 }
80 c += units;
81 }
82 sync_cube();
83 let median = (mid[0] + mid[1]) * F::new(0.5f32);
84 c = unit;
85 while c < num_channels {
86 output[(c * num_samples + s) as usize] = col[c as usize] - median;
87 c += units;
88 }
89 }
90}
91
92#[cube(launch)]
103pub fn common_median_bitonic_kernel<F: Float>(
104 input: &[F],
105 output: &mut [F],
106 num_channels: u32,
107 num_samples: u32,
108 #[comptime] padded: u32,
109 #[comptime] units: u32,
110) {
111 let s = dspk_core::compute::row_position();
112 let mut col = Shared::<[F]>::new_slice(comptime!(padded as usize));
114 if s < num_samples {
116 let unit = UNIT_POS_X;
117 let mut i = unit;
118 while i < padded {
119 let mut v = F::max_value();
122 if i < num_channels {
123 v = input[(i * num_samples + s) as usize];
124 }
125 col[i as usize] = v;
126 i += units;
127 }
128 sync_cube();
129 let k = RuntimeCell::<u32>::new(2u32);
131 while k.read() <= padded {
132 let kk = k.read();
133 let j = RuntimeCell::<u32>::new(kk / 2u32);
134 while j.read() > 0u32 {
135 let jj = j.read();
136 let mut a_i = unit;
137 while a_i < padded {
138 let b_i = a_i ^ jj;
139 if b_i > a_i {
140 let (a, b) = (col[a_i as usize], col[b_i as usize]);
141 let ascending = (a_i & kk) == 0u32;
142 let swap = if ascending { a > b } else { a < b };
143 if swap {
144 col[a_i as usize] = b;
145 col[b_i as usize] = a;
146 }
147 }
148 a_i += units;
149 }
150 sync_cube();
151 j.store(jj / 2u32);
152 }
153 k.store(kk * 2u32);
154 }
155 let median = (col[((num_channels - 1u32) / 2u32) as usize] + col[(num_channels / 2u32) as usize]) * F::new(0.5f32);
156 let mut c = unit;
157 while c < num_channels {
158 let idx = (c * num_samples + s) as usize;
159 output[idx] = input[idx] - median;
160 c += units;
161 }
162 }
163}
164
165#[cube(launch)]
172pub fn common_median_vector_kernel<F: Float, N: Size>(input: &[Vector<F, N>], output: &mut [Vector<F, N>], num_channels: u32, vectors_per_row: u32) {
173 let v = element_position();
174 if v < vectors_per_row as usize {
175 let row = vectors_per_row as usize;
176 let one = Vector::<u32, N>::new(1u32);
177 let zero = Vector::<u32, N>::new(0u32);
178 let k1 = Vector::<u32, N>::new((num_channels - 1u32) / 2u32);
179 let k2 = Vector::<u32, N>::new(num_channels / 2u32);
180 let mut mid1 = Vector::<F, N>::new(F::new(0.0f32));
181 let mut mid2 = Vector::<F, N>::new(F::new(0.0f32));
182 let mut c = 0u32;
183 while c < num_channels {
184 let x = input[c as usize * row + v];
185 let mut less = zero;
186 let mut equal = zero;
187 let mut j = 0u32;
188 while j < num_channels {
189 let y = input[j as usize * row + v];
190 less += select_many(y.less_than(&x), one, zero);
191 equal += select_many(y.equal(&x), one, zero);
192 j += 1u32;
193 }
194 let upto = less + equal;
195 mid1 = select_many(k1.greater_equal(&less).vec_and(k1.less_than(&upto)), x, mid1);
196 mid2 = select_many(k2.greater_equal(&less).vec_and(k2.less_than(&upto)), x, mid2);
197 c += 1u32;
198 }
199 let median = (mid1 + mid2) * Vector::new(F::new(0.5f32));
200 c = 0u32;
201 while c < num_channels {
202 let idx = c as usize * row + v;
203 output[idx] = input[idx] - median;
204 c += 1u32;
205 }
206 }
207}
208
209#[cube(launch)]
213pub fn direct_car_vector_kernel<F: Float, N: Size>(input: &[Vector<F, N>], output: &mut [Vector<F, N>], num_channels: u32, vectors_per_row: u32) {
214 let v = element_position();
215 if v < vectors_per_row as usize {
216 let row = vectors_per_row as usize;
217 let mut sum = Vector::<F, N>::new(F::new(0.0f32));
218 let mut c = 0u32;
219 while c < num_channels {
220 sum += input[c as usize * row + v];
221 c += 1u32;
222 }
223 let avg = sum / Vector::new(F::cast_from(num_channels));
224 c = 0u32;
225 while c < num_channels {
226 let idx = c as usize * row + v;
227 output[idx] = input[idx] - avg;
228 c += 1u32;
229 }
230 }
231}
232
233#[cube(launch)]
237pub fn common_median_vector_unaligned_kernel<F: Float, N: Size>(input: &[F], output: &mut [F], num_channels: u32, num_samples: u32, num_units: u32) {
238 let v = element_position() as u32;
239 if v < num_units {
240 let n = N::value() as u32;
241 let i = v * n;
242 let valid = u32::min(n, num_samples - i);
243 let one = Vector::<u32, N>::new(1u32);
244 let zero = Vector::<u32, N>::new(0u32);
245 let k1 = Vector::<u32, N>::new((num_channels - 1u32) / 2u32);
246 let k2 = Vector::<u32, N>::new(num_channels / 2u32);
247 let mut mid1 = Vector::<F, N>::new(F::new(0.0f32));
248 let mut mid2 = Vector::<F, N>::new(F::new(0.0f32));
249 let mut c = 0u32;
250 while c < num_channels {
251 let x = load_lanes::<F, N>(input, (c * num_samples + i) as usize, valid);
252 let mut less = zero;
253 let mut equal = zero;
254 let mut j = 0u32;
255 while j < num_channels {
256 let y = load_lanes::<F, N>(input, (j * num_samples + i) as usize, valid);
257 less += select_many(y.less_than(&x), one, zero);
258 equal += select_many(y.equal(&x), one, zero);
259 j += 1u32;
260 }
261 let upto = less + equal;
262 mid1 = select_many(k1.greater_equal(&less).vec_and(k1.less_than(&upto)), x, mid1);
263 mid2 = select_many(k2.greater_equal(&less).vec_and(k2.less_than(&upto)), x, mid2);
264 c += 1u32;
265 }
266 let median = (mid1 + mid2) * Vector::new(F::new(0.5f32));
267 c = 0u32;
268 while c < num_channels {
269 let start = (c * num_samples + i) as usize;
270 store_lanes::<F, N>(output, start, load_lanes::<F, N>(input, start, valid) - median, valid);
271 c += 1u32;
272 }
273 }
274}
275
276#[cube(launch)]
279pub fn direct_car_vector_unaligned_kernel<F: Float, N: Size>(input: &[F], output: &mut [F], num_channels: u32, num_samples: u32, num_units: u32) {
280 let v = element_position() as u32;
281 if v < num_units {
282 let n = N::value() as u32;
283 let i = v * n;
284 let valid = u32::min(n, num_samples - i);
285 let mut sum = Vector::<F, N>::new(F::new(0.0f32));
286 let mut c = 0u32;
287 while c < num_channels {
288 sum += load_lanes::<F, N>(input, (c * num_samples + i) as usize, valid);
289 c += 1u32;
290 }
291 let avg = sum / Vector::new(F::cast_from(num_channels));
292 c = 0u32;
293 while c < num_channels {
294 let start = (c * num_samples + i) as usize;
295 store_lanes::<F, N>(output, start, load_lanes::<F, N>(input, start, valid) - avg, valid);
296 c += 1u32;
297 }
298 }
299}