1use crate::ndarray;
13
14use crate::graph::AsGraph;
15use crate::ndarray_ext::{ArrayRng, NdArray};
16use crate::tensor::{AsTensor, Tensor};
17use crate::Float;
18use scirs2_core::random::{Rng, RngExt};
19
20use scirs2_core::ndarray::{Array1, ArrayView1, ArrayView2, ArrayViewMut2};
22#[cfg(feature = "simd")]
23use scirs2_core::simd::{
24 simd_add_f32_adaptive, simd_dot_f32_ultra, simd_fma_f32_ultra, simd_mul_f32_hyperoptimized,
25};
26use scirs2_core::simd_ops::{PlatformCapabilities, SimdUnifiedOps};
27
28pub(crate) type BlasIF = i32;
31pub(crate) type MklInt = BlasIF;
32
33#[allow(dead_code)]
35pub(crate) const CBLAS_ROW_MAJOR: i32 = 101;
36#[allow(dead_code)]
37pub(crate) const CBLAS_NO_TRANS: i32 = 111;
38#[allow(dead_code)]
39pub(crate) const CBLAS_TRANS: i32 = 112;
40
41#[allow(dead_code)]
52pub(crate) unsafe fn cblas_sgemm_simd_ultra(
53 _layout: i32,
54 _transa: i32,
55 _transb: i32,
56 m: BlasIF,
57 n: BlasIF,
58 k: BlasIF,
59 alpha: f32,
60 a: *const f32,
61 lda: BlasIF,
62 b: *const f32,
63 ldb: BlasIF,
64 beta: f32,
65 c: *mut f32,
66 ldc: BlasIF,
67) {
68 let m_usize = m as usize;
69 let n_usize = n as usize;
70 let k_usize = k as usize;
71
72 let caps = PlatformCapabilities::detect();
74
75 if m_usize >= 256 && n_usize >= 256 && k_usize >= 256 && caps.has_avx2() {
77 cblas_sgemm_large_simd_ultra(m, n, k, alpha, a, lda, b, ldb, beta, c, ldc);
79 } else if m_usize >= 64 && n_usize >= 64 && caps.has_sse() {
80 cblas_sgemm_medium_simd(m, n, k, alpha, a, lda, b, ldb, beta, c, ldc);
82 } else {
83 cblas_sgemm_fallback(m, n, k, alpha, a, lda, b, ldb, beta, c, ldc);
85 }
86}
87
88unsafe fn cblas_sgemm_large_simd_ultra(
90 m: BlasIF,
91 n: BlasIF,
92 k: BlasIF,
93 alpha: f32,
94 a: *const f32,
95 lda: BlasIF,
96 b: *const f32,
97 ldb: BlasIF,
98 beta: f32,
99 c: *mut f32,
100 ldc: BlasIF,
101) {
102 let m_usize = m as usize;
103 let n_usize = n as usize;
104 let k_usize = k as usize;
105
106 const TILE_SIZE: usize = 64; for i_tile in (0..m_usize).step_by(TILE_SIZE) {
110 for j_tile in (0..n_usize).step_by(TILE_SIZE) {
111 let i_end = (i_tile + TILE_SIZE).min(m_usize);
112 let j_end = (j_tile + TILE_SIZE).min(n_usize);
113
114 for i in i_tile..i_end {
116 for j in j_tile..j_end {
117 let c_offset = i * ldc as usize + j;
118
119 let mut sum = 0.0f32;
121
122 if k_usize >= 16 {
124 let mut a_row = Vec::with_capacity(k_usize);
126 let mut b_col = Vec::with_capacity(k_usize);
127
128 for ki in 0..k_usize {
129 a_row.push(*a.add(i * lda as usize + ki));
130 b_col.push(*b.add(ki * ldb as usize + j));
131 }
132
133 let a_array = Array1::from_vec(a_row);
135 let b_array = Array1::from_vec(b_col);
136 #[cfg(feature = "simd")]
137 {
138 sum = simd_dot_f32_ultra(&a_array.view(), &b_array.view());
139 }
140 #[cfg(not(feature = "simd"))]
141 {
142 sum = a_array
144 .iter()
145 .zip(b_array.iter())
146 .map(|(&a, &b)| a * b)
147 .sum();
148 }
149 } else {
150 for ki in 0..k_usize {
152 sum += *a.add(i * lda as usize + ki) * *b.add(ki * ldb as usize + j);
153 }
154 }
155
156 let c_ptr = c.add(c_offset);
158 if beta == 0.0 {
159 *c_ptr = alpha * sum;
160 } else {
161 *c_ptr = alpha * sum + beta * *c_ptr;
162 }
163 }
164 }
165 }
166 }
167}
168
169unsafe fn cblas_sgemm_medium_simd(
171 m: BlasIF,
172 n: BlasIF,
173 k: BlasIF,
174 alpha: f32,
175 a: *const f32,
176 lda: BlasIF,
177 b: *const f32,
178 ldb: BlasIF,
179 beta: f32,
180 c: *mut f32,
181 ldc: BlasIF,
182) {
183 let m_usize = m as usize;
184 let n_usize = n as usize;
185 let k_usize = k as usize;
186
187 const TILE_SIZE: usize = 32;
189
190 for i_tile in (0..m_usize).step_by(TILE_SIZE) {
191 for j_tile in (0..n_usize).step_by(TILE_SIZE) {
192 let i_end = (i_tile + TILE_SIZE).min(m_usize);
193 let j_end = (j_tile + TILE_SIZE).min(n_usize);
194
195 for i in i_tile..i_end {
196 for j in j_tile..j_end {
197 let c_offset = i * ldc as usize + j;
198 let mut sum = 0.0f32;
199
200 if k_usize >= 8 {
202 let mut products = Vec::with_capacity(k_usize);
203 for ki in 0..k_usize {
204 products.push(
205 *a.add(i * lda as usize + ki) * *b.add(ki * ldb as usize + j),
206 );
207 }
208
209 let products_array = Array1::from_vec(products);
211 sum = f32::simd_sum(&products_array.view());
212 } else {
213 for ki in 0..k_usize {
214 sum += *a.add(i * lda as usize + ki) * *b.add(ki * ldb as usize + j);
215 }
216 }
217
218 let c_ptr = c.add(c_offset);
219 if beta == 0.0 {
220 *c_ptr = alpha * sum;
221 } else {
222 *c_ptr = alpha * sum + beta * *c_ptr;
223 }
224 }
225 }
226 }
227 }
228}
229
230unsafe fn cblas_sgemm_fallback(
232 m: BlasIF,
233 n: BlasIF,
234 k: BlasIF,
235 alpha: f32,
236 a: *const f32,
237 lda: BlasIF,
238 b: *const f32,
239 ldb: BlasIF,
240 beta: f32,
241 c: *mut f32,
242 ldc: BlasIF,
243) {
244 let a_slice = std::slice::from_raw_parts(a, (m * k) as usize);
245 let b_slice = std::slice::from_raw_parts(b, (k * n) as usize);
246 let c_slice = std::slice::from_raw_parts_mut(c, (m * n) as usize);
247
248 let a_mat =
249 ArrayView2::from_shape((m as usize, k as usize), a_slice).expect("Operation failed");
250 let b_mat =
251 ArrayView2::from_shape((k as usize, n as usize), b_slice).expect("Operation failed");
252 let mut c_mat =
253 ArrayViewMut2::from_shape((m as usize, n as usize), c_slice).expect("Operation failed");
254
255 if beta == 0.0 {
256 c_mat.fill(0.0);
257 } else if beta != 1.0 {
258 c_mat.mapv_inplace(|x| x * beta);
259 }
260
261 let result = alpha * a_mat.dot(&b_mat);
262 c_mat += &result;
263}
264
265#[allow(dead_code)]
267pub(crate) unsafe fn cblas_sgemm(
268 layout: i32,
269 transa: i32,
270 transb: i32,
271 m: BlasIF,
272 n: BlasIF,
273 k: BlasIF,
274 alpha: f32,
275 a: *const f32,
276 lda: BlasIF,
277 b: *const f32,
278 ldb: BlasIF,
279 beta: f32,
280 c: *mut f32,
281 ldc: BlasIF,
282) {
283 cblas_sgemm_simd_ultra(
285 layout, transa, transb, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc,
286 );
287}
288
289#[allow(dead_code)]
290pub(crate) unsafe fn cblas_dgemm(
291 _layout: i32,
292 _transa: i32,
293 _transb: i32,
294 m: BlasIF,
295 n: BlasIF,
296 k: BlasIF,
297 alpha: f64,
298 a: *const f64,
299 lda: BlasIF,
300 b: *const f64,
301 ldb: BlasIF,
302 beta: f64,
303 c: *mut f64,
304 ldc: BlasIF,
305) {
306 let a_slice = std::slice::from_raw_parts(a, (m * k) as usize);
308 let b_slice = std::slice::from_raw_parts(b, (k * n) as usize);
309 let c_slice = std::slice::from_raw_parts_mut(c, (m * n) as usize);
310
311 let a_mat = scirs2_core::ndarray::ArrayView2::from_shape((m as usize, k as usize), a_slice)
313 .expect("Operation failed");
314 let b_mat = scirs2_core::ndarray::ArrayView2::from_shape((k as usize, n as usize), b_slice)
315 .expect("Operation failed");
316 let mut c_mat =
317 scirs2_core::ndarray::ArrayViewMut2::from_shape((m as usize, n as usize), c_slice)
318 .expect("Operation failed");
319
320 if beta == 0.0 {
322 c_mat.fill(0.0);
323 } else if beta != 1.0 {
324 c_mat.mapv_inplace(|x| x * beta);
325 }
326
327 let result = alpha * a_mat.dot(&b_mat);
328 c_mat += &result;
329}
330
331#[allow(dead_code)]
333#[allow(non_snake_case)]
334pub(crate) unsafe fn vsAdd(n: MklInt, a: *const f32, b: *const f32, y: *mut f32) {
335 let a_slice = std::slice::from_raw_parts(a, n as usize);
336 let b_slice = std::slice::from_raw_parts(b, n as usize);
337 let y_slice = std::slice::from_raw_parts_mut(y, n as usize);
338
339 for i in 0..n as usize {
340 y_slice[i] = a_slice[i] + b_slice[i];
341 }
342}
343
344#[allow(dead_code)]
345#[allow(non_snake_case)]
346pub(crate) unsafe fn vdAdd(n: MklInt, a: *const f64, b: *const f64, y: *mut f64) {
347 let a_slice = std::slice::from_raw_parts(a, n as usize);
348 let b_slice = std::slice::from_raw_parts(b, n as usize);
349 let y_slice = std::slice::from_raw_parts_mut(y, n as usize);
350
351 for i in 0..n as usize {
352 y_slice[i] = a_slice[i] + b_slice[i];
353 }
354}
355
356#[allow(dead_code)]
357#[allow(non_snake_case)]
358pub(crate) unsafe fn vsMul(n: MklInt, a: *const f32, b: *const f32, y: *mut f32) {
359 let a_slice = std::slice::from_raw_parts(a, n as usize);
360 let b_slice = std::slice::from_raw_parts(b, n as usize);
361 let y_slice = std::slice::from_raw_parts_mut(y, n as usize);
362
363 for i in 0..n as usize {
364 y_slice[i] = a_slice[i] * b_slice[i];
365 }
366}
367
368#[allow(dead_code)]
369#[allow(non_snake_case)]
370pub(crate) unsafe fn vdMul(n: MklInt, a: *const f64, b: *const f64, y: *mut f64) {
371 let a_slice = std::slice::from_raw_parts(a, n as usize);
372 let b_slice = std::slice::from_raw_parts(b, n as usize);
373 let y_slice = std::slice::from_raw_parts_mut(y, n as usize);
374
375 for i in 0..n as usize {
376 y_slice[i] = a_slice[i] * b_slice[i];
377 }
378}
379
380#[allow(dead_code)]
381#[allow(non_snake_case)]
382pub(crate) unsafe fn vsExp(n: MklInt, a: *const f32, y: *mut f32) {
383 let a_slice = std::slice::from_raw_parts(a, n as usize);
384 let y_slice = std::slice::from_raw_parts_mut(y, n as usize);
385
386 for i in 0..n as usize {
387 y_slice[i] = a_slice[i].exp();
388 }
389}
390
391#[allow(dead_code)]
392#[allow(non_snake_case)]
393pub(crate) unsafe fn vdExp(n: MklInt, a: *const f64, y: *mut f64) {
394 let a_slice = std::slice::from_raw_parts(a, n as usize);
395 let y_slice = std::slice::from_raw_parts_mut(y, n as usize);
396
397 for i in 0..n as usize {
398 y_slice[i] = a_slice[i].exp();
399 }
400}
401
402#[allow(dead_code)]
403#[allow(non_snake_case)]
404pub(crate) unsafe fn vsLn(n: MklInt, a: *const f32, y: *mut f32) {
405 let a_slice = std::slice::from_raw_parts(a, n as usize);
406 let y_slice = std::slice::from_raw_parts_mut(y, n as usize);
407
408 for i in 0..n as usize {
409 y_slice[i] = a_slice[i].ln();
410 }
411}
412
413#[allow(dead_code)]
414#[allow(non_snake_case)]
415pub(crate) unsafe fn vdLn(n: MklInt, a: *const f64, y: *mut f64) {
416 let a_slice = std::slice::from_raw_parts(a, n as usize);
417 let y_slice = std::slice::from_raw_parts_mut(y, n as usize);
418
419 for i in 0..n as usize {
420 y_slice[i] = a_slice[i].ln();
421 }
422}
423
424#[allow(dead_code)]
425#[allow(non_snake_case)]
426pub(crate) unsafe fn vsTanh(n: MklInt, a: *const f32, y: *mut f32) {
427 let a_slice = std::slice::from_raw_parts(a, n as usize);
428 let y_slice = std::slice::from_raw_parts_mut(y, n as usize);
429
430 for i in 0..n as usize {
431 y_slice[i] = a_slice[i].tanh();
432 }
433}
434
435#[allow(dead_code)]
436#[allow(non_snake_case)]
437pub(crate) unsafe fn vdTanh(n: MklInt, a: *const f64, y: *mut f64) {
438 let a_slice = std::slice::from_raw_parts(a, n as usize);
439 let y_slice = std::slice::from_raw_parts_mut(y, n as usize);
440
441 for i in 0..n as usize {
442 y_slice[i] = a_slice[i].tanh();
443 }
444}
445
446pub mod activation;
448pub mod arithmetic;
449pub mod linear_algebra;
450pub mod reduction;
451
452mod activation_ops;
454pub(crate) mod array_ops;
455pub(crate) mod basic_source_ops;
456pub(crate) mod binary_ops;
457pub(crate) mod const_gen_ops;
459mod conv_ops;
460pub(crate) mod dot_ops;
461pub(crate) mod gradient_descent_ops;
462mod gradient_ops;
463mod graph_ops;
464pub(crate) mod higher_order_ops;
465pub(crate) mod hook_ops;
466pub(crate) mod math_ops;
467mod random_ops;
468pub(crate) mod reduction_ops;
469mod xent_ops;
470
471pub(crate) mod decomposition_backward;
473pub(crate) mod decomposition_ops;
474mod eigen_ops;
475mod linalg_ops;
476pub(crate) mod matrix_calculus;
478mod matrix_ops;
480mod norm_ops;
481pub(crate) mod scalar_ops;
482pub(crate) mod solver_ops;
483mod special_matrices;
484
485mod advanced_tensor_ops;
487mod matrix_norms;
488mod matrix_solvers;
489mod special_decompositions;
490mod symmetric_ops;
491
492mod advanced_decompositions;
494mod iterative_solvers;
495mod matrix_functions;
496mod matrix_trig_functions;
497
498mod checkpoint_ops;
500
501mod debug_ops;
503
504mod advanced_indexing;
506
507mod broadcast_ops;
509
510mod memory_optimization;
512
513pub(crate) mod efficient_ops;
515
516mod custom_activations;
518
519mod performance_ops;
521
522mod graph_enhancements;
524
525mod numerical_props;
527
528pub(crate) mod kronecker_ops;
530
531#[cfg(feature = "simd")]
533pub mod simd_ops;
534
535impl<'graph, F: Float> Tensor<'graph, F> {
540 pub fn access_elem(self, i: isize) -> Tensor<'graph, F> {
556 let op = array_ops::IndexOp { index: i };
557 Tensor::builder(self.graph)
558 .append_input(self, false)
559 .build(op)
560 }
561}
562
563#[allow(dead_code)]
608pub fn grad<'graph, F: Float, A, B>(ys: &[A], xs: &[B]) -> Vec<Tensor<'graph, F>>
609where
610 A: AsRef<Tensor<'graph, F>>,
611 B: AsRef<Tensor<'graph, F>>,
612{
613 use crate::gradient::compute_gradients;
614
615 let g = ys[0].as_ref().graph();
616 let _ys: Vec<_> = ys.iter().map(|y| sum_all(y)).collect();
617 let mut grads = compute_gradients(_ys.as_slice(), xs, None, g);
618 let mut ret = Vec::with_capacity(xs.len());
619 for x in xs {
620 if let Some(gx) = grads.extract_grad(x) {
621 ret.push(gx);
622 } else {
623 let zero_tensor = crate::tensor_ops::arithmetic::mul(x.as_ref(), scalar(F::zero(), g));
626 ret.push(zero_tensor);
627 }
628 }
629 ret
630}
631
632#[allow(dead_code)]
647pub fn grad_with_default<'graph, F: Float, A, B>(
648 ys: &[A],
649 xs: &[B],
650 ys_grads: &[Tensor<'graph, F>],
651) -> Vec<Tensor<'graph, F>>
652where
653 A: AsRef<Tensor<'graph, F>>,
654 B: AsRef<Tensor<'graph, F>>,
655{
656 use crate::gradient::compute_gradients;
657
658 let g = ys[0].as_ref().graph();
659 let mut grads = compute_gradients(ys, xs, Some(ys_grads), g);
660 let mut ret = Vec::with_capacity(xs.len());
661 for x in xs {
662 if let Some(gx) = grads.extract_grad(x) {
663 ret.push(gx);
664 } else {
665 let zero_tensor = crate::tensor_ops::arithmetic::mul(x.as_ref(), scalar(F::zero(), g));
668 ret.push(zero_tensor);
669 }
670 }
671 ret
672}
673
674#[allow(dead_code)]
709pub fn jacobians<'graph, A, B, F: Float>(
710 y_: A,
711 xs_: &[B],
712 objective_len: usize,
713) -> Vec<Tensor<'graph, F>>
714where
715 A: AsRef<Tensor<'graph, F>>,
716 B: AsRef<Tensor<'graph, F>>,
717{
718 let y = y_.as_ref();
719 let mut vec_vec = Vec::with_capacity(objective_len);
720 for i in 0..objective_len as isize {
721 vec_vec.push(grad(&[y.access_elem(i)], xs_));
722 }
723
724 let _len = xs_.len();
725 let mut ret = Vec::with_capacity(_len);
726 for i in 0.._len {
728 let mut jac = Vec::with_capacity(objective_len);
730 for vec in &vec_vec {
731 jac.push(expand_dims(flatten(vec[i]), &[0]));
732 }
733 ret.push(concat(&jac, 0));
735 }
736 ret
737}
738
739#[allow(dead_code)]
741pub fn _hessian_vector_product<'graph, A, B, C, F: Float>(
742 ys: &[A],
743 xs: &[B],
744 vectors: &[C],
745) -> Vec<Tensor<'graph, F>>
746where
747 A: AsRef<Tensor<'graph, F>>,
748 B: AsRef<Tensor<'graph, F>>,
749 C: AsRef<Tensor<'graph, F>>,
750{
751 let grads = grad(ys, xs);
752 let products = grads
753 .into_iter()
754 .zip(vectors)
755 .map(|(g, v)| *g.as_ref() * *v.as_ref())
756 .collect::<Vec<_>>();
757 grad(products.as_slice(), xs)
758}
759
760#[allow(dead_code)]
765pub fn stop_gradient<'graph, A, F: Float>(x: A) -> Tensor<'graph, F>
766where
767 A: AsRef<Tensor<'graph, F>> + Copy,
768{
769 let x = x.as_ref();
770 let g = x.graph();
771 Tensor::builder(g)
772 .append_input(x, false)
773 .set_differentiable(false)
774 .build(gradient_ops::StopGradient)
775}
776
777#[allow(dead_code)]
790pub fn shape<'graph, A, F: Float>(x: A) -> Tensor<'graph, F>
791where
792 A: AsRef<Tensor<'graph, F>> + Copy,
793{
794 let x = x.as_ref();
795 let g = x.graph();
796 if let Some(id) = x.inner().shape {
797 return g.tensor(id);
798 }
799 Tensor::builder(g)
800 .append_input(x.as_ref(), false)
801 .set_differentiable(false)
802 .build(array_ops::Shape)
803}
804
805#[allow(dead_code)]
820pub fn size<'graph, A, F: Float>(x: A) -> Tensor<'graph, F>
821where
822 A: AsRef<Tensor<'graph, F>> + Copy,
823{
824 let x = x.as_ref();
825 let g = x.graph();
826 Tensor::builder(g)
827 .append_input(x.as_ref(), false)
828 .set_differentiable(false)
829 .build(array_ops::Size)
830}
831
832#[allow(dead_code)]
846pub fn rank<'graph, A, F: Float>(x: A) -> Tensor<'graph, F>
847where
848 A: AsRef<Tensor<'graph, F>> + Copy,
849{
850 let x = x.as_ref();
851 let g = x.graph();
852 Tensor::builder(g)
853 .append_input(x.as_ref(), false)
854 .set_differentiable(false)
855 .build(array_ops::Rank)
856}
857
858#[doc(hidden)]
859#[allow(dead_code)]
864pub fn nth_tensor<'graph, A, F: Float>(x: A, n: usize) -> Tensor<'graph, F>
865where
866 A: AsRef<Tensor<'graph, F>> + Copy,
867{
868 let x = x.as_ref();
869 let g = x.graph();
870 Tensor::builder(g)
871 .append_input_with_selector(x, false, n)
872 .build(activation_ops::Identity)
873}
874
875#[allow(dead_code)]
877pub fn identity<'graph, A, F: Float>(x: A) -> Tensor<'graph, F>
878where
879 A: AsRef<Tensor<'graph, F>> + Copy,
880{
881 let x = x.as_ref();
882 let g = x.graph();
883 Tensor::builder(g)
884 .append_input(x.as_ref(), false)
885 .setshape(&shape(x))
886 .build(activation_ops::Identity)
887}
888
889#[allow(dead_code)]
910pub fn setdiff1d<'graph, A, B, F: Float>(a: A, b: B) -> Tensor<'graph, F>
911where
912 A: AsRef<Tensor<'graph, F>> + Copy,
913 B: AsRef<Tensor<'graph, F>> + Copy,
914{
915 let a = a.as_ref();
916 let g = a.graph();
917 let op = array_ops::SetDiff1D;
918 Tensor::builder(g)
919 .append_input(a.as_ref(), false)
920 .append_input(b.as_ref(), false)
921 .build(op)
922}
923
924#[allow(dead_code)]
956pub fn slice<'graph, A, S, E, F: Float>(x: A, starts: S, ends: E) -> Tensor<'graph, F>
957where
958 A: AsRef<Tensor<'graph, F>> + Copy,
959 S: AsRef<[isize]>,
960 E: AsRef<[isize]>,
961{
962 let x = x.as_ref();
963 let g = x.graph();
964 let starts = starts.as_ref();
965 let ends = ends.as_ref();
966 assert_eq!(starts.len(), ends.len());
967 let starts_ends = starts.iter().zip(ends.iter());
968
969 let indices = starts_ends
970 .map(|(s, &e)| {
971 let e = if e == -1 {
972 None
973 } else {
974 Some(if e < -1 { e + 1 } else { e })
975 };
976 let slice = scirs2_core::ndarray::Slice::new(*s, e, 1);
977 scirs2_core::ndarray::SliceInfoElem::from(slice)
978 })
979 .collect::<Vec<scirs2_core::ndarray::SliceInfoElem>>();
980
981 Tensor::builder(g)
982 .append_input(x.as_ref(), false)
983 .build(array_ops::Slice { indices })
984}
985
986#[allow(dead_code)]
1010pub fn gather_common<'graph, A, B, F: Float>(param: A, indices: B, axis: isize) -> Tensor<'graph, F>
1011where
1012 A: AsRef<Tensor<'graph, F>> + Copy,
1013 B: AsRef<Tensor<'graph, F>> + Copy,
1014{
1015 let _param = param.as_ref();
1016 let g = _param.graph();
1017 let op = array_ops::Gather {
1018 axis,
1019 should_normalize_negative_indices: true,
1020 };
1021 Tensor::builder(g)
1022 .append_input(indices.as_ref(), false)
1023 .append_input(_param.as_ref(), false)
1024 .build(op)
1025}
1026
1027#[allow(dead_code)]
1049pub fn gather<'graph, A, B, F: Float>(param: A, indices: B, axis: isize) -> Tensor<'graph, F>
1050where
1051 A: AsRef<Tensor<'graph, F>> + Copy,
1052 B: AsRef<Tensor<'graph, F>> + Copy,
1053{
1054 let _param = param.as_ref();
1055 let g = _param.graph();
1056 let op = array_ops::Gather {
1057 axis,
1058 should_normalize_negative_indices: false,
1059 };
1060 Tensor::builder(g)
1061 .append_input(indices.as_ref(), false)
1062 .append_input(_param, false)
1063 .build(op)
1064}
1065
1066#[allow(dead_code)]
1079pub fn reshape<'graph, A, AT, F: Float>(x: A, shape: &AT) -> Tensor<'graph, F>
1080where
1081 A: AsRef<Tensor<'graph, F>> + Copy,
1082 AT: AsTensor<'graph, F>,
1083{
1084 let x = x.as_ref();
1085 let g = x.graph();
1086 let t = shape.as_tensor(g);
1087 Tensor::builder(g)
1100 .append_input(x.as_ref(), false)
1101 .append_input(t, false)
1102 .build(array_ops::Reshape)
1103}
1104
1105#[allow(dead_code)]
1118pub fn flatten<'graph, A, F: Float>(x: A) -> Tensor<'graph, F>
1119where
1120 A: AsRef<Tensor<'graph, F>> + Copy,
1121{
1122 let x = x.as_ref();
1123 let _g = x.graph();
1124 let shape_val = [-1i32];
1127 reshape(x, &shape_val)
1128}
1129
1130#[allow(dead_code)]
1143pub fn expand_dims<'graph, A, AT, F: Float>(x: A, axes: &AT) -> Tensor<'graph, F>
1144where
1145 A: AsRef<Tensor<'graph, F>> + Copy,
1146 AT: AsTensor<'graph, F>,
1147{
1148 let x = x.as_ref();
1149 let g = x.graph();
1150 Tensor::builder(g)
1151 .append_input(x.as_ref(), false)
1152 .append_input(axes.as_tensor(g), false)
1153 .build(array_ops::ExpandDims)
1154}
1155
1156#[allow(dead_code)]
1169pub fn squeeze<'graph, A, AT, F: Float>(x: A, axes: &AT) -> Tensor<'graph, F>
1170where
1171 A: AsRef<Tensor<'graph, F>> + Copy,
1172 AT: AsTensor<'graph, F>,
1173{
1174 let x = x.as_ref();
1175 let g = x.graph();
1176 Tensor::builder(g)
1177 .append_input(x.as_ref(), false)
1178 .append_input(axes.as_tensor(g), false)
1179 .build(array_ops::Squeeze)
1180}
1181
1182#[allow(dead_code)]
1189pub fn dropout<'graph, A, F: Float>(x: A, dropoutratio: F, train: bool) -> Tensor<'graph, F>
1190where
1191 A: AsRef<Tensor<'graph, F>> + Copy,
1192{
1193 dropout_rng(
1194 x,
1195 dropoutratio,
1196 train,
1197 crate::ndarray_ext::get_default_rng::<F>(),
1198 )
1199}
1200
1201#[allow(dead_code)]
1205pub fn dropout_rng<'graph, A, F: Float, R: Rng + 'static>(
1206 x: A,
1207 dropout_ratio: F,
1208 train: bool,
1209 mut rng: R,
1210) -> Tensor<'graph, F>
1211where
1212 A: AsRef<Tensor<'graph, F>> + Copy,
1213{
1214 let x = x.as_ref();
1215 let g = x.graph();
1216 let seed = rng.random::<u64>();
1218 Tensor::builder(g)
1219 .append_input(x.as_ref(), false)
1220 .build(random_ops::Dropout {
1221 train,
1222 arr_rng: ArrayRng::from_seed(seed),
1223 dropout_ratio,
1224 })
1225}
1226
1227#[allow(dead_code)]
1229pub fn map<'graph, A, F: Float>(
1230 x: A,
1231 f: fn(crate::ndarray_ext::NdArrayView<F>) -> NdArray<F>,
1232) -> Tensor<'graph, F>
1233where
1234 A: AsRef<Tensor<'graph, F>> + Copy,
1235{
1236 use std::marker::PhantomData;
1237 let x = x.as_ref();
1238 let g = x.graph();
1239 Tensor::builder(g)
1240 .append_input(x.as_ref(), false)
1241 .build(higher_order_ops::MapOp {
1242 phantom: PhantomData,
1243 f,
1244 })
1245}
1246
1247#[allow(dead_code)]
1251pub fn control_dependencies<'graph, A, F: Float>(
1252 x: Tensor<'graph, F>,
1253 deps: &[A],
1254) -> Tensor<'graph, F>
1255where
1256 A: AsRef<Tensor<'graph, F>> + Copy,
1257{
1258 let g = x.graph();
1259 if let Some(x_input) = x.get_incoming_tensor(0, g) {
1260 let mut ctrl_deps = Tensor::builder(g).append_input(x_input, false);
1261 for dep in deps {
1263 ctrl_deps = ctrl_deps.append_input(dep.as_ref(), false);
1264 }
1265 let new_x_input = ctrl_deps.build(graph_ops::ControlDependency);
1266 g.access_inner_mut(x.id).incoming_nodes[0].id = new_x_input.id;
1267 x
1268 } else {
1269 panic!("Source tensor cannot depend on any other tensors.");
1270 }
1271}
1272
1273#[allow(dead_code)]
1278pub fn assign<'graph, A, B, F: Float>(x: A, y: B) -> Tensor<'graph, F>
1279where
1280 A: AsRef<Tensor<'graph, F>> + Copy,
1281 B: AsRef<Tensor<'graph, F>> + Copy,
1282{
1283 let x = x.as_ref();
1284 let y = y.as_ref();
1285 let g = x.graph();
1286 Tensor::builder(g)
1287 .append_input(x, true)
1288 .append_input(y, false)
1289 .build(array_ops::Assign)
1290}
1291
1292#[allow(dead_code)]
1306pub fn convert_to_tensor<F: Float, D>(
1307 arr: scirs2_core::ndarray::Array<F, D>,
1308 graph: &impl AsGraph<F>,
1309) -> Tensor<F>
1310where
1311 D: scirs2_core::ndarray::Dimension,
1312{
1313 let originalshape = arr.shape().to_vec();
1315 let arr = arr.into_dyn();
1316
1317 let shape_isize: Vec<isize> = originalshape.iter().map(|&s| s as isize).collect();
1319 Tensor::builder(graph)
1320 .set_knownshape(&shape_isize)
1321 .set_differentiable(false)
1322 .build(const_gen_ops::ConvertToTensor { arr })
1323}
1324
1325#[allow(dead_code)]
1338pub fn scalar<F: Float>(val: F, graph: &impl AsGraph<F>) -> Tensor<F> {
1339 let op = const_gen_ops::Scalar { val };
1340 Tensor::builder(graph).set_knownshape(&[]).build(op)
1342}
1343
1344#[allow(dead_code)]
1346pub fn random_normal<'graph, A, F: Float>(
1347 shape: &A,
1348 mean: f64,
1349 stddev: f64,
1350 graph: &'graph impl AsGraph<F>,
1351) -> Tensor<'graph, F>
1352where
1353 A: AsTensor<'graph, F>,
1354{
1355 random_normal_rng(Default::default(), shape, mean, stddev, graph)
1356}
1357
1358#[allow(dead_code)]
1362pub fn random_normal_rng<'graph, A, F: Float>(
1363 arr_rng: ArrayRng<F>,
1364 shape: &A,
1365 mean: f64,
1366 stddev: f64,
1367 graph: &'graph impl AsGraph<F>,
1368) -> Tensor<'graph, F>
1369where
1370 A: AsTensor<'graph, F>,
1371{
1372 let t = shape.as_tensor(graph);
1373 Tensor::builder(graph)
1374 .append_input(t, false)
1375 .setshape(&t)
1376 .build(random_ops::RandomNormal::new(arr_rng, mean, stddev))
1377}
1378
1379#[allow(dead_code)]
1381pub fn random_uniform<'graph, A, F: Float>(
1382 shape: &A,
1383 min: f64,
1384 max: f64,
1385 graph: &'graph impl AsGraph<F>,
1386) -> Tensor<'graph, F>
1387where
1388 A: AsTensor<'graph, F>,
1389{
1390 random_uniform_rng(Default::default(), shape, min, max, graph)
1391}
1392
1393#[allow(dead_code)]
1397pub fn random_uniform_rng<'graph, A, F: Float>(
1398 arr_rng: ArrayRng<F>,
1399 shape: &A,
1400 min: f64,
1401 max: f64,
1402 graph: &'graph impl AsGraph<F>,
1403) -> Tensor<'graph, F>
1404where
1405 A: AsTensor<'graph, F>,
1406{
1407 let t = shape.as_tensor(graph);
1408 Tensor::builder(graph)
1409 .append_input(t, false)
1410 .setshape(&t)
1411 .build(random_ops::RandomUniform::new(arr_rng, min, max))
1412}
1413
1414#[allow(dead_code)]
1416pub fn standard_normal<'graph, A, F: Float>(
1417 shape: &A,
1418 graph: &'graph impl AsGraph<F>,
1419) -> Tensor<'graph, F>
1420where
1421 A: AsTensor<'graph, F>,
1422{
1423 standard_normal_rng(Default::default(), shape, graph)
1424}
1425
1426#[allow(dead_code)]
1430pub fn standard_normal_rng<'graph, A, F: Float>(
1431 arr_rng: ArrayRng<F>,
1432 shape: &A,
1433 graph: &'graph impl AsGraph<F>,
1434) -> Tensor<'graph, F>
1435where
1436 A: AsTensor<'graph, F>,
1437{
1438 let t = shape.as_tensor(graph);
1439 Tensor::builder(graph)
1440 .append_input(t, false)
1441 .setshape(&t)
1442 .build(random_ops::StandardNormal::new(arr_rng))
1443}
1444
1445#[allow(dead_code)]
1447pub fn standard_uniform<'graph, A, F: Float>(
1448 shape: &A,
1449 graph: &'graph impl AsGraph<F>,
1450) -> Tensor<'graph, F>
1451where
1452 A: AsTensor<'graph, F>,
1453{
1454 standard_uniform_rng(Default::default(), shape, graph)
1455}
1456
1457#[allow(dead_code)]
1461pub fn standard_uniform_rng<'graph, F: Float, A>(
1462 arr_rng: ArrayRng<F>,
1463 shape: &A,
1464 graph: &'graph impl AsGraph<F>,
1465) -> Tensor<'graph, F>
1466where
1467 A: AsTensor<'graph, F>,
1468{
1469 let t = shape.as_tensor(graph);
1470 Tensor::builder(graph)
1471 .append_input(t, false)
1472 .setshape(&t)
1473 .build(random_ops::StandardUniform::new(arr_rng))
1474}
1475
1476#[allow(dead_code)]
1478pub fn bernoulli<'graph, A, F: Float>(
1479 shape: &A,
1480 p: f64,
1481 graph: &'graph impl AsGraph<F>,
1482) -> Tensor<'graph, F>
1483where
1484 A: AsTensor<'graph, F>,
1485{
1486 bernoulli_rng(Default::default(), shape, p, graph)
1487}
1488
1489#[allow(dead_code)]
1493pub fn bernoulli_rng<'graph, A, F: Float>(
1494 arr_rng: ArrayRng<F>,
1495 shape: &A,
1496 p: f64,
1497 graph: &'graph impl AsGraph<F>,
1498) -> Tensor<'graph, F>
1499where
1500 A: AsTensor<'graph, F>,
1501{
1502 let t = shape.as_tensor(graph);
1503 Tensor::builder(graph)
1504 .append_input(t, false)
1505 .setshape(&t)
1506 .build(random_ops::Bernoulli::new(arr_rng, p))
1507}
1508
1509#[allow(dead_code)]
1511pub fn random_exp<'graph, A, F: Float>(
1512 shape: &A,
1513 lambda: f64,
1514 graph: &'graph impl AsGraph<F>,
1515) -> Tensor<'graph, F>
1516where
1517 A: AsTensor<'graph, F>,
1518{
1519 random_exp_rng(Default::default(), shape, lambda, graph)
1520}
1521
1522#[allow(dead_code)]
1526pub fn random_exp_rng<'graph, A, F: Float>(
1527 arr_rng: ArrayRng<F>,
1528 shape: &A,
1529 lambda: f64,
1530 graph: &'graph impl AsGraph<F>,
1531) -> Tensor<'graph, F>
1532where
1533 A: AsTensor<'graph, F>,
1534{
1535 let t = shape.as_tensor(graph);
1536 Tensor::builder(graph)
1537 .append_input(t, false)
1538 .setshape(&t)
1539 .build(random_ops::Exponential::new(arr_rng, lambda))
1540}
1541
1542#[allow(dead_code)]
1544pub fn random_gamma<'graph, A, F: Float>(
1545 shape: &A,
1546 shape_param: f64,
1547 scale: f64,
1548 graph: &'graph impl AsGraph<F>,
1549) -> Tensor<'graph, F>
1550where
1551 A: AsTensor<'graph, F>,
1552{
1553 random_gamma_rng(Default::default(), shape, shape_param, scale, graph)
1554}
1555
1556#[allow(dead_code)]
1560pub fn random_gamma_rng<'graph, A, F: Float>(
1561 arr_rng: ArrayRng<F>,
1562 shape: &A,
1563 shape_param: f64,
1564 scale: f64,
1565 graph: &'graph impl AsGraph<F>,
1566) -> Tensor<'graph, F>
1567where
1568 A: AsTensor<'graph, F>,
1569{
1570 let t = shape.as_tensor(graph);
1571 Tensor::builder(graph)
1572 .append_input(t, false)
1573 .setshape(&t)
1574 .build(random_ops::Gamma::new(arr_rng, shape_param, scale))
1575}
1576
1577#[allow(dead_code)]
1579pub fn log_normal<'graph, A, F: Float>(
1580 shape: &A,
1581 mean: f64,
1582 stddev: f64,
1583 graph: &'graph impl AsGraph<F>,
1584) -> Tensor<'graph, F>
1585where
1586 A: AsTensor<'graph, F>,
1587{
1588 log_normal_rng(Default::default(), shape, mean, stddev, graph)
1589}
1590
1591#[allow(dead_code)]
1595pub fn log_normal_rng<'graph, A, F: Float>(
1596 arr_rng: ArrayRng<F>,
1597 shape: &A,
1598 mean: f64,
1599 stddev: f64,
1600 graph: &'graph impl AsGraph<F>,
1601) -> Tensor<'graph, F>
1602where
1603 A: AsTensor<'graph, F>,
1604{
1605 let t = shape.as_tensor(graph);
1606 Tensor::builder(graph)
1607 .append_input(t, false)
1608 .setshape(&t)
1609 .build(random_ops::LogNormal::new(arr_rng, mean, stddev))
1610}
1611
1612#[allow(dead_code)]
1625pub fn zeros<'graph, A, F: Float>(shape: &A, graph: &'graph impl AsGraph<F>) -> Tensor<'graph, F>
1626where
1627 A: AsTensor<'graph, F>,
1628{
1629 let shape_tensor = shape.as_tensor(graph);
1630 Tensor::builder(graph)
1631 .append_input(shape_tensor, false)
1632 .build(const_gen_ops::Zeros)
1633}
1634
1635#[allow(dead_code)]
1648pub fn ones<'graph, A, F: Float>(shape: &A, graph: &'graph impl AsGraph<F>) -> Tensor<'graph, F>
1649where
1650 A: AsTensor<'graph, F>,
1651{
1652 Tensor::builder(graph)
1653 .append_input(shape.as_tensor(graph), false)
1654 .build(const_gen_ops::Ones)
1655}
1656
1657#[allow(dead_code)]
1671pub fn variable<F: Float, D>(
1672 arr: scirs2_core::ndarray::Array<F, D>,
1673 graph: &impl AsGraph<F>,
1674) -> Tensor<F>
1675where
1676 D: scirs2_core::ndarray::Dimension,
1677{
1678 let arr_dyn = arr.into_dyn();
1680
1681 Tensor::builder(graph).build(const_gen_ops::ConvertToTensor { arr: arr_dyn })
1683}
1684
1685impl<'g, F: Float> Tensor<'g, F> {
1687 #[inline]
1689 pub fn reshape<AT: AsTensor<'g, F>>(&self, shape: &AT) -> Tensor<'g, F> {
1690 reshape(self, shape)
1691 }
1692 #[inline]
1694 pub fn flatten(&self) -> Tensor<'g, F> {
1695 flatten(self)
1696 }
1697 #[inline]
1699 pub fn squeeze<AT: AsTensor<'g, F>>(&self, axes: &AT) -> Tensor<'g, F> {
1700 squeeze(self, axes)
1701 }
1702 #[inline]
1704 pub fn expand_dims<AT: AsTensor<'g, F>>(&self, axes: &AT) -> Tensor<'g, F> {
1705 expand_dims(self, axes)
1706 }
1707 #[inline]
1709 pub fn transpose<AT: AsTensor<'g, F>>(&self, axes: &AT) -> Tensor<'g, F> {
1710 transpose(self, axes)
1711 }
1712
1713 #[inline]
1715 pub fn size(&self) -> Tensor<'g, F> {
1716 size(self)
1717 }
1718 #[inline]
1720 pub fn rank(&self) -> Tensor<'g, F> {
1721 rank(self)
1722 }
1723 #[inline]
1725 pub fn shape_tensor(&self) -> Tensor<'g, F> {
1726 shape(self)
1727 }
1728
1729 #[inline]
1731 pub fn reduce_sum<AT: AsTensor<'g, F>>(&self, axes: &AT, keepdims: bool) -> Tensor<'g, F> {
1732 reduce_sum(self, axes, keepdims)
1733 }
1734 #[inline]
1736 pub fn reduce_mean<AT: AsTensor<'g, F>>(&self, axes: &AT, keepdims: bool) -> Tensor<'g, F> {
1737 reduce_mean(self, axes, keepdims)
1738 }
1739 #[inline]
1741 pub fn reduce_prod<AT: AsTensor<'g, F>>(&self, axes: &AT, keepdims: bool) -> Tensor<'g, F> {
1742 reduce_prod(self, axes, keepdims)
1743 }
1744 #[inline]
1746 pub fn reduce_min<AT: AsTensor<'g, F>>(&self, axes: &AT, keepdims: bool) -> Tensor<'g, F> {
1747 reduce_min(self, axes, keepdims)
1748 }
1749 #[inline]
1751 pub fn reduce_max<AT: AsTensor<'g, F>>(&self, axes: &AT, keepdims: bool) -> Tensor<'g, F> {
1752 reduce_max(self, axes, keepdims)
1753 }
1754 #[inline]
1756 pub fn reduce_variance<AT: AsTensor<'g, F>>(
1757 &self,
1758 axes: &AT,
1759 keep_dims: bool,
1760 ) -> Tensor<'g, F> {
1761 reduce_variance(self, axes, keep_dims)
1762 }
1763 #[inline]
1765 pub fn sum_all<AT: AsTensor<'g, F>>(&self) -> Tensor<'g, F> {
1766 sum_all(self)
1767 }
1768 #[inline]
1770 pub fn mean_all<AT: AsTensor<'g, F>>(&self) -> Tensor<'g, F> {
1771 mean_all(self)
1772 }
1773
1774 pub fn trace(&self) -> Tensor<'g, F> {
1776 trace(self)
1777 }
1778
1779 pub fn diag(&self) -> Tensor<'g, F> {
1781 extract_diag(self)
1782 }
1783
1784 pub fn frobenius_norm(&self) -> Tensor<'g, F> {
1786 frobenius_norm(self)
1787 }
1788
1789 pub fn scalar_mul(&self, scalar: F) -> Tensor<'g, F> {
1791 scalar_mul(self, scalar)
1792 }
1793}
1794
1795#[deprecated(
1806 since = "0.6.5",
1807 note = "misleading name: this is `abs`, not `-abs` -- use `abs` instead"
1808)]
1809pub use arithmetic::abs as neg_abs;
1810pub use arithmetic::{
1811 abs, acos, acosh, add, asin, asinh, atan, atanh, ceil, clip, cos, cosh, digamma_f32,
1812 digamma_f64, div, equal, exp, exp10, exp2, floor, greater, greater_equal, inv, inv_sqrt,
1813 lesser, lesser_equal, lgamma_f32, lgamma_f64, ln, log10, log2, maximum, minimum, mul, neg,
1814 not_equal, pow, sign, sin, sinh, sqrt, square, sub, tan, tanh, trigamma_f32, trigamma_f64,
1815};
1816
1817pub use reduction::{
1819 add_n, argmax, argmin, frobenius_norm, l1_norm, l2_norm, lp_norm, mean_all, reduce_all,
1820 reduce_any, reduce_logsumexp, reduce_max, reduce_mean, reduce_min, reduce_prod, reduce_std,
1821 reduce_sum, reduce_variance, sum_all,
1822};
1823
1824pub use linear_algebra::{
1826 batch_matmul, batch_matmul_t, concat, conv2d, conv2d_transpose, determinant, diag,
1827 dilated_conv2d, eigen, eigenvalues, extract_diag, eye, lstsq, matmul, matrix_inverse,
1828 max_pool2d, qr, scalar_mul, solve, split, svd, tensordot, trace, transpose,
1829};
1830
1831pub use activation::{
1833 batch_norm, elu, gelu, hard_sigmoid, hard_tanh, leaky_relu, log_softmax, mean_squared_error,
1834 mish, normalize, relu, relu6, sigmoid, sigmoid_cross_entropy, softmax, softmax_cross_entropy,
1835 softplus, sparse_softmax_cross_entropy, swish,
1836};
1837
1838pub use debug_ops::{debug_identity_with_gradient, debug_scalar_one};
1840pub use decomposition_ops::matrix_exp;
1841pub use decomposition_ops::{lu, qr as decomp_qr, svd as decomp_svd};
1842pub use eigen_ops::{eigen as eigen_decomp, eigenvalues as eigen_vals};
1843pub use linalg_ops::{
1844 diag as linalg_diag, extract_diag as linalg_extract_diag, eye as linalg_eye,
1845 trace as linalg_trace,
1846};
1847pub(crate) use linalg_ops::{TraceBackwardOp, TraceOp};
1852pub use matrix_ops::{
1853 determinant as matrix_det, matrix_inverse as matrix_inv,
1854 pseudo_inverse as matrix_pseudo_inverse,
1855};
1856pub use norm_ops::{frobenius_norm as norm_frobenius, nuclear_norm, spectral_norm};
1857pub use scalar_ops::scalar_mul as scalar_multiply;
1858pub use solver_ops::{lstsq as linalg_lstsq, solve as linalg_solve};
1859pub use special_matrices::{band_matrix, cholesky, symmetrize, tril, triu};
1860
1861pub use eigen_ops::eigen as eig;
1864pub use matrix_ops::determinant as det;
1865pub use matrix_ops::matrix_inverse as matinv;
1866pub use matrix_ops::pseudo_inverse as pinv;
1867
1868pub use matrix_functions::{logm, powm, sqrtm};
1870pub use matrix_functions::{matrix_log, matrix_power, matrix_sqrt};
1871pub(crate) use matrix_functions::{
1874 MatrixLogBackwardOp, MatrixPowBackwardOp, MatrixPowOp, MatrixSqrtBackwardOp,
1875};
1876
1877pub use numerical_props::{
1879 cond, cond_1, cond_2, cond_fro, cond_inf, logdet, matrix_rank, slogdet, ConditionType,
1880};
1881pub(crate) use numerical_props::{CondOp, CondTwoNormBackwardOp};
1885pub(crate) use numerical_props::LogDetBackwardOp;
1888pub(crate) use numerical_props::{LogDetOp, RankOp};
1892
1893pub use kronecker_ops::kron;
1895
1896pub use matrix_norms::{norm1, norm2, normfro, norminf};
1898
1899pub use matrix_solvers::{cholesky_solve, solve_lyapunov, solve_sylvester};
1901
1902pub use symmetric_ops::{eigh, eigvalsh};
1904
1905pub use special_decompositions::{polar, schur};
1907
1908pub use advanced_tensor_ops::{einsum, kron as kron_tensor, tensor_solve};
1910
1911pub use matrix_ops::{expm2, expm3};
1913
1914pub use advanced_decompositions::{generalized_eigen, qr_pivot, randomized_svd, svd_jacobi};
1916
1917pub use iterative_solvers::{
1919 bicgstab_solve, conjugate_gradient_solve, gmres_solve, pcg_solve, PreconditionerType,
1920};
1921
1922pub use matrix_trig_functions::{coshm, cosm, funm, signm, sinhm, sinm};
1924
1925pub use advanced_tensor_ops::kron as kronecker_product;
1927
1928pub use checkpoint_ops::{
1930 adaptive_checkpoint, checkpoint, checkpoint_segment, checkpoint_segment_flex, detach,
1931 CheckpointGroup, CheckpointProfiler,
1932};
1933pub(crate) use checkpoint_ops::CheckpointOp;
1937
1938pub use advanced_indexing::{
1940 advanced_gather, boolean_mask, get_at_coords, scatter, select_columns, select_rows, take,
1941 where_op,
1942};
1943
1944pub use broadcast_ops::{
1946 analyze_broadcast, broadcast_add, broadcast_div, broadcast_maximum, broadcast_minimum,
1947 broadcast_mul, broadcast_pow, broadcast_sub, clear_broadcast_cache, get_broadcast_cache_stats,
1948 BroadcastInfo, BroadcastStrategy,
1949};
1950
1951pub use memory_optimization::{
1953 clear_memory_pool, configure_memory_pool, disable_memory_tracking, efficient_ones,
1954 efficient_view, efficient_zeros, enable_memory_tracking, get_memory_pool_stats,
1955 get_memory_tracking_stats, get_pooled_buffer, inplace_abs, inplace_add, inplace_div,
1956 inplace_mul, inplace_neg, inplace_scalar_mul, inplace_sub, reset_memory_tracking,
1957 return_pooled_buffer, set_memory_pool_enabled, MemoryOptimizer, MemoryPoolStats,
1958 MemoryTrackerStats,
1959};
1960
1961pub use efficient_ops::{
1963 clear_reshape_cache, efficient_concat, efficient_reshape, efficient_reshape_withshape,
1964 efficient_slice, efficient_transpose, get_reshape_cache_stats, EfficientOpsManager,
1965 EfficientOpsStats, SliceRange,
1966};
1967
1968pub use custom_activations::{
1970 create_custom_activation, custom_activation, is_activation_registered,
1971 list_activation_functions, parameterized_activation, register_activation, ActivationProperties,
1972 CustomActivation, CustomActivationBuilder,
1973};
1974
1975pub use performance_ops::{
1977 cache_friendly_matmul, is_parallel_enabled, is_simd_enabled, parallel_sum,
1978 set_parallel_enabled, set_simd_enabled, simd_add, simd_mul, simd_relu, simd_sigmoid,
1979 PerformanceConfig, ReductionOperation, SimdBinaryOperation, SimdUnaryOperation,
1980};
1981
1982pub use graph_enhancements::{
1984 cached_op, clear_computation_cache, conditional, configure_cache, get_cache_stats,
1985 get_gc_stats, run_garbage_collection, smart_checkpoint, CacheStats, GcStats, GraphEnhancer,
1986 GraphStats, PredicateType,
1987};
1988
1989#[cfg(feature = "simd")]
1991pub use simd_ops::{
1992 simd_activation_relu, simd_activation_sigmoid, simd_activation_tanh, simd_broadcast_add,
1993 simd_broadcast_mul, simd_dot_product, simd_elementwise_add, simd_elementwise_div,
1994 simd_elementwise_mul, simd_elementwise_sub, simd_gradient_accumulate, simd_reduction_sum,
1995 simd_scaled_gradient_accumulate, SimdConfig, SimdDotProduct, SimdElementwiseAdd,
1996 SimdElementwiseDiv, SimdElementwiseMul, SimdElementwiseSub, SimdGradientAccumulate, SimdReLU,
1997 SimdReductionSum, SimdSigmoid, SimdTanh,
1998};
1999
2000#[cfg(test)]
2001#[path = "mod_tests.rs"]
2002mod tests;