ruprim/reduce/components/instructions/
min.rs1use ruda_kernel::dsl as kernel_dsl;
2use super::{ReduceFamily, ReduceInstruction};
3use crate::reduce::components::{
4 instructions::{Accumulator, AccumulatorFormat, Item, ReduceRequirements, ReduceStep, Value},
5 precision::ReducePrecision,
6};
7use ruda_kernel::dsl::prelude::*;
8
9#[derive(Debug, RudaType, Clone)]
12pub struct Min;
13
14impl ReduceFamily for Min {
15 type Instruction<P: ReducePrecision> = Self;
16 type Config = ();
17}
18
19#[ruda]
20impl<P: ReducePrecision> ReduceInstruction<P> for Min {
21 type SharedAccumulator = SharedMemory<Vector<P::EA, P::SI>>;
22 type Config = ();
23
24 fn requirements(_this: &Self) -> ReduceRequirements {
25 ReduceRequirements { coordinates: false }
26 }
27
28 fn accumulator_format(_this: &Self) -> comptime_type!(AccumulatorFormat) {
29 AccumulatorFormat::Single
30 }
31
32 fn from_config(_config: Self::Config) -> Self {
33 Min {}
34 }
35
36 fn null_input(_this: &Self) -> Vector<P::EI, P::SI> {
37 Vector::empty().fill(P::EI::max_value())
38 }
39
40 fn null_accumulator(_this: &Self) -> Accumulator<P> {
41 Accumulator::<P> {
42 elements: Value::new_single(Vector::empty().fill(P::EA::max_value())),
43 args: Value::new_None(),
44 }
45 }
46
47 fn reduce(
48 _this: &Self,
49 accumulator: &mut Accumulator<P>,
50 item: Item<P>,
51 #[comptime] reduce_step: ReduceStep,
52 ) {
53 let accumulator_item = &accumulator.elements.item();
54 let item = item.elements;
55 let elements = match reduce_step {
56 ReduceStep::Plane => {
57 let candidate_item = Vector::cast_from(plane_min(item));
58 select_many(
59 accumulator_item.less_than(candidate_item),
60 *accumulator_item,
61 candidate_item,
62 )
63 }
64 ReduceStep::Identity => {
65 let item = Vector::cast_from(item);
66 select_many(accumulator_item.less_than(item), *accumulator_item, item)
67 }
68 };
69
70 accumulator.elements.assign(&Value::new_single(elements));
71 }
72
73 fn plane_reduce_inplace(_this: &Self, accumulator: &mut Accumulator<P>) {
74 let acc_item = accumulator.elements.item();
75 let candidate_item = Vector::cast_from(plane_min(acc_item));
76 let min = select_many(acc_item.less_than(candidate_item), acc_item, candidate_item);
77 accumulator.elements.assign(&Value::new_single(min));
78 }
79
80 fn fuse_accumulators(_this: &Self, accumulator: &mut Accumulator<P>, other: &Accumulator<P>) {
81 let accumulator_item = accumulator.elements.item();
82 let other_item = other.elements.item();
83
84 accumulator.elements.assign(&Value::new_single(select_many(
85 accumulator_item.less_than(other_item),
86 accumulator_item,
87 other_item,
88 )));
89 }
90
91 fn to_output_parallel<Out: Numeric>(
92 _this: &Self,
93 accumulator: Accumulator<P>,
94 _shape_axis_reduce: usize,
95 ) -> Value<Out> {
96 let mut min = P::EA::max_value();
97 let accumulator = accumulator.elements.item();
98 #[unroll]
99 for k in 0..accumulator.size() {
100 let candidate = accumulator[k];
101 min = select(candidate < min, candidate, min);
102 }
103 Value::new_single(Out::cast_from(min))
104 }
105
106 fn to_output_perpendicular<Out: Numeric>(
107 _this: &Self,
108 accumulator: Accumulator<P>,
109 _shape_axis_reduce: usize,
110 ) -> Value<Vector<Out, P::SI>> {
111 Value::new_single(Vector::cast_from(accumulator.elements.item()))
112 }
113}