1mod activations;
42mod complex;
43pub mod constructors;
44mod conversions;
45mod expression;
46mod math_ops;
47mod sparse;
48pub mod transformations;
49mod utils;
50
51#[cfg(test)]
52mod complex_tests;
53#[cfg(test)]
54mod constructors_tests;
55#[cfg(test)]
56mod property_tests;
57
58use crate::errors::Result;
59use scirs2_core::ndarray::{ArrayBase, ArrayD, Dim, IxDynImpl, OwnedRepr};
60use scirs2_core::Complex;
61use scirs2_core::{Complex32, Complex64};
62use serde::{Deserialize, Serialize};
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
66pub enum DType {
67 F32,
69 F16,
71 BF16,
73 F64,
75 C32,
77 C64,
79 CF16,
81 CBF16,
83 U8,
85 U16,
87 U32,
89 U64,
91 I8,
93 I16,
95 I32,
97 I64,
99 Bool,
101}
102
103impl DType {
104 pub fn size_in_bytes(&self) -> usize {
106 match self {
107 DType::F32 => 4,
108 DType::F16 => 2,
109 DType::BF16 => 2,
110 DType::F64 => 8,
111 DType::C32 => 8, DType::C64 => 16, DType::CF16 => 4, DType::CBF16 => 4, DType::U8 => 1,
116 DType::U16 => 2,
117 DType::U32 => 4,
118 DType::U64 => 8,
119 DType::I8 => 1,
120 DType::I16 => 2,
121 DType::I32 => 4,
122 DType::I64 => 8,
123 DType::Bool => 1,
124 }
125 }
126}
127
128#[cfg(all(target_os = "macos", feature = "metal"))]
161#[derive(Debug)]
162pub struct MetalTensorData {
163 pub buffer_id: crate::gpu_ops::metal::BufferId,
164 pub shape: Vec<usize>,
165 pub dtype: DType,
166}
167
168#[cfg(all(target_os = "macos", feature = "metal"))]
169impl Clone for MetalTensorData {
170 fn clone(&self) -> Self {
171 Self {
174 buffer_id: self.buffer_id,
175 shape: self.shape.clone(),
176 dtype: self.dtype,
177 }
178 }
179}
180
181#[cfg(feature = "cuda")]
189#[derive(Debug, Clone)]
190pub struct CudaTensorData {
191 pub buffer: crate::gpu_ops::cuda::BufferHandle,
193 pub shape: Vec<usize>,
194 pub dtype: DType,
195}
196
197#[cfg(feature = "cuda")]
198impl CudaTensorData {
199 pub fn new(
203 buffer_id: crate::gpu_ops::cuda::BufferId,
204 device_id: usize,
205 shape: Vec<usize>,
206 dtype: DType,
207 ) -> Self {
208 Self {
209 buffer: crate::gpu_ops::cuda::BufferHandle::new(buffer_id, device_id),
210 shape,
211 dtype,
212 }
213 }
214
215 #[cfg(test)]
217 pub(crate) fn from_handle(
218 buffer: crate::gpu_ops::cuda::BufferHandle,
219 shape: Vec<usize>,
220 dtype: DType,
221 ) -> Self {
222 Self {
223 buffer,
224 shape,
225 dtype,
226 }
227 }
228
229 #[inline]
231 pub fn buffer_id(&self) -> crate::gpu_ops::cuda::BufferId {
232 self.buffer.id()
233 }
234
235 #[inline]
237 pub fn device_id(&self) -> usize {
238 self.buffer.device_id()
239 }
240}
241
242pub enum Tensor {
243 F32(ArrayD<f32>),
245 F64(ArrayD<f64>),
246 F16(ArrayD<half::f16>),
247 BF16(ArrayD<half::bf16>),
248 I64(ArrayD<i64>),
249 C32(ArrayD<Complex32>),
251 C64(ArrayD<Complex64>),
252 CF16(ArrayD<Complex<half::f16>>),
253 CBF16(ArrayD<Complex<half::bf16>>),
254 Sparse(crate::sparse_tensor::SparseTensor),
256 #[cfg(feature = "candle")]
259 Candle(candle_core::Tensor),
260 #[cfg(all(target_os = "macos", feature = "metal"))]
262 Metal(MetalTensorData),
263 #[cfg(feature = "cuda")]
265 CUDA(CudaTensorData),
266}
267
268impl Clone for Tensor {
270 fn clone(&self) -> Self {
271 match self {
272 Tensor::F32(arr) => Tensor::F32(arr.clone()),
273 Tensor::F64(arr) => Tensor::F64(arr.clone()),
274 Tensor::F16(arr) => Tensor::F16(arr.clone()),
275 Tensor::BF16(arr) => Tensor::BF16(arr.clone()),
276 Tensor::I64(arr) => Tensor::I64(arr.clone()),
277 Tensor::C32(arr) => Tensor::C32(arr.clone()),
278 Tensor::C64(arr) => Tensor::C64(arr.clone()),
279 Tensor::CF16(arr) => Tensor::CF16(arr.clone()),
280 Tensor::CBF16(arr) => Tensor::CBF16(arr.clone()),
281 Tensor::Sparse(s) => Tensor::Sparse(s.clone()),
282 #[cfg(feature = "candle")]
283 Tensor::Candle(t) => Tensor::Candle(t.clone()),
284 #[cfg(all(target_os = "macos", feature = "metal"))]
285 Tensor::Metal(data) => Tensor::Metal(data.clone()),
286 #[cfg(feature = "cuda")]
287 Tensor::CUDA(data) => Tensor::CUDA(data.clone()),
288 }
289 }
290}
291
292impl std::fmt::Debug for Tensor {
294 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
295 match self {
296 Tensor::F32(_) => write!(f, "Tensor::F32(shape: {:?}, dtype: F32)", self.shape()),
297 Tensor::F64(_) => write!(f, "Tensor::F64(shape: {:?}, dtype: F64)", self.shape()),
298 Tensor::F16(_) => write!(f, "Tensor::F16(shape: {:?}, dtype: F16)", self.shape()),
299 Tensor::BF16(_) => write!(f, "Tensor::BF16(shape: {:?}, dtype: BF16)", self.shape()),
300 Tensor::I64(_) => write!(f, "Tensor::I64(shape: {:?}, dtype: I64)", self.shape()),
301 Tensor::C32(_) => write!(f, "Tensor::C32(shape: {:?}, dtype: C32)", self.shape()),
302 Tensor::C64(_) => write!(f, "Tensor::C64(shape: {:?}, dtype: C64)", self.shape()),
303 Tensor::CF16(_) => write!(f, "Tensor::CF16(shape: {:?}, dtype: CF16)", self.shape()),
304 Tensor::CBF16(_) => write!(f, "Tensor::CBF16(shape: {:?}, dtype: CBF16)", self.shape()),
305 Tensor::Sparse(s) => write!(f, "Tensor::Sparse({:?})", s),
306 #[cfg(feature = "candle")]
307 Tensor::Candle(_) => write!(f, "Tensor::Candle(shape: {:?})", self.shape()),
308 #[cfg(all(target_os = "macos", feature = "metal"))]
309 Tensor::Metal(data) => write!(
310 f,
311 "Tensor::Metal(shape: {:?}, dtype: {:?}, buffer_id: {:?})",
312 data.shape, data.dtype, data.buffer_id
313 ),
314 #[cfg(feature = "cuda")]
315 Tensor::CUDA(data) => write!(
316 f,
317 "Tensor::CUDA(shape: {:?}, dtype: {:?}, buffer: {:?})",
318 data.shape, data.dtype, data.buffer
319 ),
320 }
321 }
322}
323
324#[cfg(feature = "candle")]
328unsafe impl Sync for Tensor {}
329
330impl From<ArrayBase<OwnedRepr<f32>, Dim<IxDynImpl>>> for Tensor {
333 fn from(arr: ArrayD<f32>) -> Self {
334 Tensor::F32(arr)
335 }
336}
337
338impl From<ArrayBase<OwnedRepr<f64>, Dim<IxDynImpl>>> for Tensor {
339 fn from(arr: ArrayD<f64>) -> Self {
340 Tensor::F64(arr)
341 }
342}
343
344impl std::ops::Add for Tensor {
346 type Output = Result<Tensor>;
347
348 fn add(self, other: Tensor) -> Self::Output {
349 Tensor::add(&self, &other)
350 }
351}
352
353impl std::ops::Add for &Tensor {
354 type Output = Result<Tensor>;
355
356 fn add(self, other: &Tensor) -> Self::Output {
357 Tensor::add(self, other)
358 }
359}
360
361impl std::ops::Add<&&Tensor> for &Tensor {
362 type Output = Result<Tensor>;
363
364 fn add(self, other: &&Tensor) -> Self::Output {
365 Tensor::add(self, other)
366 }
367}
368
369impl std::ops::Add<&Tensor> for &&Tensor {
370 type Output = Result<Tensor>;
371
372 fn add(self, other: &Tensor) -> Self::Output {
373 Tensor::add(self, other)
374 }
375}
376
377impl std::ops::Sub for Tensor {
378 type Output = Result<Tensor>;
379
380 fn sub(self, other: Tensor) -> Self::Output {
381 Tensor::sub(&self, &other)
382 }
383}
384
385impl std::ops::Mul<f32> for Tensor {
387 type Output = Result<Tensor>;
388
389 fn mul(self, scalar: f32) -> Self::Output {
390 self.scalar_mul(scalar)
391 }
392}
393
394impl std::ops::Mul<f32> for &Tensor {
395 type Output = Result<Tensor>;
396
397 fn mul(self, scalar: f32) -> Self::Output {
398 self.scalar_mul(scalar)
399 }
400}
401
402impl std::ops::Mul<f64> for Tensor {
403 type Output = Result<Tensor>;
404
405 fn mul(self, scalar: f64) -> Self::Output {
406 self.scalar_mul(scalar as f32)
407 }
408}
409
410impl std::ops::Mul<f64> for &Tensor {
411 type Output = Result<Tensor>;
412
413 fn mul(self, scalar: f64) -> Self::Output {
414 self.scalar_mul(scalar as f32)
415 }
416}
417
418impl std::ops::Mul<&Tensor> for &Tensor {
420 type Output = Result<Tensor>;
421
422 fn mul(self, other: &Tensor) -> Self::Output {
423 Tensor::mul(self, other)
424 }
425}
426
427impl std::ops::Mul<Tensor> for &Tensor {
428 type Output = Result<Tensor>;
429
430 fn mul(self, other: Tensor) -> Self::Output {
431 Tensor::mul(self, &other)
432 }
433}
434
435impl std::ops::Mul<&Tensor> for Tensor {
436 type Output = Result<Tensor>;
437
438 fn mul(self, other: &Tensor) -> Self::Output {
439 Tensor::mul(&self, other)
440 }
441}
442
443impl std::ops::Div<f32> for Tensor {
445 type Output = Result<Tensor>;
446
447 fn div(self, scalar: f32) -> Self::Output {
448 self.scalar_div(scalar)
449 }
450}
451
452impl std::ops::Div<f32> for &Tensor {
453 type Output = Result<Tensor>;
454
455 fn div(self, scalar: f32) -> Self::Output {
456 self.scalar_div(scalar)
457 }
458}
459
460impl std::ops::Div<f64> for Tensor {
461 type Output = Result<Tensor>;
462
463 fn div(self, scalar: f64) -> Self::Output {
464 self.scalar_div(scalar as f32)
465 }
466}
467
468impl std::ops::Div<f64> for &Tensor {
469 type Output = Result<Tensor>;
470
471 fn div(self, scalar: f64) -> Self::Output {
472 self.scalar_div(scalar as f32)
473 }
474}
475
476impl std::ops::Div<f64> for &&Tensor {
477 type Output = Result<Tensor>;
478
479 fn div(self, scalar: f64) -> Self::Output {
480 (*self).scalar_div(scalar as f32)
481 }
482}
483
484impl std::ops::Sub for &Tensor {
486 type Output = Result<Tensor>;
487
488 fn sub(self, other: &Tensor) -> Self::Output {
489 Tensor::sub(self, other)
490 }
491}
492
493pub type TensorType = DType;
495
496pub use expression::{EvalContext, ExprNode, OpType, OptimizationHints, TensorExpr};
498
499pub use utils::{clear_gradients, disable_grad, enable_grad, is_grad_enabled};