1use crate::{Result, Tensor, TensorError};
7use scirs2_core::numeric::{Float, FromPrimitive, One, Zero};
8use std::ops::Range;
9
10pub fn zeros<T>(shape: &[usize]) -> Tensor<T>
12where
13 T: Clone + Default + Zero + Send + Sync + 'static,
14{
15 Tensor::zeros(shape)
16}
17
18pub fn ones<T>(shape: &[usize]) -> Tensor<T>
20where
21 T: Clone + Default + One + Send + Sync + 'static,
22{
23 Tensor::ones(shape)
24}
25
26pub fn full<T>(shape: &[usize], fill_value: T) -> Result<Tensor<T>>
28where
29 T: Clone + Default + Send + Sync + 'static,
30{
31 let size = shape.iter().product();
32 let data = vec![fill_value; size];
33 Tensor::from_vec(data, shape)
34}
35
36pub fn arange<T>(start: T, stop: T, step: T) -> Result<Tensor<T>>
38where
39 T: Clone + Default + Send + Sync + 'static + PartialOrd + std::ops::Add<Output = T>,
40{
41 let estimated_size = {
43 let mut count = 0;
44 let mut current = start.clone();
45 while current < stop {
46 count += 1;
47 current = current + step.clone();
48 if count > 1_000_000 {
50 break;
51 }
52 }
53 count.max(1)
54 };
55
56 let mut values = Vec::with_capacity(estimated_size);
57 let mut current = start.clone();
58
59 while current < stop {
60 values.push(current.clone());
61 current = current + step.clone();
62 }
63
64 if values.is_empty() {
65 values.push(start);
66 }
67
68 let len = values.len();
69 Tensor::from_vec(values, &[len])
70}
71
72pub fn linspace<T>(start: T, stop: T, num: usize, endpoint: bool) -> Result<Tensor<T>>
74where
75 T: Clone + Default + Send + Sync + 'static + Float + FromPrimitive,
76{
77 if num == 0 {
78 return Tensor::from_vec(Vec::new(), &[0]);
79 }
80
81 if num == 1 {
82 return Tensor::from_vec(vec![start], &[1]);
83 }
84
85 let step = if endpoint {
86 (stop - start) / T::from_usize(num - 1).expect("step count should convert to float")
87 } else {
88 (stop - start) / T::from_usize(num).expect("step count should convert to float")
89 };
90
91 let mut values = Vec::with_capacity(num);
92 for i in 0..num {
93 let value = start + step * T::from_usize(i).expect("array index should convert to float");
94 values.push(value);
95 }
96
97 Tensor::from_vec(values, &[num])
98}
99
100pub fn logspace<T>(start: T, stop: T, num: usize, base: T, endpoint: bool) -> Result<Tensor<T>>
102where
103 T: Clone + Default + Send + Sync + 'static + Float + FromPrimitive,
104{
105 let linear = linspace(start, stop, num, endpoint)?;
106 let linear_data = linear.as_slice().ok_or_else(|| {
107 TensorError::unsupported_operation_simple("Cannot access linear data".to_string())
108 })?;
109
110 let log_data: Vec<T> = linear_data.iter().map(|&x| base.powf(x)).collect();
111
112 Tensor::from_vec(log_data, &[num])
113}
114
115pub fn geomspace<T>(start: T, stop: T, num: usize, endpoint: bool) -> Result<Tensor<T>>
117where
118 T: Clone + Default + Send + Sync + 'static + Float + FromPrimitive,
119{
120 if start <= T::zero() || stop <= T::zero() {
121 return Err(TensorError::invalid_argument(
122 "geomspace requires positive start and stop values".to_string(),
123 ));
124 }
125
126 let log_start = start.ln();
127 let log_stop = stop.ln();
128
129 let log_linear = linspace(log_start, log_stop, num, endpoint)?;
130 let log_data = log_linear.as_slice().ok_or_else(|| {
131 TensorError::unsupported_operation_simple("Cannot access log linear data".to_string())
132 })?;
133
134 let geom_data: Vec<T> = log_data.iter().map(|&x| x.exp()).collect();
135
136 Tensor::from_vec(geom_data, &[num])
137}
138
139pub fn eye<T>(n: usize, m: Option<usize>, k: i32) -> Result<Tensor<T>>
141where
142 T: Clone + Default + Zero + One + Send + Sync + 'static,
143{
144 let m = m.unwrap_or(n);
145 let mut data = vec![T::zero(); n * m];
146
147 for i in 0..n {
149 let j = (i as i32 + k) as usize;
150 if j < m {
151 data[i * m + j] = T::one();
152 }
153 }
154
155 Tensor::from_vec(data, &[n, m])
156}
157
158pub fn identity<T>(n: usize) -> Result<Tensor<T>>
160where
161 T: Clone + Default + Zero + One + Send + Sync + 'static,
162{
163 eye(n, None, 0)
164}
165
166pub fn from_range<T>(range: Range<T>) -> Result<Tensor<T>>
168where
169 T: Clone + Default + Send + Sync + 'static + PartialOrd + std::ops::Add<Output = T> + One,
170{
171 let estimated_size = {
173 let mut count = 0;
174 let mut current = range.start.clone();
175 let step = T::one();
176 while current < range.end {
177 count += 1;
178 current = current + step.clone();
179 if count > 1_000_000 {
181 break;
182 }
183 }
184 count.max(1)
185 };
186
187 let mut values = Vec::with_capacity(estimated_size);
188 let mut current = range.start;
189 let step = T::one();
190
191 while current < range.end {
192 values.push(current.clone());
193 current = current + step.clone();
194 }
195
196 let len = values.len();
197 Tensor::from_vec(values, &[len])
198}
199
200pub fn diag<T>(v: &Tensor<T>, k: i32) -> Result<Tensor<T>>
202where
203 T: Clone + Default + Zero + Send + Sync + 'static,
204{
205 if v.shape().rank() != 1 {
206 return Err(TensorError::invalid_argument(
207 "diag requires a 1D input tensor".to_string(),
208 ));
209 }
210
211 let n = v.shape().dims()[0];
212 let size = n + k.unsigned_abs() as usize;
213 let mut data = vec![T::zero(); size * size];
214
215 let v_data = v.as_slice().ok_or_else(|| {
216 TensorError::unsupported_operation_simple("Cannot access input data".to_string())
217 })?;
218
219 for (i, value) in v_data.iter().enumerate() {
220 let row = if k >= 0 { i } else { i + (-k) as usize };
221 let col = if k >= 0 { i + k as usize } else { i };
222
223 if row < size && col < size {
224 data[row * size + col] = value.clone();
225 }
226 }
227
228 Tensor::from_vec(data, &[size, size])
229}
230
231pub fn diagonal<T>(matrix: &Tensor<T>, offset: i32) -> Result<Tensor<T>>
233where
234 T: Clone + Default + Send + Sync + 'static,
235{
236 if matrix.shape().rank() != 2 {
237 return Err(TensorError::invalid_argument(
238 "diagonal requires a 2D input tensor".to_string(),
239 ));
240 }
241
242 let dims = matrix.shape().dims();
243 let rows = dims[0];
244 let cols = dims[1];
245
246 let matrix_data = matrix.as_slice().ok_or_else(|| {
247 TensorError::unsupported_operation_simple("Cannot access matrix data".to_string())
248 })?;
249
250 let mut diag_data = Vec::new();
251
252 if offset >= 0 {
253 let offset = offset as usize;
254 for i in 0..rows {
255 let j = i + offset;
256 if j < cols {
257 diag_data.push(matrix_data[i * cols + j].clone());
258 }
259 }
260 } else {
261 let offset = (-offset) as usize;
262 for i in offset..rows {
263 let j = i - offset;
264 if j < cols {
265 diag_data.push(matrix_data[i * cols + j].clone());
266 }
267 }
268 }
269
270 let len = diag_data.len();
271 Tensor::from_vec(diag_data, &[len])
272}
273
274pub fn tri<T>(n: usize, m: Option<usize>, k: i32, lower: bool) -> Result<Tensor<T>>
276where
277 T: Clone + Default + Zero + One + Send + Sync + 'static,
278{
279 let m = m.unwrap_or(n);
280 let mut data = vec![T::zero(); n * m];
281
282 for i in 0..n {
283 for j in 0..m {
284 let condition = if lower {
285 j as i32 <= i as i32 + k
286 } else {
287 j as i32 >= i as i32 + k
288 };
289
290 if condition {
291 data[i * m + j] = T::one();
292 }
293 }
294 }
295
296 Tensor::from_vec(data, &[n, m])
297}
298
299pub fn triu<T>(n: usize, m: Option<usize>, k: i32) -> Result<Tensor<T>>
301where
302 T: Clone + Default + Zero + One + Send + Sync + 'static,
303{
304 tri(n, m, k, false)
305}
306
307pub fn tril<T>(n: usize, m: Option<usize>, k: i32) -> Result<Tensor<T>>
309where
310 T: Clone + Default + Zero + One + Send + Sync + 'static,
311{
312 tri(n, m, k, true)
313}
314
315pub fn meshgrid<T>(x: &Tensor<T>, y: &Tensor<T>, indexing: &str) -> Result<(Tensor<T>, Tensor<T>)>
317where
318 T: Clone + Default + Send + Sync + 'static,
319{
320 if x.shape().rank() != 1 || y.shape().rank() != 1 {
321 return Err(TensorError::invalid_argument(
322 "meshgrid requires 1D input tensors".to_string(),
323 ));
324 }
325
326 let x_data = x.as_slice().ok_or_else(|| {
327 TensorError::unsupported_operation_simple("Cannot access x data".to_string())
328 })?;
329 let y_data = y.as_slice().ok_or_else(|| {
330 TensorError::unsupported_operation_simple("Cannot access y data".to_string())
331 })?;
332
333 let (x_len, y_len) = (x_data.len(), y_data.len());
334
335 let (xx_data, yy_data, shape) = match indexing {
336 "xy" => {
337 let mut xx = Vec::with_capacity(y_len * x_len);
339 let mut yy = Vec::with_capacity(y_len * x_len);
340
341 for y_val in y_data {
342 for x_val in x_data {
343 xx.push(x_val.clone());
344 yy.push(y_val.clone());
345 }
346 }
347
348 (xx, yy, vec![y_len, x_len])
349 }
350 "ij" => {
351 let mut xx = Vec::with_capacity(x_len * y_len);
353 let mut yy = Vec::with_capacity(x_len * y_len);
354
355 for x_val in x_data {
356 for y_val in y_data {
357 xx.push(x_val.clone());
358 yy.push(y_val.clone());
359 }
360 }
361
362 (xx, yy, vec![x_len, y_len])
363 }
364 _ => {
365 return Err(TensorError::invalid_argument(format!(
366 "Unknown indexing: '{indexing}'. Use 'xy' or 'ij'"
367 )));
368 }
369 };
370
371 let xx_tensor = Tensor::from_vec(xx_data, &shape)?;
372 let yy_tensor = Tensor::from_vec(yy_data, &shape)?;
373
374 Ok((xx_tensor, yy_tensor))
375}
376
377pub fn fromfunction<T, F>(func: F, shape: &[usize]) -> Result<Tensor<T>>
379where
380 T: Clone + Default + Send + Sync + 'static,
381 F: Fn(&[usize]) -> T + Send + Sync,
382{
383 let total_size = shape.iter().product();
384 let mut data = Vec::with_capacity(total_size);
385
386 let mut indices = vec![0; shape.len()];
388
389 for _ in 0..total_size {
390 data.push(func(&indices));
391
392 let mut carry = true;
394 for i in (0..shape.len()).rev() {
395 if carry {
396 indices[i] += 1;
397 if indices[i] < shape[i] {
398 carry = false;
399 } else {
400 indices[i] = 0;
401 }
402 }
403 }
404 }
405
406 Tensor::from_vec(data, shape)
407}
408
409#[cfg(test)]
410mod tests {
411 use super::*;
412
413 #[test]
414 fn test_arange() {
415 let result = arange(0.0f32, 5.0, 1.0).expect("test: arange should succeed");
416 if let Some(data) = result.as_slice() {
417 assert_eq!(data, &[0.0, 1.0, 2.0, 3.0, 4.0]);
418 }
419 }
420
421 #[test]
422 fn test_linspace() {
423 let result = linspace(0.0f32, 1.0, 6, true).expect("test: linspace should succeed");
424 if let Some(data) = result.as_slice() {
425 assert_eq!(data.len(), 6);
426 assert!((data[0] - 0.0).abs() < 1e-6);
427 assert!((data[5] - 1.0).abs() < 1e-6);
428 }
429 }
430
431 #[test]
432 fn test_eye() {
433 let result = eye::<f32>(3, None, 0).expect("test: operation should succeed");
434 assert_eq!(result.shape().dims(), &[3, 3]);
435
436 if let Some(data) = result.as_slice() {
437 let expected = &[1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0];
438 assert_eq!(data, expected);
439 }
440 }
441
442 #[test]
443 fn test_diag() {
444 let v = Tensor::<f32>::from_vec(vec![1.0, 2.0, 3.0], &[3])
445 .expect("test: from_vec should succeed");
446 let result = diag(&v, 0).expect("test: diag should succeed");
447 assert_eq!(result.shape().dims(), &[3, 3]);
448
449 if let Some(data) = result.as_slice() {
450 let expected = &[1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 3.0];
451 assert_eq!(data, expected);
452 }
453 }
454
455 #[test]
456 fn test_diagonal() {
457 let matrix =
458 Tensor::<f32>::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0], &[3, 3])
459 .expect("test: operation should succeed");
460
461 let result = diagonal(&matrix, 0).expect("test: diagonal should succeed");
462 if let Some(data) = result.as_slice() {
463 assert_eq!(data, &[1.0, 5.0, 9.0]);
464 }
465 }
466
467 #[test]
468 fn test_meshgrid() {
469 let x =
470 Tensor::<f32>::from_vec(vec![1.0, 2.0], &[2]).expect("test: from_vec should succeed");
471 let y = Tensor::<f32>::from_vec(vec![3.0, 4.0, 5.0], &[3])
472 .expect("test: from_vec should succeed");
473
474 let (xx, yy) = meshgrid(&x, &y, "xy").expect("test: meshgrid should succeed");
475 assert_eq!(xx.shape().dims(), &[3, 2]);
476 assert_eq!(yy.shape().dims(), &[3, 2]);
477 }
478
479 #[test]
480 fn test_fromfunction() {
481 let result = fromfunction(|indices| (indices[0] + indices[1]) as f32, &[2, 3])
482 .expect("test: operation should succeed");
483 assert_eq!(result.shape().dims(), &[2, 3]);
484
485 if let Some(data) = result.as_slice() {
486 assert_eq!(data, &[0.0, 1.0, 2.0, 1.0, 2.0, 3.0]);
487 }
488 }
489
490 #[test]
491 fn test_triu_tril() {
492 let upper = triu::<f32>(3, None, 0).expect("test: operation should succeed");
493 if let Some(data) = upper.as_slice() {
494 let expected = &[1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0];
495 assert_eq!(data, expected);
496 }
497
498 let lower = tril::<f32>(3, None, 0).expect("test: operation should succeed");
499 if let Some(data) = lower.as_slice() {
500 let expected = &[1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0];
501 assert_eq!(data, expected);
502 }
503 }
504}