Skip to main content

ruprim/reduce/components/instructions/
min.rs

1use 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// TODO Add to test framework.
10/// Return the item with the maximum absolute value.
11#[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}