1use crate::dtype::{DType, Element};
4use crate::error::Result;
5use crate::ops::UtilityOps;
6use crate::runtime::cpu::{
7 CpuClient, CpuRuntime,
8 helpers::{dispatch_dtype, ensure_contiguous},
9 kernels,
10};
11use crate::runtime::validate_arange;
12use crate::tensor::Tensor;
13
14use crate::error::Error;
15
16impl UtilityOps<CpuRuntime> for CpuClient {
18 fn clamp(
19 &self,
20 a: &Tensor<CpuRuntime>,
21 min_val: f64,
22 max_val: f64,
23 ) -> Result<Tensor<CpuRuntime>> {
24 let dtype = a.dtype();
25 let a_contig = ensure_contiguous(a)?;
26 let out = Tensor::<CpuRuntime>::empty(a.shape(), dtype, &self.device);
27
28 let a_ptr = a_contig.ptr();
29 let out_ptr = out.ptr();
30 let numel = a.numel();
31
32 dispatch_dtype!(dtype, T => {
33 unsafe {
34 kernels::clamp_kernel::<T>(
35 a_ptr as *const T,
36 out_ptr as *mut T,
37 numel,
38 min_val,
39 max_val,
40 );
41 }
42 }, "clamp");
43
44 Ok(out)
45 }
46
47 fn fill(&self, shape: &[usize], value: f64, dtype: DType) -> Result<Tensor<CpuRuntime>> {
48 let out = Tensor::<CpuRuntime>::empty(shape, dtype, &self.device);
49 let out_ptr = out.ptr();
50 let numel = out.numel();
51
52 dispatch_dtype!(dtype, T => {
53 unsafe {
54 kernels::fill_kernel::<T>(
55 out_ptr as *mut T,
56 T::from_f64(value),
57 numel,
58 );
59 }
60 }, "fill");
61
62 Ok(out)
63 }
64
65 fn arange(&self, start: f64, stop: f64, step: f64, dtype: DType) -> Result<Tensor<CpuRuntime>> {
66 let numel = validate_arange(start, stop, step)?;
68
69 if numel == 0 {
71 return Ok(Tensor::<CpuRuntime>::empty(&[0], dtype, &self.device));
72 }
73
74 let out = Tensor::<CpuRuntime>::empty(&[numel], dtype, &self.device);
75 let out_ptr = out.ptr();
76
77 dispatch_dtype!(dtype, T => {
78 unsafe {
79 kernels::arange_kernel::<T>(out_ptr as *mut T, start, step, numel);
80 }
81 }, "arange");
82
83 Ok(out)
84 }
85
86 fn linspace(
87 &self,
88 start: f64,
89 stop: f64,
90 steps: usize,
91 dtype: DType,
92 ) -> Result<Tensor<CpuRuntime>> {
93 if steps == 0 {
98 return Ok(Tensor::<CpuRuntime>::empty(&[0], dtype, &self.device));
99 }
100
101 if steps == 1 {
102 let out = Tensor::<CpuRuntime>::empty(&[1], dtype, &self.device);
103 let out_ptr = out.ptr();
104
105 dispatch_dtype!(dtype, T => {
106 unsafe {
107 *(out_ptr as *mut T) = T::from_f64(start);
108 }
109 }, "linspace");
110
111 return Ok(out);
112 }
113
114 let out = Tensor::<CpuRuntime>::empty(&[steps], dtype, &self.device);
115 let out_ptr = out.ptr();
116
117 dispatch_dtype!(dtype, T => {
118 unsafe {
119 kernels::linspace_kernel::<T>(out_ptr as *mut T, start, stop, steps);
120 }
121 }, "linspace");
122
123 Ok(out)
124 }
125
126 fn eye(&self, n: usize, m: Option<usize>, dtype: DType) -> Result<Tensor<CpuRuntime>> {
127 use crate::runtime::validate_eye;
129 let (rows, cols) = validate_eye(n, m);
130
131 if rows == 0 || cols == 0 {
133 return Ok(Tensor::<CpuRuntime>::empty(
134 &[rows, cols],
135 dtype,
136 &self.device,
137 ));
138 }
139
140 let out = Tensor::<CpuRuntime>::empty(&[rows, cols], dtype, &self.device);
141 let out_ptr = out.ptr();
142
143 dispatch_dtype!(dtype, T => {
144 unsafe {
145 kernels::eye_kernel::<T>(out_ptr as *mut T, rows, cols);
146 }
147 }, "eye");
148
149 Ok(out)
150 }
151
152 fn one_hot(
153 &self,
154 indices: &Tensor<CpuRuntime>,
155 num_classes: usize,
156 ) -> Result<Tensor<CpuRuntime>> {
157 let dtype = indices.dtype();
158
159 if !dtype.is_int() {
161 return Err(Error::UnsupportedDType {
162 dtype,
163 op: "one_hot",
164 });
165 }
166
167 if num_classes == 0 {
168 return Err(Error::InvalidArgument {
169 arg: "num_classes",
170 reason: "one_hot requires num_classes > 0".to_string(),
171 });
172 }
173
174 let indices = ensure_contiguous(indices)?;
175 let numel = indices.numel();
176
177 let mut out_shape = indices.shape().to_vec();
179 out_shape.push(num_classes);
180
181 let out = Tensor::<CpuRuntime>::empty(&out_shape, DType::F32, &self.device);
182 let out_ptr = out.ptr() as *mut f32;
183
184 unsafe {
186 std::ptr::write_bytes(out_ptr, 0, numel * num_classes);
187 }
188
189 let indices_ptr = indices.ptr();
190
191 dispatch_dtype!(dtype, T => {
193 unsafe {
194 kernels::one_hot_kernel::<T>(
195 indices_ptr as *const T,
196 out_ptr,
197 numel,
198 num_classes,
199 );
200 }
201 }, "one_hot");
202
203 Ok(out)
204 }
205
206 fn meshgrid(
207 &self,
208 tensors: &[&Tensor<CpuRuntime>],
209 indexing: crate::ops::MeshgridIndexing,
210 ) -> Result<Vec<Tensor<CpuRuntime>>> {
211 crate::ops::impl_generic::meshgrid_impl(tensors, indexing)
212 }
213}