1use core::cmp::Ordering;
2use rand::Rng;
3
4use crate::distribution::Distribution;
5use crate::{BoolStore, DType, bf16, f16, flex32};
6
7use super::cast::ToElement;
8
9pub trait Element:
14 ToElement
15 + ElementRandom
16 + ElementConversion
17 + ElementEq
18 + bytemuck::CheckedBitPattern
19 + bytemuck::NoUninit
20 + bytemuck::Zeroable
21 + core::fmt::Debug
22 + core::fmt::Display
23 + Default
24 + Send
25 + Sync
26 + Copy
27 + 'static
28{
29 fn dtype() -> DType;
31}
32
33pub trait ElementOrdered: Element + ElementComparison + ElementLimits {}
41
42pub trait ElementConversion {
44 fn from_elem<E: ToElement>(elem: E) -> Self;
54
55 fn elem<E: Element>(self) -> E;
57}
58
59pub trait ElementRandom {
61 fn random<R: Rng>(distribution: Distribution, rng: &mut R) -> Self;
72}
73
74pub trait ElementEq {
76 fn eq(&self, other: &Self) -> bool;
78}
79
80pub trait ElementComparison {
82 fn cmp(&self, other: &Self) -> Ordering;
84}
85
86pub trait ElementLimits {
88 const MIN: Self;
90 const MAX: Self;
92}
93
94pub trait ElementAdd {
96 fn add(self, other: Self) -> Self;
98}
99
100#[macro_export]
102macro_rules! make_element {
103 (
104 ty $type:ident,
105 convert $convert:expr,
106 random $random:expr,
107 cmp $cmp:expr,
108 add $add:expr,
109 dtype $dtype:expr
110 ) => {
111 make_element!(ty $type, convert $convert, random $random, cmp $cmp, add $add, dtype $dtype, min $type::MIN, max $type::MAX);
112 };
113 (
114 ty $type:ident,
115 convert $convert:expr,
116 random $random:expr,
117 cmp $cmp:expr,
118 add $add:expr,
119 dtype $dtype:expr,
120 min $min:expr,
121 max $max:expr
122 ) => {
123 make_element!(ty $type, convert $convert, random $random, cmp $cmp, dtype $dtype, min $min, max $max);
124
125 impl ElementAdd for $type {
126 #[inline(always)]
127 fn add(self, other: Self) -> Self {
128 $add(self, other)
129 }
130 }
131 };
132 (
133 ty $type:ident,
134 convert $convert:expr,
135 random $random:expr,
136 cmp $cmp:expr,
137 dtype $dtype:expr,
138 min $min:expr,
139 max $max:expr
140 ) => {
141 impl Element for $type {
142 #[inline(always)]
143 fn dtype() -> $crate::DType {
144 $dtype
145 }
146 }
147 impl ElementEq for $type {
148 fn eq(&self, other: &Self) -> bool {
149 self == other
150 }
151 }
152
153 impl ElementConversion for $type {
154 #[inline(always)]
155 fn from_elem<E: ToElement>(elem: E) -> Self {
156 #[allow(clippy::redundant_closure_call)]
157 $convert(&elem)
158 }
159 #[inline(always)]
160 fn elem<E: Element>(self) -> E {
161 E::from_elem(self)
162 }
163 }
164
165 impl ElementRandom for $type {
166 fn random<R: Rng>(distribution: Distribution, rng: &mut R) -> Self {
167 #[allow(clippy::redundant_closure_call)]
168 $random(distribution, rng)
169 }
170 }
171
172 impl ElementComparison for $type {
173 fn cmp(&self, other: &Self) -> Ordering {
174 let a = self.elem::<$type>();
175 let b = other.elem::<$type>();
176 #[allow(clippy::redundant_closure_call)]
177 $cmp(&a, &b)
178 }
179 }
180
181 impl ElementLimits for $type {
182 const MIN: Self = $min;
183 const MAX: Self = $max;
184 }
185
186 impl ElementOrdered for $type {}
187
188 };
189}
190
191make_element!(
192 ty f64,
193 convert ToElement::to_f64,
194 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
195 cmp |a: &f64, b: &f64| a.total_cmp(b),
196 add |a, b| a + b,
197 dtype DType::F64
198);
199
200make_element!(
201 ty f32,
202 convert ToElement::to_f32,
203 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
204 cmp |a: &f32, b: &f32| a.total_cmp(b),
205 add |a, b| a + b,
206 dtype DType::F32
207);
208
209make_element!(
210 ty i64,
211 convert ToElement::to_i64,
212 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
213 cmp |a: &i64, b: &i64| Ord::cmp(a, b),
214 add |a, b| a + b,
215 dtype DType::I64
216);
217
218make_element!(
219 ty u64,
220 convert ToElement::to_u64,
221 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
222 cmp |a: &u64, b: &u64| Ord::cmp(a, b),
223 add |a, b| a + b,
224 dtype DType::U64
225);
226
227make_element!(
228 ty i32,
229 convert ToElement::to_i32,
230 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
231 cmp |a: &i32, b: &i32| Ord::cmp(a, b),
232 add |a, b| a + b,
233 dtype DType::I32
234);
235
236make_element!(
237 ty u32,
238 convert ToElement::to_u32,
239 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
240 cmp |a: &u32, b: &u32| Ord::cmp(a, b),
241 add |a, b| a + b,
242 dtype DType::U32
243);
244
245make_element!(
246 ty i16,
247 convert ToElement::to_i16,
248 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
249 cmp |a: &i16, b: &i16| Ord::cmp(a, b),
250 add |a, b| a + b,
251 dtype DType::I16
252);
253
254make_element!(
255 ty u16,
256 convert ToElement::to_u16,
257 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
258 cmp |a: &u16, b: &u16| Ord::cmp(a, b),
259 add |a, b| a + b,
260 dtype DType::U16
261);
262
263make_element!(
264 ty i8,
265 convert ToElement::to_i8,
266 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
267 cmp |a: &i8, b: &i8| Ord::cmp(a, b),
268 add |a, b| a + b,
269 dtype DType::I8
270);
271
272make_element!(
273 ty u8,
274 convert ToElement::to_u8,
275 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
276 cmp |a: &u8, b: &u8| Ord::cmp(a, b),
277 add |a, b| a + b,
278 dtype DType::U8
279);
280
281make_element!(
282 ty f16,
283 convert ToElement::to_f16,
284 random |distribution: Distribution, rng: &mut R| {
285 let sample: f32 = distribution.sampler(rng).sample();
286 f16::from_elem(sample)
287 },
288 cmp |a: &f16, b: &f16| a.total_cmp(b),
289 add |a: f16, b: f16| f16::from_f32(a.to_f32() + b.to_f32()),
290 dtype DType::F16
291);
292make_element!(
293 ty bf16,
294 convert ToElement::to_bf16,
295 random |distribution: Distribution, rng: &mut R| {
296 let sample: f32 = distribution.sampler(rng).sample();
297 bf16::from_elem(sample)
298 },
299 cmp |a: &bf16, b: &bf16| a.total_cmp(b),
300 add |a, b| a + b,
301 dtype DType::BF16
302);
303
304make_element!(
305 ty flex32,
306 convert |elem: &dyn ToElement| flex32::from_f32(elem.to_f32()),
307 random |distribution: Distribution, rng: &mut R| {
308 let sample: f32 = distribution.sampler(rng).sample();
309 flex32::from_elem(sample)
310 },
311 cmp |a: &flex32, b: &flex32| a.total_cmp(b),
312 add |a: flex32, b: flex32| flex32::from_f32(a.to_f32() + b.to_f32()),
313 dtype DType::Flex32,
314 min flex32::from_f32(f16::MIN.to_f32_const()),
315 max flex32::from_f32(f16::MAX.to_f32_const())
316);
317
318make_element!(
319 ty bool,
320 convert ToElement::to_bool,
321 random |distribution: Distribution, rng: &mut R| {
322 let sample: u8 = distribution.sampler(rng).sample();
323 bool::from_elem(sample)
324 },
325 cmp |a: &bool, b: &bool| Ord::cmp(a, b),
326 dtype DType::Bool(BoolStore::Native),
327 min false,
328 max true
329);