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
94#[macro_export]
96macro_rules! make_element {
97 (
98 ty $type:ident,
99 convert $convert:expr,
100 random $random:expr,
101 cmp $cmp:expr,
102 dtype $dtype:expr
103 ) => {
104 make_element!(ty $type, convert $convert, random $random, cmp $cmp, dtype $dtype, min $type::MIN, max $type::MAX);
105 };
106 (
107 ty $type:ident,
108 convert $convert:expr,
109 random $random:expr,
110 cmp $cmp:expr,
111 dtype $dtype:expr,
112 min $min:expr,
113 max $max:expr
114 ) => {
115 impl Element for $type {
116 #[inline(always)]
117 fn dtype() -> $crate::DType {
118 $dtype
119 }
120 }
121 impl ElementEq for $type {
122 fn eq(&self, other: &Self) -> bool {
123 self == other
124 }
125 }
126
127 impl ElementConversion for $type {
128 #[inline(always)]
129 fn from_elem<E: ToElement>(elem: E) -> Self {
130 #[allow(clippy::redundant_closure_call)]
131 $convert(&elem)
132 }
133 #[inline(always)]
134 fn elem<E: Element>(self) -> E {
135 E::from_elem(self)
136 }
137 }
138
139 impl ElementRandom for $type {
140 fn random<R: Rng>(distribution: Distribution, rng: &mut R) -> Self {
141 #[allow(clippy::redundant_closure_call)]
142 $random(distribution, rng)
143 }
144 }
145
146 impl ElementComparison for $type {
147 fn cmp(&self, other: &Self) -> Ordering {
148 let a = self.elem::<$type>();
149 let b = other.elem::<$type>();
150 #[allow(clippy::redundant_closure_call)]
151 $cmp(&a, &b)
152 }
153 }
154
155 impl ElementLimits for $type {
156 const MIN: Self = $min;
157 const MAX: Self = $max;
158 }
159
160 impl ElementOrdered for $type {}
161
162 };
163}
164
165make_element!(
166 ty f64,
167 convert ToElement::to_f64,
168 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
169 cmp |a: &f64, b: &f64| a.total_cmp(b),
170 dtype DType::F64
171);
172
173make_element!(
174 ty f32,
175 convert ToElement::to_f32,
176 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
177 cmp |a: &f32, b: &f32| a.total_cmp(b),
178 dtype DType::F32
179);
180
181make_element!(
182 ty i64,
183 convert ToElement::to_i64,
184 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
185 cmp |a: &i64, b: &i64| Ord::cmp(a, b),
186 dtype DType::I64
187);
188
189make_element!(
190 ty u64,
191 convert ToElement::to_u64,
192 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
193 cmp |a: &u64, b: &u64| Ord::cmp(a, b),
194 dtype DType::U64
195);
196
197make_element!(
198 ty i32,
199 convert ToElement::to_i32,
200 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
201 cmp |a: &i32, b: &i32| Ord::cmp(a, b),
202 dtype DType::I32
203);
204
205make_element!(
206 ty u32,
207 convert ToElement::to_u32,
208 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
209 cmp |a: &u32, b: &u32| Ord::cmp(a, b),
210 dtype DType::U32
211);
212
213make_element!(
214 ty i16,
215 convert ToElement::to_i16,
216 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
217 cmp |a: &i16, b: &i16| Ord::cmp(a, b),
218 dtype DType::I16
219);
220
221make_element!(
222 ty u16,
223 convert ToElement::to_u16,
224 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
225 cmp |a: &u16, b: &u16| Ord::cmp(a, b),
226 dtype DType::U16
227);
228
229make_element!(
230 ty i8,
231 convert ToElement::to_i8,
232 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
233 cmp |a: &i8, b: &i8| Ord::cmp(a, b),
234 dtype DType::I8
235);
236
237make_element!(
238 ty u8,
239 convert ToElement::to_u8,
240 random |distribution: Distribution, rng: &mut R| distribution.sampler(rng).sample(),
241 cmp |a: &u8, b: &u8| Ord::cmp(a, b),
242 dtype DType::U8
243);
244
245make_element!(
246 ty f16,
247 convert ToElement::to_f16,
248 random |distribution: Distribution, rng: &mut R| {
249 let sample: f32 = distribution.sampler(rng).sample();
250 f16::from_elem(sample)
251 },
252 cmp |a: &f16, b: &f16| a.total_cmp(b),
253 dtype DType::F16
254);
255make_element!(
256 ty bf16,
257 convert ToElement::to_bf16,
258 random |distribution: Distribution, rng: &mut R| {
259 let sample: f32 = distribution.sampler(rng).sample();
260 bf16::from_elem(sample)
261 },
262 cmp |a: &bf16, b: &bf16| a.total_cmp(b),
263 dtype DType::BF16
264);
265
266make_element!(
267 ty flex32,
268 convert |elem: &dyn ToElement| flex32::from_f32(elem.to_f32()),
269 random |distribution: Distribution, rng: &mut R| {
270 let sample: f32 = distribution.sampler(rng).sample();
271 flex32::from_elem(sample)
272 },
273 cmp |a: &flex32, b: &flex32| a.total_cmp(b),
274 dtype DType::Flex32,
275 min flex32::from_f32(f16::MIN.to_f32_const()),
276 max flex32::from_f32(f16::MAX.to_f32_const())
277);
278
279make_element!(
280 ty bool,
281 convert ToElement::to_bool,
282 random |distribution: Distribution, rng: &mut R| {
283 let sample: u8 = distribution.sampler(rng).sample();
284 bool::from_elem(sample)
285 },
286 cmp |a: &bool, b: &bool| Ord::cmp(a, b),
287 dtype DType::Bool(BoolStore::Native),
288 min false,
289 max true
290);