1use alloc::vec;
4use alloc::vec::Vec;
5use burn_backend::{
6 DType, Distribution, ExecutionError, FloatDType, Scalar, TensorData, TensorMetadata,
7 ops::{FloatTensorOps, GridSampleOptions, IntTensorOps},
8 tensor::{BoolTensor, Device, FloatTensor, IntTensor},
9};
10use burn_std::{Bytes, IntDType, Shape, Slice, bf16, f16};
11#[cfg(not(feature = "std"))]
12#[allow(unused_imports)]
13use num_traits::Float;
14
15use crate::Layout;
16use num_traits::ToPrimitive;
17
18use crate::ops::binary::{BinaryOp, binary_op, scalar_op};
19use crate::ops::matmul;
20use crate::ops::unary;
21use crate::{Flex, FlexTensor};
22
23impl FloatTensorOps<Flex> for Flex {
24 fn float_from_data(data: TensorData, _device: &Device<Flex>) -> FloatTensor<Flex> {
25 FlexTensor::from_data(data)
26 }
27
28 fn float_random(
29 shape: Shape,
30 distribution: Distribution,
31 _device: &Device<Flex>,
32 dtype: FloatDType,
33 ) -> FloatTensor<Flex> {
34 let mut seed = crate::backend::SEED.lock().unwrap();
35 let mut rng = seed.take().unwrap_or_else(crate::backend::get_seeded_rng);
36 let data = match dtype {
37 FloatDType::F64 => TensorData::random::<f64, _, _>(shape, distribution, &mut rng),
38 FloatDType::F32 | FloatDType::Flex32 => {
39 TensorData::random::<f32, _, _>(shape, distribution, &mut rng)
40 }
41 FloatDType::F16 => TensorData::random::<f16, _, _>(shape, distribution, &mut rng),
42 FloatDType::BF16 => TensorData::random::<bf16, _, _>(shape, distribution, &mut rng),
43 };
44 *seed = Some(rng);
45 FlexTensor::from_data(data)
46 }
47
48 async fn float_into_data(tensor: FloatTensor<Flex>) -> Result<TensorData, ExecutionError> {
49 Ok(tensor.into_data())
50 }
51
52 fn float_to_device(tensor: FloatTensor<Flex>, _device: &Device<Flex>) -> FloatTensor<Flex> {
53 tensor
55 }
56
57 fn float_detach(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
58 tensor
59 }
60
61 fn float_into_int(tensor: FloatTensor<Flex>, out_dtype: burn_std::IntDType) -> IntTensor<Flex> {
62 let tensor = tensor.to_contiguous();
63 let shape = tensor.layout().shape().clone();
64 let src = tensor.dtype();
65 let out_dt = DType::from(out_dtype);
66
67 macro_rules! read_floats {
69 (|$x:ident| $conv:expr) => {
70 match src {
71 DType::F32 => tensor
72 .storage::<f32>()
73 .iter()
74 .map(|v| {
75 let $x = *v as f64;
76 $conv
77 })
78 .collect(),
79 DType::F64 => tensor
80 .storage::<f64>()
81 .iter()
82 .map(|v| {
83 let $x = *v;
84 $conv
85 })
86 .collect(),
87 DType::F16 => tensor
88 .storage::<f16>()
89 .iter()
90 .map(|v| {
91 let $x = f32::from(*v) as f64;
92 $conv
93 })
94 .collect(),
95 DType::BF16 => tensor
96 .storage::<bf16>()
97 .iter()
98 .map(|v| {
99 let $x = f32::from(*v) as f64;
100 $conv
101 })
102 .collect(),
103 _ => panic!("float_into_int: unsupported source dtype {:?}", src),
104 }
105 };
106 }
107
108 macro_rules! convert {
109 ($int_ty:ty) => {{
110 let data: Vec<$int_ty> = read_floats!(|x| x as $int_ty);
111 FlexTensor::new(Bytes::from_elems(data), Layout::contiguous(shape), out_dt)
112 }};
113 }
114
115 match out_dtype {
116 IntDType::I64 => convert!(i64),
117 IntDType::I32 => convert!(i32),
118 IntDType::I16 => convert!(i16),
119 IntDType::I8 => convert!(i8),
120 IntDType::U64 => convert!(u64),
121 IntDType::U32 => convert!(u32),
122 IntDType::U16 => convert!(u16),
123 IntDType::U8 => convert!(u8),
124 }
125 }
126
127 fn float_empty(shape: Shape, _device: &Device<Flex>, dtype: FloatDType) -> FloatTensor<Flex> {
128 FlexTensor::empty(shape, dtype.into())
129 }
130
131 fn float_add(lhs: FloatTensor<Flex>, rhs: FloatTensor<Flex>) -> FloatTensor<Flex> {
132 binary_op(lhs, rhs, |a, b| a + b, |a, b| a + b, Some(BinaryOp::Add))
133 }
134
135 fn float_add_scalar(lhs: FloatTensor<Flex>, rhs: Scalar) -> FloatTensor<Flex> {
136 let rhs_val = rhs.to_f64().unwrap();
137 scalar_op(lhs, rhs_val, |a, b| a + b, |a, b| a + b)
138 }
139
140 fn float_sub(lhs: FloatTensor<Flex>, rhs: FloatTensor<Flex>) -> FloatTensor<Flex> {
141 binary_op(lhs, rhs, |a, b| a - b, |a, b| a - b, Some(BinaryOp::Sub))
142 }
143
144 fn float_sub_scalar(lhs: FloatTensor<Flex>, rhs: Scalar) -> FloatTensor<Flex> {
145 let rhs_val = rhs.to_f64().unwrap();
146 scalar_op(lhs, rhs_val, |a, b| a - b, |a, b| a - b)
147 }
148
149 fn float_mul(lhs: FloatTensor<Flex>, rhs: FloatTensor<Flex>) -> FloatTensor<Flex> {
150 binary_op(lhs, rhs, |a, b| a * b, |a, b| a * b, Some(BinaryOp::Mul))
151 }
152
153 fn float_mul_scalar(lhs: FloatTensor<Flex>, rhs: Scalar) -> FloatTensor<Flex> {
154 let rhs_val = rhs.to_f64().unwrap();
155 scalar_op(lhs, rhs_val, |a, b| a * b, |a, b| a * b)
156 }
157
158 fn float_div(lhs: FloatTensor<Flex>, rhs: FloatTensor<Flex>) -> FloatTensor<Flex> {
159 binary_op(lhs, rhs, |a, b| a / b, |a, b| a / b, Some(BinaryOp::Div))
160 }
161
162 fn float_div_scalar(lhs: FloatTensor<Flex>, rhs: Scalar) -> FloatTensor<Flex> {
163 let rhs_val = rhs.to_f64().unwrap();
164 scalar_op(lhs, rhs_val, |a, b| a / b, |a, b| a / b)
165 }
166
167 fn float_remainder(lhs: FloatTensor<Flex>, rhs: FloatTensor<Flex>) -> FloatTensor<Flex> {
168 binary_op(
170 lhs,
171 rhs,
172 |a, b| ((a % b) + b) % b,
173 |a, b| ((a % b) + b) % b,
174 None,
175 )
176 }
177
178 fn float_remainder_scalar(lhs: FloatTensor<Flex>, rhs: Scalar) -> FloatTensor<Flex> {
179 let rhs_val = rhs.to_f64().unwrap();
180 scalar_op(
182 lhs,
183 rhs_val,
184 |a, b| ((a % b) + b) % b,
185 |a, b| ((a % b) + b) % b,
186 )
187 }
188
189 fn float_matmul(lhs: FloatTensor<Flex>, rhs: FloatTensor<Flex>) -> FloatTensor<Flex> {
190 matmul::matmul(lhs, rhs)
191 }
192
193 fn float_cross(
194 lhs: FloatTensor<Flex>,
195 rhs: FloatTensor<Flex>,
196 dim: usize,
197 ) -> FloatTensor<Flex> {
198 let shape = lhs.layout().shape();
199 let ndims = shape.num_dims();
200 assert_eq!(
201 shape[dim], 3,
202 "cross product requires dimension {} to have size 3, got {}",
203 dim, shape[dim]
204 );
205
206 let make_slices = |idx: usize| -> alloc::vec::Vec<Slice> {
208 (0..ndims)
209 .map(|d| {
210 if d == dim {
211 Slice::new(idx as isize, Some((idx + 1) as isize), 1)
212 } else {
213 Slice::new(0, None, 1)
214 }
215 })
216 .collect()
217 };
218
219 let a0 = Self::float_slice(lhs.clone(), &make_slices(0));
222 let a1 = Self::float_slice(lhs.clone(), &make_slices(1));
223 let a2 = Self::float_slice(lhs, &make_slices(2));
224
225 let b0 = Self::float_slice(rhs.clone(), &make_slices(0));
226 let b1 = Self::float_slice(rhs.clone(), &make_slices(1));
227 let b2 = Self::float_slice(rhs, &make_slices(2));
228
229 let c0 = Self::float_sub(
234 Self::float_mul(a1.clone(), b2.clone()),
235 Self::float_mul(a2.clone(), b1.clone()),
236 );
237 let c1 = Self::float_sub(
238 Self::float_mul(a2, b0.clone()),
239 Self::float_mul(a0.clone(), b2),
240 );
241 let c2 = Self::float_sub(Self::float_mul(a0, b1), Self::float_mul(a1, b0));
242
243 Self::float_cat(vec![c0, c1, c2], dim)
245 }
246
247 fn float_recip(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
248 unary::recip(tensor)
249 }
250
251 fn float_swap_dims(tensor: FloatTensor<Flex>, dim1: usize, dim2: usize) -> FloatTensor<Flex> {
252 tensor.transpose(dim1, dim2)
253 }
254
255 fn float_permute(tensor: FloatTensor<Flex>, axes: &[usize]) -> FloatTensor<Flex> {
256 tensor.permute(axes)
257 }
258
259 fn float_flip(tensor: FloatTensor<Flex>, axes: &[usize]) -> FloatTensor<Flex> {
260 crate::ops::flip::flip(tensor, axes)
261 }
262
263 fn float_cat(tensors: Vec<FloatTensor<Flex>>, dim: usize) -> FloatTensor<Flex> {
264 crate::ops::cat::cat(tensors, dim)
265 }
266
267 fn float_reshape(tensor: FloatTensor<Flex>, shape: Shape) -> FloatTensor<Flex> {
268 tensor.reshape(shape)
269 }
270
271 fn float_gather(
272 dim: usize,
273 tensor: FloatTensor<Flex>,
274 indices: IntTensor<Flex>,
275 ) -> FloatTensor<Flex> {
276 match tensor.dtype() {
277 DType::F32 => crate::ops::gather_scatter::gather::<f32>(tensor, dim, indices),
278 DType::F64 => crate::ops::gather_scatter::gather::<f64>(tensor, dim, indices),
279 DType::F16 => crate::ops::gather_scatter::gather::<f16>(tensor, dim, indices),
280 DType::BF16 => crate::ops::gather_scatter::gather::<bf16>(tensor, dim, indices),
281 _ => panic!("float_gather: unsupported dtype {:?}", tensor.dtype()),
282 }
283 }
284
285 fn float_scatter_add(
286 dim: usize,
287 tensor: FloatTensor<Flex>,
288 indices: IntTensor<Flex>,
289 value: FloatTensor<Flex>,
290 ) -> FloatTensor<Flex> {
291 match tensor.dtype() {
292 DType::F32 => {
293 crate::ops::gather_scatter::scatter_add::<f32>(tensor, dim, indices, value)
294 }
295 DType::F64 => {
296 crate::ops::gather_scatter::scatter_add::<f64>(tensor, dim, indices, value)
297 }
298 DType::F16 => {
299 crate::ops::gather_scatter::scatter_add::<f16>(tensor, dim, indices, value)
300 }
301 DType::BF16 => {
302 crate::ops::gather_scatter::scatter_add::<bf16>(tensor, dim, indices, value)
303 }
304 _ => panic!("float_scatter_add: unsupported dtype {:?}", tensor.dtype()),
305 }
306 }
307
308 fn float_scatter_nd(
309 data: FloatTensor<Flex>,
310 indices: IntTensor<Flex>,
311 values: FloatTensor<Flex>,
312 reduction: burn_backend::tensor::IndexingUpdateOp,
313 ) -> FloatTensor<Flex> {
314 match data.dtype() {
315 DType::F32 => {
316 crate::ops::gather_scatter::scatter_nd::<f32>(data, indices, values, reduction)
317 }
318 DType::F64 => {
319 crate::ops::gather_scatter::scatter_nd::<f64>(data, indices, values, reduction)
320 }
321 DType::F16 => {
322 crate::ops::gather_scatter::scatter_nd::<f16>(data, indices, values, reduction)
323 }
324 DType::BF16 => {
325 crate::ops::gather_scatter::scatter_nd::<bf16>(data, indices, values, reduction)
326 }
327 _ => panic!("float_scatter_nd: unsupported dtype {:?}", data.dtype()),
328 }
329 }
330
331 fn float_gather_nd(data: FloatTensor<Flex>, indices: IntTensor<Flex>) -> FloatTensor<Flex> {
332 match data.dtype() {
333 DType::F32 => crate::ops::gather_scatter::gather_nd::<f32>(data, indices),
334 DType::F64 => crate::ops::gather_scatter::gather_nd::<f64>(data, indices),
335 DType::F16 => crate::ops::gather_scatter::gather_nd::<f16>(data, indices),
336 DType::BF16 => crate::ops::gather_scatter::gather_nd::<bf16>(data, indices),
337 _ => panic!("float_gather_nd: unsupported dtype {:?}", data.dtype()),
338 }
339 }
340
341 fn float_select(
342 tensor: FloatTensor<Flex>,
343 dim: usize,
344 indices: IntTensor<Flex>,
345 ) -> FloatTensor<Flex> {
346 match tensor.dtype() {
347 DType::F32 => crate::ops::gather_scatter::select::<f32>(tensor, dim, indices),
348 DType::F64 => crate::ops::gather_scatter::select::<f64>(tensor, dim, indices),
349 DType::F16 => crate::ops::gather_scatter::select::<f16>(tensor, dim, indices),
350 DType::BF16 => crate::ops::gather_scatter::select::<bf16>(tensor, dim, indices),
351 _ => panic!("float_select: unsupported dtype {:?}", tensor.dtype()),
352 }
353 }
354
355 fn float_select_add(
356 tensor: FloatTensor<Flex>,
357 dim: usize,
358 indices: IntTensor<Flex>,
359 value: FloatTensor<Flex>,
360 ) -> FloatTensor<Flex> {
361 match tensor.dtype() {
362 DType::F32 => {
363 crate::ops::gather_scatter::select_add::<f32>(tensor, dim, indices, value)
364 }
365 DType::F64 => {
366 crate::ops::gather_scatter::select_add::<f64>(tensor, dim, indices, value)
367 }
368 DType::F16 => {
369 crate::ops::gather_scatter::select_add::<f16>(tensor, dim, indices, value)
370 }
371 DType::BF16 => {
372 crate::ops::gather_scatter::select_add::<bf16>(tensor, dim, indices, value)
373 }
374 _ => panic!("float_select_add: unsupported dtype {:?}", tensor.dtype()),
375 }
376 }
377
378 fn float_slice(tensor: FloatTensor<Flex>, slices: &[Slice]) -> FloatTensor<Flex> {
379 crate::ops::slice::slice(tensor, slices)
380 }
381
382 fn float_slice_assign(
383 tensor: FloatTensor<Flex>,
384 slices: &[Slice],
385 value: FloatTensor<Flex>,
386 ) -> FloatTensor<Flex> {
387 crate::ops::slice::slice_assign(tensor, slices, value)
388 }
389
390 fn float_mask_where(
391 tensor: FloatTensor<Flex>,
392 mask: BoolTensor<Flex>,
393 value: FloatTensor<Flex>,
394 ) -> FloatTensor<Flex> {
395 match tensor.dtype() {
396 DType::F32 => crate::ops::mask::mask_where_f32(tensor, mask, value),
397 DType::F64 => crate::ops::mask::mask_where_f64(tensor, mask, value),
398 DType::F16 => crate::ops::mask::mask_where_f16(tensor, mask, value),
399 DType::BF16 => crate::ops::mask::mask_where_bf16(tensor, mask, value),
400 dtype => panic!("float_mask_where: unsupported dtype {:?}", dtype),
401 }
402 }
403
404 fn float_mask_fill(
405 tensor: FloatTensor<Flex>,
406 mask: BoolTensor<Flex>,
407 value: Scalar,
408 ) -> FloatTensor<Flex> {
409 match tensor.dtype() {
410 DType::F32 => crate::ops::mask::mask_fill_f32(tensor, mask, value.to_f32().unwrap()),
411 DType::F64 => crate::ops::mask::mask_fill_f64(tensor, mask, value.to_f64().unwrap()),
412 DType::F16 => crate::ops::mask::mask_fill_f16(
413 tensor,
414 mask,
415 f16::from_f64(value.to_f64().unwrap()),
416 ),
417 DType::BF16 => crate::ops::mask::mask_fill_bf16(
418 tensor,
419 mask,
420 bf16::from_f64(value.to_f64().unwrap()),
421 ),
422 dtype => panic!("float_mask_fill: unsupported dtype {:?}", dtype),
423 }
424 }
425
426 fn float_equal(
427 lhs: FloatTensor<Flex>,
428 rhs: FloatTensor<Flex>,
429 out_dtype: burn_std::BoolDType,
430 ) -> BoolTensor<Flex> {
431 crate::ops::comparison::equal(lhs, rhs, out_dtype)
432 }
433
434 fn float_equal_elem(
435 lhs: FloatTensor<Flex>,
436 rhs: Scalar,
437 out_dtype: burn_std::BoolDType,
438 ) -> BoolTensor<Flex> {
439 crate::ops::comparison::equal_elem(lhs, rhs.to_f64().unwrap(), out_dtype)
440 }
441
442 fn float_greater(
443 lhs: FloatTensor<Flex>,
444 rhs: FloatTensor<Flex>,
445 out_dtype: burn_std::BoolDType,
446 ) -> BoolTensor<Flex> {
447 crate::ops::comparison::greater(lhs, rhs, out_dtype)
448 }
449
450 fn float_greater_elem(
451 lhs: FloatTensor<Flex>,
452 rhs: Scalar,
453 out_dtype: burn_std::BoolDType,
454 ) -> BoolTensor<Flex> {
455 crate::ops::comparison::greater_elem(lhs, rhs.to_f64().unwrap(), out_dtype)
456 }
457
458 fn float_greater_equal(
459 lhs: FloatTensor<Flex>,
460 rhs: FloatTensor<Flex>,
461 out_dtype: burn_std::BoolDType,
462 ) -> BoolTensor<Flex> {
463 crate::ops::comparison::greater_equal(lhs, rhs, out_dtype)
464 }
465
466 fn float_greater_equal_elem(
467 lhs: FloatTensor<Flex>,
468 rhs: Scalar,
469 out_dtype: burn_std::BoolDType,
470 ) -> BoolTensor<Flex> {
471 crate::ops::comparison::greater_equal_elem(lhs, rhs.to_f64().unwrap(), out_dtype)
472 }
473
474 fn float_lower(
475 lhs: FloatTensor<Flex>,
476 rhs: FloatTensor<Flex>,
477 out_dtype: burn_std::BoolDType,
478 ) -> BoolTensor<Flex> {
479 crate::ops::comparison::lower(lhs, rhs, out_dtype)
480 }
481
482 fn float_lower_elem(
483 lhs: FloatTensor<Flex>,
484 rhs: Scalar,
485 out_dtype: burn_std::BoolDType,
486 ) -> BoolTensor<Flex> {
487 crate::ops::comparison::lower_elem(lhs, rhs.to_f64().unwrap(), out_dtype)
488 }
489
490 fn float_lower_equal(
491 lhs: FloatTensor<Flex>,
492 rhs: FloatTensor<Flex>,
493 out_dtype: burn_std::BoolDType,
494 ) -> BoolTensor<Flex> {
495 crate::ops::comparison::lower_equal(lhs, rhs, out_dtype)
496 }
497
498 fn float_lower_equal_elem(
499 lhs: FloatTensor<Flex>,
500 rhs: Scalar,
501 out_dtype: burn_std::BoolDType,
502 ) -> BoolTensor<Flex> {
503 crate::ops::comparison::lower_equal_elem(lhs, rhs.to_f64().unwrap(), out_dtype)
504 }
505
506 fn float_not_equal(
507 lhs: FloatTensor<Flex>,
508 rhs: FloatTensor<Flex>,
509 out_dtype: burn_std::BoolDType,
510 ) -> BoolTensor<Flex> {
511 crate::ops::comparison::not_equal(lhs, rhs, out_dtype)
512 }
513
514 fn float_not_equal_elem(
515 lhs: FloatTensor<Flex>,
516 rhs: Scalar,
517 out_dtype: burn_std::BoolDType,
518 ) -> BoolTensor<Flex> {
519 crate::ops::comparison::not_equal_elem(lhs, rhs.to_f64().unwrap(), out_dtype)
520 }
521
522 fn float_neg(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
523 unary::unary_op(tensor, |x: f32| -x, |x: f64| -x)
524 }
525
526 fn float_clamp(tensor: FloatTensor<Flex>, min: Scalar, max: Scalar) -> FloatTensor<Flex> {
527 let min32 = min.to_f32().unwrap();
528 let max32 = max.to_f32().unwrap();
529 let min64 = min.to_f64().unwrap();
530 let max64 = max.to_f64().unwrap();
531 unary::unary_op(
532 tensor,
533 move |x: f32| x.clamp(min32, max32),
534 move |x: f64| x.clamp(min64, max64),
535 )
536 }
537
538 fn float_clamp_min(tensor: FloatTensor<Flex>, min: Scalar) -> FloatTensor<Flex> {
539 let min32 = min.to_f32().unwrap();
540 let min64 = min.to_f64().unwrap();
541 unary::unary_op(
542 tensor,
543 move |x: f32| x.max(min32),
544 move |x: f64| x.max(min64),
545 )
546 }
547
548 fn float_clamp_max(tensor: FloatTensor<Flex>, max: Scalar) -> FloatTensor<Flex> {
549 let max32 = max.to_f32().unwrap();
550 let max64 = max.to_f64().unwrap();
551 unary::unary_op(
552 tensor,
553 move |x: f32| x.min(max32),
554 move |x: f64| x.min(max64),
555 )
556 }
557
558 fn float_sign(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
559 unary::unary_op(
560 tensor,
561 |x: f32| {
562 if x.is_nan() {
563 x
564 } else if x > 0.0 {
565 1.0
566 } else if x < 0.0 {
567 -1.0
568 } else {
569 0.0
570 }
571 },
572 |x: f64| {
573 if x.is_nan() {
574 x
575 } else if x > 0.0 {
576 1.0
577 } else if x < 0.0 {
578 -1.0
579 } else {
580 0.0
581 }
582 },
583 )
584 }
585
586 fn float_mean(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
587 crate::ops::reduce::mean(tensor)
588 }
589
590 fn float_max(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
591 crate::ops::reduce::max(tensor)
592 }
593
594 fn float_max_dim(tensor: FloatTensor<Flex>, dim: usize) -> FloatTensor<Flex> {
595 crate::ops::reduce::max_dim(tensor, dim)
596 }
597
598 fn float_min(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
599 crate::ops::reduce::min(tensor)
600 }
601
602 fn float_min_dim(tensor: FloatTensor<Flex>, dim: usize) -> FloatTensor<Flex> {
603 crate::ops::reduce::min_dim(tensor, dim)
604 }
605
606 fn float_max_dim_with_indices(
607 tensor: FloatTensor<Flex>,
608 dim: usize,
609 indices_dtype: burn_std::IntDType,
610 ) -> (FloatTensor<Flex>, IntTensor<Flex>) {
611 let (values, indices) = crate::ops::reduce::max_dim_with_indices(tensor, dim);
612 if indices.dtype() != DType::from(indices_dtype) {
613 (values, Flex::int_cast(indices, indices_dtype))
614 } else {
615 (values, indices)
616 }
617 }
618
619 fn float_min_dim_with_indices(
620 tensor: FloatTensor<Flex>,
621 dim: usize,
622 indices_dtype: burn_std::IntDType,
623 ) -> (FloatTensor<Flex>, IntTensor<Flex>) {
624 let (values, indices) = crate::ops::reduce::min_dim_with_indices(tensor, dim);
625 if indices.dtype() != DType::from(indices_dtype) {
626 (values, Flex::int_cast(indices, indices_dtype))
627 } else {
628 (values, indices)
629 }
630 }
631
632 fn float_any(tensor: FloatTensor<Flex>, out_dtype: burn_std::BoolDType) -> BoolTensor<Flex> {
633 crate::ops::comparison::any_float(tensor, out_dtype)
634 }
635
636 fn float_any_dim(
637 tensor: FloatTensor<Flex>,
638 dim: usize,
639 out_dtype: burn_std::BoolDType,
640 ) -> BoolTensor<Flex> {
641 crate::ops::comparison::any_float_dim(tensor, dim, out_dtype)
642 }
643
644 fn float_all(tensor: FloatTensor<Flex>, out_dtype: burn_std::BoolDType) -> BoolTensor<Flex> {
645 crate::ops::comparison::all_float(tensor, out_dtype)
646 }
647
648 fn float_all_dim(
649 tensor: FloatTensor<Flex>,
650 dim: usize,
651 out_dtype: burn_std::BoolDType,
652 ) -> BoolTensor<Flex> {
653 crate::ops::comparison::all_float_dim(tensor, dim, out_dtype)
654 }
655
656 fn float_sum(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
657 crate::ops::reduce::sum(tensor)
658 }
659
660 fn float_sum_dim(tensor: FloatTensor<Flex>, dim: usize) -> FloatTensor<Flex> {
661 crate::ops::reduce::sum_dim(tensor, dim)
662 }
663
664 fn float_mean_dim(tensor: FloatTensor<Flex>, dim: usize) -> FloatTensor<Flex> {
665 crate::ops::reduce::mean_dim(tensor, dim)
666 }
667
668 fn float_prod(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
669 crate::ops::reduce::prod(tensor)
670 }
671
672 fn float_prod_dim(tensor: FloatTensor<Flex>, dim: usize) -> FloatTensor<Flex> {
673 crate::ops::reduce::prod_dim(tensor, dim)
674 }
675
676 fn float_cumsum(tensor: FloatTensor<Flex>, dim: usize) -> FloatTensor<Flex> {
677 match tensor.dtype() {
678 DType::F32 => crate::ops::cumulative::cumsum_f32(tensor, dim),
679 DType::F64 => crate::ops::cumulative::cumsum_f64(tensor, dim),
680 DType::F16 => {
681 crate::ops::cumulative::cumsum_half(tensor, dim, f16::to_f32, f16::from_f32)
682 }
683 DType::BF16 => {
684 crate::ops::cumulative::cumsum_half(tensor, dim, bf16::to_f32, bf16::from_f32)
685 }
686 _ => panic!("float_cumsum: unsupported dtype {:?}", tensor.dtype()),
687 }
688 }
689
690 fn float_cumprod(tensor: FloatTensor<Flex>, dim: usize) -> FloatTensor<Flex> {
691 match tensor.dtype() {
692 DType::F32 => crate::ops::cumulative::cumprod_f32(tensor, dim),
693 DType::F64 => crate::ops::cumulative::cumprod_f64(tensor, dim),
694 DType::F16 => {
695 crate::ops::cumulative::cumprod_half(tensor, dim, f16::to_f32, f16::from_f32)
696 }
697 DType::BF16 => {
698 crate::ops::cumulative::cumprod_half(tensor, dim, bf16::to_f32, bf16::from_f32)
699 }
700 _ => panic!("float_cumprod: unsupported dtype {:?}", tensor.dtype()),
701 }
702 }
703
704 fn float_cummin(tensor: FloatTensor<Flex>, dim: usize) -> FloatTensor<Flex> {
705 match tensor.dtype() {
706 DType::F32 => crate::ops::cumulative::cummin_f32(tensor, dim),
707 DType::F64 => crate::ops::cumulative::cummin_f64(tensor, dim),
708 DType::F16 => {
709 crate::ops::cumulative::cummin_half(tensor, dim, f16::to_f32, f16::from_f32)
710 }
711 DType::BF16 => {
712 crate::ops::cumulative::cummin_half(tensor, dim, bf16::to_f32, bf16::from_f32)
713 }
714 _ => panic!("float_cummin: unsupported dtype {:?}", tensor.dtype()),
715 }
716 }
717
718 fn float_cummax(tensor: FloatTensor<Flex>, dim: usize) -> FloatTensor<Flex> {
719 match tensor.dtype() {
720 DType::F32 => crate::ops::cumulative::cummax_f32(tensor, dim),
721 DType::F64 => crate::ops::cumulative::cummax_f64(tensor, dim),
722 DType::F16 => {
723 crate::ops::cumulative::cummax_half(tensor, dim, f16::to_f32, f16::from_f32)
724 }
725 DType::BF16 => {
726 crate::ops::cumulative::cummax_half(tensor, dim, bf16::to_f32, bf16::from_f32)
727 }
728 _ => panic!("float_cummax: unsupported dtype {:?}", tensor.dtype()),
729 }
730 }
731
732 fn float_cast(tensor: FloatTensor<Flex>, dtype: FloatDType) -> FloatTensor<Flex> {
733 use crate::Layout;
734 use burn_std::{Bytes, bf16, f16};
735
736 let src_dtype = tensor.dtype();
737 let target_dtype = DType::from(dtype);
738
739 if src_dtype == target_dtype {
741 return tensor;
742 }
743
744 let tensor = tensor.to_contiguous();
745 let shape = tensor.layout().shape().clone();
746
747 let f64_values: Vec<f64> = match src_dtype {
749 DType::F32 => {
750 let src: &[f32] = tensor.storage();
751 src.iter().map(|&v| v as f64).collect()
752 }
753 DType::F64 => {
754 let src: &[f64] = tensor.storage();
755 src.to_vec()
756 }
757 DType::F16 => {
758 let src: &[f16] = tensor.storage();
759 src.iter().map(|&v| v.to_f32() as f64).collect()
760 }
761 DType::BF16 => {
762 let src: &[bf16] = tensor.storage();
763 src.iter().map(|&v| v.to_f32() as f64).collect()
764 }
765 _ => panic!("float_cast: unsupported source dtype {:?}", src_dtype),
766 };
767
768 match target_dtype {
770 DType::F32 => {
771 let result: Vec<f32> = f64_values.iter().map(|&v| v as f32).collect();
772 let bytes = Bytes::from_elems(result);
773 FlexTensor::new(bytes, Layout::contiguous(shape), DType::F32)
774 }
775 DType::F64 => {
776 let bytes = Bytes::from_elems(f64_values);
777 FlexTensor::new(bytes, Layout::contiguous(shape), DType::F64)
778 }
779 DType::F16 => {
780 let result: Vec<f16> = f64_values.iter().map(|&v| f16::from_f64(v)).collect();
781 let bytes = Bytes::from_elems(result);
782 FlexTensor::new(bytes, Layout::contiguous(shape), DType::F16)
783 }
784 DType::BF16 => {
785 let result: Vec<bf16> = f64_values.iter().map(|&v| bf16::from_f64(v)).collect();
786 let bytes = Bytes::from_elems(result);
787 FlexTensor::new(bytes, Layout::contiguous(shape), DType::BF16)
788 }
789 _ => panic!("float_cast: unsupported target dtype {:?}", target_dtype),
790 }
791 }
792
793 fn float_exp(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
794 unary::exp(tensor)
795 }
796
797 fn float_log(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
798 unary::log(tensor)
799 }
800
801 fn float_log1p(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
802 unary::log1p(tensor)
803 }
804
805 fn float_powf(lhs: FloatTensor<Flex>, rhs: FloatTensor<Flex>) -> FloatTensor<Flex> {
806 binary_op(lhs, rhs, |a: f32, b| a.powf(b), |a: f64, b| a.powf(b), None)
807 }
808
809 fn float_powf_scalar_impl(tensor: FloatTensor<Flex>, value: Scalar) -> FloatTensor<Flex> {
810 let exp = value.to_f64().unwrap();
811 scalar_op(tensor, exp, |a: f32, b| a.powf(b), |a: f64, b| a.powf(b))
812 }
813
814 fn float_sqrt(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
815 unary::sqrt(tensor)
816 }
817
818 fn float_abs(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
819 unary::abs(tensor)
820 }
821
822 fn float_cos(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
823 unary::cos(tensor)
824 }
825
826 fn float_sin(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
827 unary::sin(tensor)
828 }
829
830 fn float_tan(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
831 unary::tan(tensor)
832 }
833
834 fn float_cosh(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
835 unary::cosh(tensor)
836 }
837
838 fn float_sinh(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
839 unary::sinh(tensor)
840 }
841
842 fn float_tanh(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
843 unary::tanh(tensor)
844 }
845
846 fn float_acos(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
847 unary::acos(tensor)
848 }
849
850 fn float_acosh(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
851 unary::acosh(tensor)
852 }
853
854 fn float_asin(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
855 unary::asin(tensor)
856 }
857
858 fn float_asinh(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
859 unary::asinh(tensor)
860 }
861
862 fn float_atan(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
863 unary::atan(tensor)
864 }
865
866 fn float_atanh(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
867 unary::atanh(tensor)
868 }
869
870 fn float_atan2(lhs: FloatTensor<Flex>, rhs: FloatTensor<Flex>) -> FloatTensor<Flex> {
871 binary_op(
872 lhs,
873 rhs,
874 |a: f32, b| a.atan2(b),
875 |a: f64, b| a.atan2(b),
876 None,
877 )
878 }
879
880 fn float_round(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
881 unary::round(tensor)
882 }
883
884 fn float_floor(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
885 unary::floor(tensor)
886 }
887
888 fn float_ceil(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
889 unary::ceil(tensor)
890 }
891
892 fn float_trunc(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
893 unary::trunc(tensor)
894 }
895
896 fn float_erf(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
897 unary::erf(tensor)
898 }
899
900 fn float_argmax(
901 tensor: FloatTensor<Flex>,
902 dim: usize,
903 out_dtype: burn_std::IntDType,
904 ) -> IntTensor<Flex> {
905 let result = crate::ops::reduce::argmax(tensor, dim);
906 if result.dtype() != DType::from(out_dtype) {
907 Flex::int_cast(result, out_dtype)
908 } else {
909 result
910 }
911 }
912
913 fn float_argmin(
914 tensor: FloatTensor<Flex>,
915 dim: usize,
916 out_dtype: burn_std::IntDType,
917 ) -> IntTensor<Flex> {
918 let result = crate::ops::reduce::argmin(tensor, dim);
919 if result.dtype() != DType::from(out_dtype) {
920 Flex::int_cast(result, out_dtype)
921 } else {
922 result
923 }
924 }
925
926 fn float_expand(tensor: FloatTensor<Flex>, shape: Shape) -> FloatTensor<Flex> {
927 crate::ops::expand::expand(tensor, shape)
928 }
929
930 fn float_unfold(
931 tensor: FloatTensor<Flex>,
932 dim: usize,
933 size: usize,
934 step: usize,
935 ) -> FloatTensor<Flex> {
936 crate::ops::unfold::unfold(tensor, dim, size, step)
938 }
939
940 fn float_grid_sample_2d(
941 tensor: FloatTensor<Flex>,
942 grid: FloatTensor<Flex>,
943 options: GridSampleOptions,
944 ) -> FloatTensor<Flex> {
945 crate::ops::grid_sample::grid_sample_2d(tensor, grid, options)
946 }
947
948 fn float_zeros(shape: Shape, _device: &Device<Flex>, dtype: FloatDType) -> FloatTensor<Flex> {
949 FlexTensor::zeros(shape, dtype.into())
950 }
951
952 fn float_ones(shape: Shape, _device: &Device<Flex>, dtype: FloatDType) -> FloatTensor<Flex> {
953 let dt: burn_backend::DType = dtype.into();
954 match dt {
955 DType::F32 => FlexTensor::filled_typed(shape, dt, 1.0f32),
956 DType::F64 => FlexTensor::filled_typed(shape, dt, 1.0f64),
957 DType::F16 => FlexTensor::filled_typed(shape, dt, f16::ONE),
958 DType::BF16 => FlexTensor::filled_typed(shape, dt, bf16::ONE),
959 _ => unreachable!(),
960 }
961 }
962
963 fn float_full(
964 shape: Shape,
965 fill_value: Scalar,
966 _device: &Device<Flex>,
967 dtype: FloatDType,
968 ) -> FloatTensor<Flex> {
969 let dt: burn_backend::DType = dtype.into();
970 match dt {
971 DType::F32 => FlexTensor::filled_typed(shape, dt, fill_value.to_f32().unwrap()),
972 DType::F64 => FlexTensor::filled_typed(shape, dt, fill_value.to_f64().unwrap()),
973 DType::F16 => {
974 FlexTensor::filled_typed(shape, dt, f16::from_f32(fill_value.to_f32().unwrap()))
975 }
976 DType::BF16 => {
977 FlexTensor::filled_typed(shape, dt, bf16::from_f32(fill_value.to_f32().unwrap()))
978 }
979 _ => unreachable!(),
980 }
981 }
982
983 fn float_transpose(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
984 let ndims = tensor.layout().num_dims();
985 if ndims < 2 {
986 return tensor;
987 }
988 tensor.transpose(ndims - 2, ndims - 1)
989 }
990
991 fn float_repeat_dim(tensor: FloatTensor<Flex>, dim: usize, times: usize) -> FloatTensor<Flex> {
992 crate::ops::repeat_dim::repeat_dim(tensor, dim, times)
993 }
994
995 fn float_sort(tensor: FloatTensor<Flex>, dim: usize, descending: bool) -> FloatTensor<Flex> {
996 crate::ops::sort::sort(tensor, dim, descending)
997 }
998
999 fn float_sort_with_indices(
1000 tensor: FloatTensor<Flex>,
1001 dim: usize,
1002 descending: bool,
1003 indices_dtype: burn_std::IntDType,
1004 ) -> (FloatTensor<Flex>, IntTensor<Flex>) {
1005 let (values, indices) = crate::ops::sort::sort_with_indices(tensor, dim, descending);
1006 let indices = if indices.dtype() != DType::from(indices_dtype) {
1007 Flex::int_cast(indices, indices_dtype)
1008 } else {
1009 indices
1010 };
1011 (values, indices)
1012 }
1013
1014 fn float_argsort(
1015 tensor: FloatTensor<Flex>,
1016 dim: usize,
1017 descending: bool,
1018 out_dtype: burn_std::IntDType,
1019 ) -> IntTensor<Flex> {
1020 let indices = crate::ops::sort::argsort(tensor, dim, descending);
1021 if indices.dtype() != DType::from(out_dtype) {
1022 Flex::int_cast(indices, out_dtype)
1023 } else {
1024 indices
1025 }
1026 }
1027
1028 fn float_powi(lhs: FloatTensor<Flex>, rhs: IntTensor<Flex>) -> FloatTensor<Flex> {
1029 let dtype = lhs.dtype();
1030 Self::float_powf(lhs, Flex::int_into_float(rhs, dtype.into()))
1031 }
1032
1033 fn float_powi_scalar(lhs: FloatTensor<Flex>, rhs: Scalar) -> FloatTensor<Flex> {
1034 match rhs.to_i64().unwrap() {
1035 0 => Self::float_ones(lhs.shape(), &Default::default(), lhs.dtype().into()),
1036 1 => lhs,
1037 2 => Self::float_mul(lhs.clone(), lhs),
1038 -1 => Self::float_recip(lhs),
1039 -2 => Self::float_recip(Self::float_mul(lhs.clone(), lhs)),
1040 _ => Self::float_powf_scalar_impl(lhs, rhs),
1041 }
1042 }
1043
1044 fn float_powf_scalar(tensor: FloatTensor<Flex>, value: Scalar) -> FloatTensor<Flex> {
1045 if let Some(exp) = value.try_as_integer() {
1046 Self::float_powi_scalar(tensor, exp)
1047 } else {
1048 Self::float_powf_scalar_impl(tensor, value)
1049 }
1050 }
1051
1052 fn float_max_abs(tensor: FloatTensor<Flex>) -> FloatTensor<Flex> {
1053 let abs = unary::abs(tensor);
1054 crate::ops::reduce::max(abs)
1055 }
1056
1057 fn float_max_abs_dim(tensor: FloatTensor<Flex>, dim: usize) -> FloatTensor<Flex> {
1058 let abs = unary::abs(tensor);
1059 crate::ops::reduce::max_dim(abs, dim)
1060 }
1061
1062 fn float_is_nan(tensor: FloatTensor<Flex>, out_dtype: burn_std::BoolDType) -> BoolTensor<Flex> {
1063 unary::float_predicate(tensor, out_dtype, |x: f32| x.is_nan(), |x: f64| x.is_nan())
1064 }
1065
1066 fn float_is_inf(tensor: FloatTensor<Flex>, out_dtype: burn_std::BoolDType) -> BoolTensor<Flex> {
1067 unary::float_predicate(
1068 tensor,
1069 out_dtype,
1070 |x: f32| x.is_infinite(),
1071 |x: f64| x.is_infinite(),
1072 )
1073 }
1074
1075 fn float_hypot(lhs: FloatTensor<Flex>, rhs: FloatTensor<Flex>) -> FloatTensor<Flex> {
1076 binary_op(
1077 lhs,
1078 rhs,
1079 |a: f32, b| a.hypot(b),
1080 |a: f64, b| a.hypot(b),
1081 None,
1082 )
1083 }
1084}
1085
1086#[cfg(test)]
1095mod tests {
1096 use burn_backend::TensorData;
1097
1098 use crate::Flex;
1099
1100 #[test]
1101 fn test_float_into_int_i32() {
1102 use burn_backend::ops::FloatTensorOps;
1103 use burn_std::IntDType;
1104
1105 let t = crate::FlexTensor::from_data(TensorData::from([1.5f32, -2.7, 0.0, 255.9]));
1106 let result = Flex::float_into_int(t, IntDType::I32);
1107 assert_eq!(result.dtype(), burn_backend::DType::I32);
1108 let data: Vec<i32> = result.into_data().to_vec().unwrap();
1109 assert_eq!(data, vec![1, -2, 0, 255]);
1110 }
1111
1112 #[test]
1113 fn test_float_into_int_u8() {
1114 use burn_backend::ops::FloatTensorOps;
1115 use burn_std::IntDType;
1116
1117 let t = crate::FlexTensor::from_data(TensorData::from([0.0f32, 1.9, 127.5, 255.0]));
1118 let result = Flex::float_into_int(t, IntDType::U8);
1119 assert_eq!(result.dtype(), burn_backend::DType::U8);
1120 let data: Vec<u8> = result.into_data().to_vec().unwrap();
1121 assert_eq!(data, vec![0, 1, 127, 255]);
1122 }
1123
1124 #[test]
1125 fn test_float_argmax_i32_out_dtype() {
1126 use burn_backend::ops::FloatTensorOps;
1127 use burn_std::IntDType;
1128
1129 let t = crate::FlexTensor::from_data(TensorData::from([[1.0f32, 3.0, 2.0]]));
1130 let result = Flex::float_argmax(t, 1, IntDType::I32);
1131 assert_eq!(result.dtype(), burn_backend::DType::I32);
1132 let data: Vec<i32> = result.into_data().to_vec().unwrap();
1133 assert_eq!(data, vec![1]);
1134 }
1135
1136 #[test]
1137 fn test_float_argmin_i32_out_dtype() {
1138 use burn_backend::ops::FloatTensorOps;
1139 use burn_std::IntDType;
1140
1141 let t = crate::FlexTensor::from_data(TensorData::from([[3.0f32, 1.0, 2.0]]));
1142 let result = Flex::float_argmin(t, 1, IntDType::I32);
1143 assert_eq!(result.dtype(), burn_backend::DType::I32);
1144 let data: Vec<i32> = result.into_data().to_vec().unwrap();
1145 assert_eq!(data, vec![1]);
1146 }
1147
1148 #[test]
1149 fn test_float_argmax_i64_out_dtype() {
1150 use burn_backend::ops::FloatTensorOps;
1151 use burn_std::IntDType;
1152
1153 let t = crate::FlexTensor::from_data(TensorData::from([[1.0f32, 3.0, 2.0]]));
1154 let result = Flex::float_argmax(t, 1, IntDType::I64);
1155 assert_eq!(result.dtype(), burn_backend::DType::I64);
1156 let data: Vec<i64> = result.into_data().to_vec().unwrap();
1157 assert_eq!(data, vec![1]);
1158 }
1159
1160 #[test]
1161 fn test_float_max_dim_with_indices_i32() {
1162 use burn_backend::ops::FloatTensorOps;
1163 use burn_std::IntDType;
1164
1165 let t = crate::FlexTensor::from_data(TensorData::from([[1.0f32, 5.0], [3.0, 2.0]]));
1166 let (values, indices) = Flex::float_max_dim_with_indices(t, 1, IntDType::I32);
1167 assert_eq!(indices.dtype(), burn_backend::DType::I32);
1168 let idx: Vec<i32> = indices.into_data().to_vec().unwrap();
1169 assert_eq!(idx, vec![1, 0]);
1170 let vals: Vec<f32> = values.into_data().to_vec().unwrap();
1171 assert_eq!(vals, vec![5.0, 3.0]);
1172 }
1173
1174 #[test]
1175 fn test_float_min_dim_with_indices_i32() {
1176 use burn_backend::ops::FloatTensorOps;
1177 use burn_std::IntDType;
1178
1179 let t = crate::FlexTensor::from_data(TensorData::from([[1.0f32, 5.0], [3.0, 2.0]]));
1180 let (values, indices) = Flex::float_min_dim_with_indices(t, 1, IntDType::I32);
1181 assert_eq!(indices.dtype(), burn_backend::DType::I32);
1182 let idx: Vec<i32> = indices.into_data().to_vec().unwrap();
1183 assert_eq!(idx, vec![0, 1]);
1184 let vals: Vec<f32> = values.into_data().to_vec().unwrap();
1185 assert_eq!(vals, vec![1.0, 2.0]);
1186 }
1187
1188 #[test]
1189 fn test_float_random_f64() {
1190 use burn_backend::{DType, FloatDType, ops::FloatTensorOps};
1191
1192 let shape = burn_std::Shape::from(vec![100]);
1193 let dist = burn_backend::Distribution::Uniform(0.0, 1.0);
1194 let device = crate::FlexDevice;
1195 let t = Flex::float_random(shape, dist, &device, FloatDType::F64);
1196 assert_eq!(t.dtype(), DType::F64);
1197 let data: Vec<f64> = t.into_data().to_vec().unwrap();
1198 assert!(data.iter().all(|&v| (0.0..=1.0).contains(&v)));
1199 }
1200
1201 #[test]
1202 fn test_float_random_f16() {
1203 use burn_backend::{DType, FloatDType, ops::FloatTensorOps};
1204
1205 let shape = burn_std::Shape::from(vec![100]);
1206 let dist = burn_backend::Distribution::Uniform(0.0, 1.0);
1207 let device = crate::FlexDevice;
1208 let t = Flex::float_random(shape, dist, &device, FloatDType::F16);
1209 assert_eq!(t.dtype(), DType::F16);
1210 }
1211}