use crate::tensor::Tensor;
use crate::shape::Shape;
use crate::buffer::Buffer;
use crate::dtypes::DType;
use crate::device::Device;
use crate::errors::{EtensorError, EtensorResult};
pub struct CpuAllocator;
impl CpuAllocator {
pub fn zeros(shape: Shape, dtype: DType, requires_grad: bool) -> EtensorResult<Tensor> {
if dtype != DType::F32 {
return Err(EtensorError::InternalError(
"CpuAllocator currently only supports F32 initialization.".to_string(),
));
}
let num_elements = shape.num_elements();
let buffer = Buffer::from_f32_vec(vec![0.0; num_elements]);
Ok(Tensor::new(buffer, shape, Device::Cpu, dtype, requires_grad))
}
pub fn ones(shape: Shape, dtype: DType, requires_grad: bool) -> EtensorResult<Tensor> {
if dtype != DType::F32 {
return Err(EtensorError::InternalError(
"CpuAllocator currently only supports F32 initialization.".to_string(),
));
}
let num_elements = shape.num_elements();
let buffer = Buffer::from_f32_vec(vec![1.0; num_elements]);
Ok(Tensor::new(buffer, shape, Device::Cpu, dtype, requires_grad))
}
pub fn full(shape: Shape, value: f32, dtype: DType, requires_grad: bool) -> EtensorResult<Tensor> {
if dtype != DType::F32 {
return Err(EtensorError::InternalError(
"CpuAllocator currently only supports F32 initialization.".to_string(),
));
}
let num_elements = shape.num_elements();
let buffer = Buffer::from_f32_vec(vec![value; num_elements]);
Ok(Tensor::new(buffer, shape, Device::Cpu, dtype, requires_grad))
}
pub fn arange(start: f32, end: f32, step: f32, dtype: DType, requires_grad: bool) -> EtensorResult<Tensor> {
if dtype != DType::F32 {
return Err(EtensorError::InternalError(
"CpuAllocator currently only supports F32 initialization.".to_string(),
));
}
if step == 0.0 {
return Err(EtensorError::InternalError("Arange step size cannot be zero.".to_string()));
}
let size = ((end - start) / step).ceil() as usize;
let mut data = Vec::with_capacity(size);
let mut current = start;
for _ in 0..size {
data.push(current);
current += step;
}
let shape = Shape::new(vec![size]);
let buffer = Buffer::from_f32_vec(data);
Ok(Tensor::new(buffer, shape, Device::Cpu, dtype, requires_grad))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cpu_alloc_zeros() {
let shape = Shape::new(vec![2, 3]);
let t = CpuAllocator::zeros(shape, DType::F32, false).unwrap();
let slice = t.data.as_f32_slice().unwrap();
assert_eq!(slice.len(), 6);
assert_eq!(slice, &[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
}
#[test]
fn test_cpu_alloc_ones() {
let shape = Shape::new(vec![4]);
let t = CpuAllocator::ones(shape, DType::F32, true).unwrap();
let slice = t.data.as_f32_slice().unwrap();
assert_eq!(slice, &[1.0, 1.0, 1.0, 1.0]);
assert!(t.requires_grad);
}
#[test]
fn test_cpu_alloc_full() {
let shape = Shape::new(vec![2, 2]);
let t = CpuAllocator::full(shape, 42.0, DType::F32, false).unwrap();
let slice = t.data.as_f32_slice().unwrap();
assert_eq!(slice, &[42.0, 42.0, 42.0, 42.0]);
}
#[test]
fn test_cpu_alloc_arange() {
let t = CpuAllocator::arange(0.0, 5.0, 1.0, DType::F32, false).unwrap();
let slice = t.data.as_f32_slice().unwrap();
assert_eq!(slice, &[0.0, 1.0, 2.0, 3.0, 4.0]);
assert_eq!(t.shape.dims, vec![5]);
}
}