rustymath_kernels/operation/
at.rs1use super::*;
2
3pub fn at(
5 combine: Option<&Kernel>, root: WriteRoot<'_>, values: crate::agreement::Read<'_>, ids: Writes<'_>, checked: bool, settings: Settings, output: &mut Buffer
6) -> Result<(), Error> {
7 let (wanted, n) = (output.dtype(), ids.len());
8 if values.plan.len() != 1 && values.plan.len() != n { return Err(Error::new(Kind::Length, "write values do not match positions")); }
9 let projection = combine.map_or(Projection::AsIs, |k| k.projection(settings));
10 match combine {
11 None => {
12 root.initialize(wanted, checked, Projection::AsIs, output)?;
13 with_dtype!(wanted, T => at_typed::<T>(values, ids, checked, None, output))?;
14 }
15 Some(kernel) => kernel
16 .projected(&[values], None, Seed::Identity, settings, |inputs, _| kernel.write(root, inputs[0], ids, checked, projection, settings, output))?,
17 }
18 finish(output, wanted, crate::domain::Variant { checked, ..crate::domain::Variant::checked(wanted) })
19}
20
21pub(crate) fn at_typed<T: crate::buffer::Cast>(
23 values: crate::agreement::Read<'_>, ids: Writes<'_>, checked: bool,
24 combine: Option<&dyn Fn(&mut [T], crate::gather::Writes<'_>, Arg<'_, T>) -> Option<Kind>>, output: &mut Buffer) -> Result<(), Error> {
25 let out = T::vec_mut(output).expect("write output has its working dtype");
26 let mut scratch = Vec::new();
27 let mut result = Ok(());
28 ids.runs_while(&mut |start, positions| {
29 result = (|| {
30 for (k, positions) in positions.chunks(crate::CHUNK).enumerate() {
31 let start = start + k * crate::CHUNK;
32 let source = values.part::<T>(if values.plan.len() == 1 { 0..1 } else { start..start + positions.len() }, checked, &mut scratch)?;
33 let writes = Writes::Offsets(positions);
34 match combine {
35 None => match source {
36 Arg::One(value) => writes.write(out, &[value], crate::gather::Same), Arg::Many(values) => writes.write(out, values, crate::gather::Same)
37 },
38 Some(combine) => {
39 if let Some(kind) = combine(&mut out[..], writes, source) {
40 return Err(Error::new(kind, "modified write is outside the function's domain"));
41 }
42 }
43 }
44 }
45 Ok(())
46 })();
47 result.is_ok()
48 });
49 result
50}
51
52impl Kernel {
53 fn write(
55 &self, root: WriteRoot<'_>, values: crate::agreement::Read<'_>, ids: Writes<'_>, checked: bool, projection: Projection, settings: Settings,
56 output: &mut Buffer) -> Result<(), Error> {
57 let variant = self.variant;
58 if let Some(fold) = self.fold() {
59 let working = match variant.dtype {
60 DType::Boolean => DType::Integer(Width::U8), DType::Float(FloatWidth::F16) => DType::Float(FloatWidth::F32), dtype => dtype
61 };
62 native_reduction!(fold, variant.dtype, variant.fails_on_overflow(), |R, T| {
63 type S = <R as crate::reduce::Reduction<T>>::Total;
64 if S::DTYPE == variant.dtype || S::DTYPE == working {
65 root.initialize(S::DTYPE, checked, projection, output)?;
66 return at_typed::<S>(
67 values, ids, checked, Some(&|out, writes, items| {
68 writes.combine(out, items, |x, y| {
69 let (value, ok) = <R as crate::reduce::Reduction<T>>::chain(x, y);
70 (value, (!ok && variant.fails_on_overflow()).then_some(Kind::Overflow))
71 })
72 }), output,
73 );
74 }
75 None::<()>
76 });
77 }
78 self.definition.binary(variant, settings, Route::At { root, values, ids, checked, projection }, output)
79 }
80}