Skip to main content

rstsr_core/tensor/
creation.rs

1//! Creation methods for `Tensor` struct.
2//!
3//! This module relates to the [Python array API standard v2024.12](https://data-apis.org/array-api/2024.12/API_specification/creation_functions.html).
4//!
5//! Todo list:
6//! - [x] `arange`: [`arange`]
7//! - [x] `asarray`: [`asarray`] (defined elsewhere)
8//! - [x] `empty`: [`empty`]
9//! - [x] `empty_like`: [`empty_like`]
10//! - [x] `eye`: [`eye`]
11//! - [ ] ~`from_dlpack`~
12//! - [x] `full`: [`full`]
13//! - [x] `full_like`: [`full_like`]
14//! - [x] `linspace`: [`linspace`]
15//! - [x] `meshgrid`
16//! - [x] `ones`: [`ones`]
17//! - [x] `ones_like`: [`ones_like`]
18//! - [x] `tril`
19//! - [x] `triu`
20//! - [x] `zeros`: [`zeros`]
21//! - [x] `zeros_like`: [`zeros_like`]
22
23use crate::prelude_dev::*;
24use num::complex::ComplexFloat;
25use num::{Num, One, Zero};
26
27/* #region arange */
28
29pub trait ArangeAPI<Inp> {
30    type Out;
31
32    fn arange_f(self) -> Result<Self::Out>;
33
34    fn arange(self) -> Self::Out
35    where
36        Self: Sized,
37    {
38        Self::arange_f(self).rstsr_unwrap()
39    }
40}
41
42/// Evenly spaced values within the half-open interval `[start, stop)` as
43/// one-dimensional array.
44///
45/// # See also
46///
47/// - [Python array API standard: `arange`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.arange.html)
48pub fn arange<Args, Inp>(param: Args) -> Args::Out
49where
50    Args: ArangeAPI<Inp>,
51{
52    return ArangeAPI::arange(param);
53}
54
55pub fn arange_f<Args, Inp>(param: Args) -> Result<Args::Out>
56where
57    Args: ArangeAPI<Inp>,
58{
59    return ArangeAPI::arange_f(param);
60}
61
62impl<T, B> ArangeAPI<(T, B)> for (T, T, T, &B)
63where
64    B: DeviceAPI<T> + DeviceCreationArangeAPI<T>,
65{
66    type Out = Tensor<T, B, IxD>;
67
68    fn arange_f(self) -> Result<Self::Out> {
69        // full implementation
70        let (start, stop, step, device) = self;
71        let data = device.arange_impl(start, stop, step)?;
72        let layout = vec![data.len()].into();
73        unsafe { Ok(Tensor::new_unchecked(data, layout)) }
74    }
75}
76
77impl<T, B> ArangeAPI<(T, B)> for (T, T, &B)
78where
79    T: One,
80    B: DeviceAPI<T> + DeviceCreationArangeAPI<T>,
81{
82    type Out = Tensor<T, B, IxD>;
83
84    fn arange_f(self) -> Result<Self::Out> {
85        // (start, stop, device) -> (start, stop, 1, device)
86        let (start, stop, device) = self;
87        let step = T::one();
88        arange_f((start, stop, step, device))
89    }
90}
91
92impl<T, B> ArangeAPI<(T, B)> for (T, &B)
93where
94    T: Zero + One,
95    B: DeviceAPI<T> + DeviceCreationArangeAPI<T>,
96{
97    type Out = Tensor<T, B, IxD>;
98
99    fn arange_f(self) -> Result<Self::Out> {
100        // (stop, device) -> (0, stop, 1, device)
101        let (stop, device) = self;
102        let start = T::zero();
103        let step = T::one();
104        arange_f((start, stop, step, device))
105    }
106}
107
108impl<T> ArangeAPI<T> for (T, T, T)
109where
110    T: PartialOrd + Clone + Add<Output = T> + Zero + 'static,
111{
112    type Out = Tensor<T, DeviceCpu, IxD>;
113
114    fn arange_f(self) -> Result<Self::Out> {
115        // full implementation
116        let (start, stop, step) = self;
117        arange_f((start, stop, step, &DeviceCpu::default()))
118    }
119}
120
121impl<T> ArangeAPI<T> for (T, T)
122where
123    T: PartialOrd + Clone + Add<Output = T> + Zero + One + 'static,
124{
125    type Out = Tensor<T, DeviceCpu, IxD>;
126
127    fn arange_f(self) -> Result<Self::Out> {
128        // (start, stop) -> (start, stop, 1)
129        let (start, stop) = self;
130        arange_f((start, stop, &DeviceCpu::default()))
131    }
132}
133
134impl<T> ArangeAPI<T> for T
135where
136    T: PartialOrd + Clone + Add<Output = T> + Zero + One + 'static,
137{
138    type Out = Tensor<T, DeviceCpu, IxD>;
139
140    fn arange_f(self) -> Result<Self::Out> {
141        // (stop) -> (0, stop, 1)
142        arange_f((T::zero(), self, &DeviceCpu::default()))
143    }
144}
145
146/* #endregion */
147
148/* #region empty */
149
150pub trait EmptyAPI<Inp> {
151    type Out;
152
153    /// # Safety
154    ///
155    /// This function is unsafe because it creates a tensor with uninitialized.
156    unsafe fn empty_f(self) -> Result<Self::Out>;
157
158    /// # Safety
159    ///
160    /// This function is unsafe because it creates a tensor with uninitialized.
161    unsafe fn empty(self) -> Self::Out
162    where
163        Self: Sized,
164    {
165        Self::empty_f(self).rstsr_unwrap()
166    }
167}
168
169/// Uninitialized tensor having a specified shape.
170///
171/// # Safety
172///
173/// This function is unsafe because it creates a tensor with uninitialized.
174///
175/// # See also
176///
177/// - [Python array API standard: `empty`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.empty.html)
178pub unsafe fn empty<Args, Inp>(param: Args) -> Args::Out
179where
180    Args: EmptyAPI<Inp>,
181{
182    return EmptyAPI::empty(param);
183}
184
185/// # Safety
186///
187/// This function is unsafe because it creates a tensor with uninitialized.
188pub unsafe fn empty_f<Args, Inp>(param: Args) -> Result<Args::Out>
189where
190    Args: EmptyAPI<Inp>,
191{
192    return EmptyAPI::empty_f(param);
193}
194
195impl<T, D, B> EmptyAPI<(T, D)> for (Layout<D>, &B)
196where
197    D: DimAPI,
198    B: DeviceAPI<T> + DeviceCreationAnyAPI<T>,
199{
200    type Out = Tensor<T, B, IxD>;
201
202    unsafe fn empty_f(self) -> Result<Self::Out> {
203        let (layout, device) = self;
204        let (_, idx_max) = layout.bounds_index()?;
205        let storage = B::empty_impl(device, idx_max)?;
206        unsafe { Ok(Tensor::new_unchecked(storage, layout.into_dim()?)) }
207    }
208}
209
210impl<T, D, B> EmptyAPI<(T, D)> for (D, FlagOrder, &B)
211where
212    D: DimAPI,
213    B: DeviceAPI<T> + DeviceCreationAnyAPI<T>,
214{
215    type Out = Tensor<T, B, IxD>;
216
217    unsafe fn empty_f(self) -> Result<Self::Out> {
218        let (shape, order, device) = self;
219        let layout = shape.new_contig(None, order);
220        empty_f((layout, device))
221    }
222}
223
224impl<T, D, B> EmptyAPI<(T, D)> for (D, &B)
225where
226    D: DimAPI,
227    B: DeviceAPI<T> + DeviceCreationAnyAPI<T>,
228{
229    type Out = Tensor<T, B, IxD>;
230
231    unsafe fn empty_f(self) -> Result<Self::Out> {
232        let (shape, device) = self;
233        let default_order = device.default_order();
234        let layout = shape.new_contig(None, default_order);
235        empty_f((layout, device))
236    }
237}
238
239impl<T, D> EmptyAPI<(T, D)> for (D, FlagOrder)
240where
241    D: DimAPI,
242{
243    type Out = Tensor<T, DeviceCpu, IxD>;
244
245    unsafe fn empty_f(self) -> Result<Self::Out> {
246        let (shape, order) = self;
247        empty_f((shape, order, &DeviceCpu::default()))
248    }
249}
250
251#[duplicate_item(L; [D]; [Layout<D>])]
252impl<T, D> EmptyAPI<(T, D)> for L
253where
254    D: DimAPI,
255{
256    type Out = Tensor<T, DeviceCpu, IxD>;
257
258    unsafe fn empty_f(self) -> Result<Self::Out> {
259        empty_f((self, &DeviceCpu::default()))
260    }
261}
262
263/* #endregion */
264
265/* #region empty_like */
266
267pub trait EmptyLikeAPI<Inp> {
268    type Out;
269
270    /// # Safety
271    ///
272    /// This function is unsafe because it creates a tensor with uninitialized.
273    unsafe fn empty_like_f(self) -> Result<Self::Out>;
274
275    /// # Safety
276    ///
277    /// This function is unsafe because it creates a tensor with uninitialized.
278    unsafe fn empty_like(self) -> Self::Out
279    where
280        Self: Sized,
281    {
282        Self::empty_like_f(self).rstsr_unwrap()
283    }
284}
285
286/// Uninitialized tensor with the same shape as an input tensor.
287///
288/// # Safety
289///
290/// This function is unsafe because it creates a tensor with uninitialized.
291///
292/// # See also
293///
294/// - [Python array API standard: `empty_like`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.empty_like.html)
295pub unsafe fn empty_like<Args, Inp>(param: Args) -> Args::Out
296where
297    Args: EmptyLikeAPI<Inp>,
298{
299    return EmptyLikeAPI::empty_like(param);
300}
301
302/// # Safety
303///
304/// This function is unsafe because it creates a tensor with uninitialized.
305pub unsafe fn empty_like_f<Args, Inp>(param: Args) -> Result<Args::Out>
306where
307    Args: EmptyLikeAPI<Inp>,
308{
309    return EmptyLikeAPI::empty_like_f(param);
310}
311
312impl<R, T, B, D> EmptyLikeAPI<()> for (&TensorAny<R, T, B, D>, TensorIterOrder, &B)
313where
314    R: DataAPI<Data = B::Raw>,
315    D: DimAPI,
316    B: DeviceAPI<T> + DeviceCreationAnyAPI<T>,
317{
318    type Out = Tensor<T, B, D>;
319
320    unsafe fn empty_like_f(self) -> Result<Self::Out> {
321        let (tensor, order, device) = self;
322        let layout = layout_for_array_copy(tensor.layout(), order)?;
323        let idx_max = layout.size();
324        let storage = device.empty_impl(idx_max)?;
325        unsafe { Ok(Tensor::new_unchecked(storage, layout)) }
326    }
327}
328
329impl<R, T, B, D> EmptyLikeAPI<()> for (&TensorAny<R, T, B, D>, &B)
330where
331    R: DataAPI<Data = B::Raw>,
332    D: DimAPI,
333    B: DeviceAPI<T> + DeviceCreationAnyAPI<T>,
334{
335    type Out = Tensor<T, B, D>;
336
337    unsafe fn empty_like_f(self) -> Result<Self::Out> {
338        let (tensor, device) = self;
339        empty_like_f((tensor, TensorIterOrder::default(), device))
340    }
341}
342
343impl<R, T, B, D> EmptyLikeAPI<()> for (&TensorAny<R, T, B, D>, TensorIterOrder)
344where
345    R: DataAPI<Data = B::Raw>,
346    D: DimAPI,
347    B: DeviceAPI<T> + DeviceCreationAnyAPI<T>,
348{
349    type Out = Tensor<T, B, D>;
350
351    unsafe fn empty_like_f(self) -> Result<Self::Out> {
352        let (tensor, order) = self;
353        let device = tensor.device();
354        empty_like_f((tensor, order, device))
355    }
356}
357
358impl<R, T, B, D> EmptyLikeAPI<()> for &TensorAny<R, T, B, D>
359where
360    R: DataAPI<Data = B::Raw>,
361    D: DimAPI,
362    B: DeviceAPI<T> + DeviceCreationAnyAPI<T>,
363{
364    type Out = Tensor<T, B, D>;
365
366    unsafe fn empty_like_f(self) -> Result<Self::Out> {
367        let device = self.device();
368        empty_like_f((self, TensorIterOrder::default(), device))
369    }
370}
371
372/* #endregion */
373
374/* #region eye */
375
376pub trait EyeAPI<Inp> {
377    type Out;
378
379    fn eye_f(self) -> Result<Self::Out>;
380
381    fn eye(self) -> Self::Out
382    where
383        Self: Sized,
384    {
385        Self::eye_f(self).rstsr_unwrap()
386    }
387}
388
389/// Returns a two-dimensional array with ones on the kth diagonal and zeros
390/// elsewhere.
391///
392/// # See also
393///
394/// - [Python array API standard: `eye`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.eye.html)
395pub fn eye<Args, Inp>(param: Args) -> Args::Out
396where
397    Args: EyeAPI<Inp>,
398{
399    return EyeAPI::eye(param);
400}
401
402pub fn eye_f<Args, Inp>(param: Args) -> Result<Args::Out>
403where
404    Args: EyeAPI<Inp>,
405{
406    return EyeAPI::eye_f(param);
407}
408
409impl<T, B> EyeAPI<(T, B)> for (usize, usize, isize, FlagOrder, &B)
410where
411    T: Num,
412    B: DeviceAPI<T> + DeviceCreationNumAPI<T> + OpAssignAPI<T, Ix1>,
413{
414    type Out = Tensor<T, B, IxD>;
415
416    fn eye_f(self) -> Result<Self::Out> {
417        let (n_rows, n_cols, k, order, device) = self;
418        let layout = match order {
419            RowMajor => [n_rows, n_cols].c(),
420            ColMajor => [n_cols, n_rows].f(),
421        };
422        let mut storage = device.zeros_impl(layout.size())?;
423        let layout_diag = layout.diagonal(Some(k), Some(0), Some(1))?;
424        device.fill(storage.raw_mut(), &layout_diag, T::one())?;
425        unsafe { Ok(Tensor::new_unchecked(storage, layout.into_dim()?)) }
426    }
427}
428
429impl<T, B> EyeAPI<(T, B)> for (usize, usize, isize, &B)
430where
431    T: Num,
432    B: DeviceAPI<T> + DeviceCreationNumAPI<T> + OpAssignAPI<T, Ix1>,
433{
434    type Out = Tensor<T, B, IxD>;
435
436    fn eye_f(self) -> Result<Self::Out> {
437        // (n_rows, n_cols, k, device) -> (n_rows, n_cols, k, C, device)
438        let (n_rows, n_cols, k, device) = self;
439        let default_order = device.default_order();
440        eye_f((n_rows, n_cols, k, default_order, device))
441    }
442}
443
444impl<T, B> EyeAPI<(T, B)> for (usize, &B)
445where
446    T: Num,
447    B: DeviceAPI<T> + DeviceCreationNumAPI<T> + OpAssignAPI<T, Ix1>,
448{
449    type Out = Tensor<T, B, IxD>;
450
451    fn eye_f(self) -> Result<Self::Out> {
452        // (n_rows, n_cols, k, device) -> (n_rows, n_cols, k, C, device)
453        let (n_rows, device) = self;
454        let default_order = device.default_order();
455        eye_f((n_rows, n_rows, 0, default_order, device))
456    }
457}
458
459impl<T> EyeAPI<T> for (usize, usize, isize, FlagOrder)
460where
461    T: Num + Clone + Send + Sync,
462{
463    type Out = Tensor<T, DeviceCpu, IxD>;
464
465    fn eye_f(self) -> Result<Self::Out> {
466        let (n_rows, n_cols, k, order) = self;
467        eye_f((n_rows, n_cols, k, order, &DeviceCpu::default()))
468    }
469}
470
471impl<T> EyeAPI<T> for (usize, usize, isize)
472where
473    T: Num + Clone + Send + Sync,
474{
475    type Out = Tensor<T, DeviceCpu, IxD>;
476
477    fn eye_f(self) -> Result<Self::Out> {
478        // (n_rows, n_cols, k) -> (n_rows, n_cols, k, C)
479        let (n_rows, n_cols, k) = self;
480        let device = DeviceCpu::default();
481        let default_order = device.default_order();
482        eye_f((n_rows, n_cols, k, default_order, &device))
483    }
484}
485
486impl<T> EyeAPI<T> for usize
487where
488    T: Num + Clone + Send + Sync,
489{
490    type Out = Tensor<T, DeviceCpu, IxD>;
491
492    fn eye_f(self) -> Result<Self::Out> {
493        // n_rows -> (n_rows, n_rows, 0, C)
494        let device = DeviceCpu::default();
495        let default_order = device.default_order();
496        eye_f((self, self, 0, default_order, &device))
497    }
498}
499
500/* #endregion */
501
502/* #region full */
503
504pub trait FullAPI<Inp> {
505    type Out;
506
507    fn full_f(self) -> Result<Self::Out>;
508
509    fn full(self) -> Self::Out
510    where
511        Self: Sized,
512    {
513        Self::full_f(self).rstsr_unwrap()
514    }
515}
516
517/// New tensor having a specified shape and filled with given value.
518///
519/// # See also
520///
521/// - [Python array API standard: `full`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.full.html)
522pub fn full<Args, Inp>(param: Args) -> Args::Out
523where
524    Args: FullAPI<Inp>,
525{
526    return FullAPI::full(param);
527}
528
529pub fn full_f<Args, Inp>(param: Args) -> Result<Args::Out>
530where
531    Args: FullAPI<Inp>,
532{
533    return FullAPI::full_f(param);
534}
535
536impl<T, D, B> FullAPI<(T, D)> for (Layout<D>, T, &B)
537where
538    T: Clone,
539    D: DimAPI,
540    B: DeviceAPI<T> + DeviceCreationAnyAPI<T>,
541{
542    type Out = Tensor<T, B, IxD>;
543
544    fn full_f(self) -> Result<Self::Out> {
545        let (layout, fill, device) = self;
546        let idx_max = layout.size();
547        let storage = device.full_impl(idx_max, fill)?;
548        unsafe { Ok(Tensor::new_unchecked(storage, layout.into_dim()?)) }
549    }
550}
551
552impl<T, D, B> FullAPI<(T, D)> for (D, T, FlagOrder, &B)
553where
554    T: Clone,
555    D: DimAPI,
556    B: DeviceAPI<T> + DeviceCreationAnyAPI<T>,
557{
558    type Out = Tensor<T, B, IxD>;
559
560    fn full_f(self) -> Result<Self::Out> {
561        let (shape, fill, order, device) = self;
562        let layout = shape.new_contig(None, order);
563        full_f((layout, fill, device))
564    }
565}
566
567impl<T, D, B> FullAPI<(T, D)> for (D, T, &B)
568where
569    T: Clone,
570    D: DimAPI,
571    B: DeviceAPI<T> + DeviceCreationAnyAPI<T>,
572{
573    type Out = Tensor<T, B, IxD>;
574
575    fn full_f(self) -> Result<Self::Out> {
576        let (shape, fill, device) = self;
577        let default_order = device.default_order();
578        let layout = shape.new_contig(None, default_order);
579        full_f((layout, fill, device))
580    }
581}
582
583impl<T, D> FullAPI<(T, D)> for (D, T, FlagOrder)
584where
585    T: Clone,
586    D: DimAPI,
587{
588    type Out = Tensor<T, DeviceCpu, IxD>;
589
590    fn full_f(self) -> Result<Self::Out> {
591        let (shape, fill, order) = self;
592        full_f((shape, fill, order, &DeviceCpu::default()))
593    }
594}
595
596#[duplicate_item(L; [D]; [Layout<D>])]
597impl<T, D> FullAPI<(T, D)> for (L, T)
598where
599    T: Clone,
600    D: DimAPI,
601{
602    type Out = Tensor<T, DeviceCpu, IxD>;
603
604    fn full_f(self) -> Result<Self::Out> {
605        let (shape, fill) = self;
606        full_f((shape, fill, &DeviceCpu::default()))
607    }
608}
609
610/* #endregion */
611
612/* #region full_like */
613
614pub trait FullLikeAPI<Inp> {
615    type Out;
616
617    fn full_like_f(self) -> Result<Self::Out>;
618
619    fn full_like(self) -> Self::Out
620    where
621        Self: Sized,
622    {
623        Self::full_like_f(self).rstsr_unwrap()
624    }
625}
626
627/// New tensor filled with given value and having the same shape as an input
628/// tensor.
629///
630/// # See also
631///
632/// - [Python array API standard: `full_like`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.full_like.html)
633pub fn full_like<Args, Inp>(param: Args) -> Args::Out
634where
635    Args: FullLikeAPI<Inp>,
636{
637    return FullLikeAPI::full_like(param);
638}
639
640pub fn full_like_f<Args, Inp>(param: Args) -> Result<Args::Out>
641where
642    Args: FullLikeAPI<Inp>,
643{
644    return FullLikeAPI::full_like_f(param);
645}
646
647impl<R, T, B, D> FullLikeAPI<()> for (&TensorAny<R, T, B, D>, T, TensorIterOrder, &B)
648where
649    T: Clone,
650    R: DataAPI<Data = B::Raw>,
651    D: DimAPI,
652    B: DeviceAPI<T> + DeviceCreationAnyAPI<T>,
653{
654    type Out = Tensor<T, B, D>;
655
656    fn full_like_f(self) -> Result<Self::Out> {
657        let (tensor, fill, order, device) = self;
658        let layout = layout_for_array_copy(tensor.layout(), order)?;
659        let idx_max = layout.size();
660        let storage = device.full_impl(idx_max, fill)?;
661        unsafe { Ok(Tensor::new_unchecked(storage, layout)) }
662    }
663}
664
665impl<R, T, B, D> FullLikeAPI<()> for (&TensorAny<R, T, B, D>, T, &B)
666where
667    T: Clone,
668    R: DataAPI<Data = B::Raw>,
669    D: DimAPI,
670    B: DeviceAPI<T> + DeviceCreationAnyAPI<T>,
671{
672    type Out = Tensor<T, B, D>;
673
674    fn full_like_f(self) -> Result<Self::Out> {
675        let (tensor, fill, device) = self;
676        full_like_f((tensor, fill, TensorIterOrder::default(), device))
677    }
678}
679
680impl<R, T, B, D> FullLikeAPI<()> for (&TensorAny<R, T, B, D>, T, TensorIterOrder)
681where
682    T: Clone,
683    R: DataAPI<Data = B::Raw>,
684    D: DimAPI,
685    B: DeviceAPI<T> + DeviceCreationAnyAPI<T>,
686{
687    type Out = Tensor<T, B, D>;
688
689    fn full_like_f(self) -> Result<Self::Out> {
690        let (tensor, fill, order) = self;
691        let device = tensor.device();
692        full_like_f((tensor, fill, order, device))
693    }
694}
695
696impl<R, T, B, D> FullLikeAPI<()> for (&TensorAny<R, T, B, D>, T)
697where
698    T: Clone,
699    R: DataAPI<Data = B::Raw>,
700    D: DimAPI,
701    B: DeviceAPI<T> + DeviceCreationAnyAPI<T>,
702{
703    type Out = Tensor<T, B, D>;
704
705    fn full_like_f(self) -> Result<Self::Out> {
706        let (tensor, fill) = self;
707        let device = tensor.device();
708        full_like_f((tensor, fill, TensorIterOrder::default(), device))
709    }
710}
711
712impl<R, T, B, D> TensorAny<R, T, B, D>
713where
714    R: DataAPI<Data = B::Raw>,
715    T: Clone,
716    D: DimAPI,
717    B: DeviceAPI<T> + DeviceCreationAnyAPI<T>,
718{
719    pub fn full_like(&self, fill: T) -> Tensor<T, B, D> {
720        full_like((self, fill))
721    }
722
723    pub fn full_like_f(&self, fill: T) -> Result<Tensor<T, B, D>> {
724        full_like_f((self, fill))
725    }
726}
727
728/* #endregion */
729
730/* #region linspace */
731
732pub trait LinspaceAPI<Inp> {
733    type Out;
734
735    fn linspace_f(self) -> Result<Self::Out>;
736
737    fn linspace(self) -> Self::Out
738    where
739        Self: Sized,
740    {
741        Self::linspace_f(self).rstsr_unwrap()
742    }
743}
744
745/// Evenly spaced numbers over a specified interval.
746///
747/// For boundary condition, current implementation is similar to numpy,
748/// where `n = 0` will return an empty array, and `n = 1` will return an
749/// array with starting value.
750///
751/// # See also
752///
753/// - [Python array API standard: `linspace`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.linspace.html)
754pub fn linspace<Args, Inp>(param: Args) -> Args::Out
755where
756    Args: LinspaceAPI<Inp>,
757{
758    return LinspaceAPI::linspace(param);
759}
760
761pub fn linspace_f<Args, Inp>(param: Args) -> Result<Args::Out>
762where
763    Args: LinspaceAPI<Inp>,
764{
765    return LinspaceAPI::linspace_f(param);
766}
767
768impl<T, B> LinspaceAPI<(T, B)> for (T, T, usize, bool, &B)
769where
770    T: ComplexFloat,
771    B: DeviceAPI<T> + DeviceCreationComplexFloatAPI<T>,
772{
773    type Out = Tensor<T, B, IxD>;
774
775    fn linspace_f(self) -> Result<Self::Out> {
776        let (start, end, n, endpoint, device) = self;
777        let data = B::linspace_impl(device, start, end, n, endpoint)?;
778        let layout = vec![data.len()].into();
779        unsafe { Ok(Tensor::new_unchecked(data, layout)) }
780    }
781}
782
783impl<T, B> LinspaceAPI<(T, B)> for (T, T, usize, &B)
784where
785    T: ComplexFloat,
786    B: DeviceAPI<T> + DeviceCreationComplexFloatAPI<T>,
787{
788    type Out = Tensor<T, B, IxD>;
789
790    fn linspace_f(self) -> Result<Self::Out> {
791        // (start, end, n, device) -> (start, end, n, true, device)
792        let (start, end, n, device) = self;
793        linspace_f((start, end, n, true, device))
794    }
795}
796
797impl<T> LinspaceAPI<T> for (T, T, usize, bool)
798where
799    T: ComplexFloat + Send + Sync,
800{
801    type Out = Tensor<T, DeviceCpu, IxD>;
802
803    fn linspace_f(self) -> Result<Self::Out> {
804        // (start, end, n, endpoint) -> (start, end, n, endpoint, device)
805        let (start, end, n, endpoint) = self;
806        linspace_f((start, end, n, endpoint, &DeviceCpu::default()))
807    }
808}
809
810impl<T> LinspaceAPI<T> for (T, T, usize)
811where
812    T: ComplexFloat + Send + Sync,
813{
814    type Out = Tensor<T, DeviceCpu, IxD>;
815
816    fn linspace_f(self) -> Result<Self::Out> {
817        // (start, end, n) -> (start, end, n, true, device)
818        let (start, end, n) = self;
819        linspace_f((start, end, n, true, &DeviceCpu::default()))
820    }
821}
822
823/* #endregion */
824
825/* #region ones */
826
827pub trait OnesAPI<Inp> {
828    type Out;
829
830    fn ones_f(self) -> Result<Self::Out>;
831
832    fn ones(self) -> Self::Out
833    where
834        Self: Sized,
835    {
836        Self::ones_f(self).rstsr_unwrap()
837    }
838}
839
840/// New tensor filled with ones and having a specified shape.
841///
842/// # See also
843///
844/// - [Python array API standard: `ones`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.ones.html)
845pub fn ones<Args, Inp>(param: Args) -> Args::Out
846where
847    Args: OnesAPI<Inp>,
848{
849    return OnesAPI::ones(param);
850}
851
852pub fn ones_f<Args, Inp>(param: Args) -> Result<Args::Out>
853where
854    Args: OnesAPI<Inp>,
855{
856    return OnesAPI::ones_f(param);
857}
858
859impl<T, D, B> OnesAPI<(T, D)> for (Layout<D>, &B)
860where
861    T: Num,
862    D: DimAPI,
863    B: DeviceAPI<T> + DeviceCreationNumAPI<T>,
864{
865    type Out = Tensor<T, B, IxD>;
866
867    fn ones_f(self) -> Result<Self::Out> {
868        let (layout, device) = self;
869        let (_, idx_max) = layout.bounds_index()?;
870        let storage = device.ones_impl(idx_max)?;
871        unsafe { Ok(Tensor::new_unchecked(storage, layout.into_dim()?)) }
872    }
873}
874
875impl<T, D, B> OnesAPI<(T, D)> for (D, FlagOrder, &B)
876where
877    T: Num,
878    D: DimAPI,
879    B: DeviceAPI<T> + DeviceCreationNumAPI<T>,
880{
881    type Out = Tensor<T, B, IxD>;
882
883    fn ones_f(self) -> Result<Self::Out> {
884        let (shape, order, device) = self;
885        let layout = shape.new_contig(None, order);
886        ones_f((layout, device))
887    }
888}
889
890impl<T, D, B> OnesAPI<(T, D)> for (D, &B)
891where
892    T: Num,
893    D: DimAPI,
894    B: DeviceAPI<T> + DeviceCreationNumAPI<T>,
895{
896    type Out = Tensor<T, B, IxD>;
897
898    fn ones_f(self) -> Result<Self::Out> {
899        let (shape, device) = self;
900        let default_order = device.default_order();
901        let layout = shape.new_contig(None, default_order);
902        ones_f((layout, device))
903    }
904}
905
906impl<T, D> OnesAPI<(T, D)> for (D, FlagOrder)
907where
908    T: Num + Clone,
909    D: DimAPI,
910{
911    type Out = Tensor<T, DeviceCpu, IxD>;
912
913    fn ones_f(self) -> Result<Self::Out> {
914        let (shape, order) = self;
915        ones_f((shape, order, &DeviceCpu::default()))
916    }
917}
918
919#[duplicate_item(L; [D]; [Layout<D>])]
920impl<T, D> OnesAPI<(T, D)> for L
921where
922    T: Num + Clone,
923    D: DimAPI,
924{
925    type Out = Tensor<T, DeviceCpu, IxD>;
926
927    fn ones_f(self) -> Result<Self::Out> {
928        ones_f((self, &DeviceCpu::default()))
929    }
930}
931
932/* #endregion */
933
934/* #region ones_like */
935
936pub trait OnesLikeAPI<Inp> {
937    type Out;
938
939    fn ones_like_f(self) -> Result<Self::Out>;
940
941    fn ones_like(self) -> Self::Out
942    where
943        Self: Sized,
944    {
945        Self::ones_like_f(self).rstsr_unwrap()
946    }
947}
948
949/// New tensor filled with ones and having the same shape as an input
950/// tensor.
951///
952/// # See also
953///
954/// - [Python array API standard: `ones_like`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.ones_like.html)
955pub fn ones_like<Args, Inp>(param: Args) -> Args::Out
956where
957    Args: OnesLikeAPI<Inp>,
958{
959    return OnesLikeAPI::ones_like(param);
960}
961
962pub fn ones_like_f<Args, Inp>(param: Args) -> Result<Args::Out>
963where
964    Args: OnesLikeAPI<Inp>,
965{
966    return OnesLikeAPI::ones_like_f(param);
967}
968
969impl<R, T, B, D> OnesLikeAPI<()> for (&TensorAny<R, T, B, D>, TensorIterOrder, &B)
970where
971    R: DataAPI<Data = B::Raw>,
972    T: Num,
973    D: DimAPI,
974    B: DeviceAPI<T> + DeviceCreationNumAPI<T>,
975{
976    type Out = Tensor<T, B, D>;
977
978    fn ones_like_f(self) -> Result<Self::Out> {
979        let (tensor, order, device) = self;
980        let layout = layout_for_array_copy(tensor.layout(), order)?;
981        let idx_max = layout.size();
982        let storage = device.ones_impl(idx_max)?;
983        unsafe { Ok(Tensor::new_unchecked(storage, layout)) }
984    }
985}
986
987impl<R, T, B, D> OnesLikeAPI<()> for (&TensorAny<R, T, B, D>, &B)
988where
989    R: DataAPI<Data = B::Raw>,
990    T: Num,
991    D: DimAPI,
992    B: DeviceAPI<T> + DeviceCreationNumAPI<T>,
993{
994    type Out = Tensor<T, B, D>;
995
996    fn ones_like_f(self) -> Result<Self::Out> {
997        let (tensor, device) = self;
998        ones_like_f((tensor, TensorIterOrder::default(), device))
999    }
1000}
1001
1002impl<R, T, B, D> OnesLikeAPI<()> for (&TensorAny<R, T, B, D>, TensorIterOrder)
1003where
1004    R: DataAPI<Data = B::Raw>,
1005    T: Num,
1006    D: DimAPI,
1007    B: DeviceAPI<T> + DeviceCreationNumAPI<T>,
1008{
1009    type Out = Tensor<T, B, D>;
1010
1011    fn ones_like_f(self) -> Result<Self::Out> {
1012        let (tensor, order) = self;
1013        let device = tensor.device();
1014        ones_like_f((tensor, order, device))
1015    }
1016}
1017
1018impl<R, T, B, D> OnesLikeAPI<()> for &TensorAny<R, T, B, D>
1019where
1020    R: DataAPI<Data = B::Raw>,
1021    T: Num,
1022    D: DimAPI,
1023    B: DeviceAPI<T> + DeviceCreationNumAPI<T>,
1024{
1025    type Out = Tensor<T, B, D>;
1026
1027    fn ones_like_f(self) -> Result<Self::Out> {
1028        let device = self.device();
1029        ones_like_f((self, TensorIterOrder::default(), device))
1030    }
1031}
1032
1033impl<R, T, B, D> TensorAny<R, T, B, D>
1034where
1035    R: DataAPI<Data = B::Raw>,
1036    D: DimAPI,
1037    T: Num,
1038    B: DeviceAPI<T> + DeviceCreationNumAPI<T>,
1039{
1040    /// New tensor filled with ones and having the same shape as an input
1041    /// tensor.
1042    ///
1043    /// # See also
1044    ///
1045    /// [`ones_like`]
1046    pub fn ones_like(&self) -> Tensor<T, B, D> {
1047        ones_like((self, TensorIterOrder::default(), self.device()))
1048    }
1049
1050    pub fn ones_like_f(&self) -> Result<Tensor<T, B, D>> {
1051        ones_like_f((self, TensorIterOrder::default(), self.device()))
1052    }
1053}
1054
1055/* #endregion */
1056
1057/* #region uninit */
1058
1059pub trait UninitAPI<Inp> {
1060    type Out;
1061
1062    fn uninit_f(self) -> Result<Self::Out>;
1063
1064    fn uninit(self) -> Self::Out
1065    where
1066        Self: Sized,
1067    {
1068        Self::uninit_f(self).rstsr_unwrap()
1069    }
1070}
1071
1072/// New tensor filled with uninitialized values and having a specified shape.
1073pub fn uninit<Args, Inp>(param: Args) -> Args::Out
1074where
1075    Args: UninitAPI<Inp>,
1076{
1077    return UninitAPI::uninit(param);
1078}
1079
1080pub fn uninit_f<Args, Inp>(param: Args) -> Result<Args::Out>
1081where
1082    Args: UninitAPI<Inp>,
1083{
1084    return UninitAPI::uninit_f(param);
1085}
1086
1087impl<T, D, B> UninitAPI<(T, D)> for (Layout<D>, &B)
1088where
1089    D: DimAPI,
1090    B: DeviceRawAPI<MaybeUninit<T>> + DeviceCreationAnyAPI<T>,
1091{
1092    type Out = Tensor<MaybeUninit<T>, B, IxD>;
1093
1094    fn uninit_f(self) -> Result<Self::Out> {
1095        let (layout, device) = self;
1096        let (_, idx_max) = layout.bounds_index()?;
1097        let storage = B::uninit_impl(device, idx_max)?;
1098        unsafe { Ok(Tensor::new_unchecked(storage, layout.into_dim()?)) }
1099    }
1100}
1101
1102impl<T, D, B> UninitAPI<(T, D)> for (D, FlagOrder, &B)
1103where
1104    D: DimAPI,
1105    B: DeviceRawAPI<MaybeUninit<T>> + DeviceCreationAnyAPI<T>,
1106{
1107    type Out = Tensor<MaybeUninit<T>, B, IxD>;
1108
1109    fn uninit_f(self) -> Result<Self::Out> {
1110        let (shape, order, device) = self;
1111        let layout = shape.new_contig(None, order);
1112        uninit_f((layout, device))
1113    }
1114}
1115
1116impl<T, D, B> UninitAPI<(T, D)> for (D, &B)
1117where
1118    D: DimAPI,
1119    B: DeviceRawAPI<MaybeUninit<T>> + DeviceCreationAnyAPI<T>,
1120{
1121    type Out = Tensor<MaybeUninit<T>, B, IxD>;
1122
1123    fn uninit_f(self) -> Result<Self::Out> {
1124        let (shape, device) = self;
1125        let default_order = device.default_order();
1126        let layout = shape.new_contig(None, default_order);
1127        uninit_f((layout, device))
1128    }
1129}
1130
1131impl<T, D> UninitAPI<(T, D)> for (D, FlagOrder)
1132where
1133    T: Clone,
1134    D: DimAPI,
1135{
1136    type Out = Tensor<MaybeUninit<T>, DeviceCpu, IxD>;
1137
1138    fn uninit_f(self) -> Result<Self::Out> {
1139        let (shape, order) = self;
1140        uninit_f((shape, order, &DeviceCpu::default()))
1141    }
1142}
1143
1144#[duplicate_item(L; [D]; [Layout<D>])]
1145impl<T, D> UninitAPI<(T, D)> for L
1146where
1147    T: Clone,
1148    D: DimAPI,
1149{
1150    type Out = Tensor<MaybeUninit<T>, DeviceCpu, IxD>;
1151
1152    fn uninit_f(self) -> Result<Self::Out> {
1153        uninit_f((self, &DeviceCpu::default()))
1154    }
1155}
1156
1157/* #endregion */
1158
1159/* #region assume_init */
1160
1161/// Converts a tensor with uninitialized values into a tensor with initialized values.
1162///
1163/// # Safety
1164///
1165/// This function is unsafe because it assumes that all elements in the input tensor are properly
1166/// initialized.
1167pub unsafe fn assume_init_f<T, B, D>(tensor: Tensor<MaybeUninit<T>, B, D>) -> Result<Tensor<T, B, D>>
1168where
1169    D: DimAPI,
1170    B: DeviceAPI<T> + DeviceAPI<MaybeUninit<T>> + DeviceCreationAnyAPI<T>,
1171{
1172    let (storage, layout) = tensor.into_raw_parts();
1173    let storage = B::assume_init_impl(storage)?;
1174    unsafe { Ok(Tensor::new_unchecked(storage, layout)) }
1175}
1176
1177/// Converts a tensor with uninitialized values into a tensor with initialized values.
1178///
1179/// # Safety
1180///
1181/// This function is unsafe because it assumes that all elements in the input tensor are properly
1182/// initialized.
1183pub unsafe fn assume_init<T, B, D>(tensor: Tensor<MaybeUninit<T>, B, D>) -> Tensor<T, B, D>
1184where
1185    D: DimAPI,
1186    B: DeviceAPI<T> + DeviceAPI<MaybeUninit<T>> + DeviceCreationAnyAPI<T>,
1187{
1188    unsafe { assume_init_f(tensor).rstsr_unwrap() }
1189}
1190
1191/* #endregion */
1192
1193/* #region zeros */
1194
1195pub trait ZerosAPI<Inp> {
1196    type Out;
1197
1198    fn zeros_f(self) -> Result<Self::Out>;
1199
1200    fn zeros(self) -> Self::Out
1201    where
1202        Self: Sized,
1203    {
1204        Self::zeros_f(self).rstsr_unwrap()
1205    }
1206}
1207
1208/// New tensor filled with zeros and having a specified shape.
1209///
1210/// # See also
1211///
1212/// - [Python array API standard: `zeros`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.zeros.html)
1213pub fn zeros<Args, Inp>(param: Args) -> Args::Out
1214where
1215    Args: ZerosAPI<Inp>,
1216{
1217    return ZerosAPI::zeros(param);
1218}
1219
1220pub fn zeros_f<Args, Inp>(param: Args) -> Result<Args::Out>
1221where
1222    Args: ZerosAPI<Inp>,
1223{
1224    return ZerosAPI::zeros_f(param);
1225}
1226
1227impl<T, D, B> ZerosAPI<(T, D)> for (Layout<D>, &B)
1228where
1229    T: Num,
1230    D: DimAPI,
1231    B: DeviceAPI<T> + DeviceCreationNumAPI<T>,
1232{
1233    type Out = Tensor<T, B, IxD>;
1234
1235    fn zeros_f(self) -> Result<Self::Out> {
1236        let (layout, device) = self;
1237        let (_, idx_max) = layout.bounds_index()?;
1238        let storage = B::zeros_impl(device, idx_max)?;
1239        unsafe { Ok(Tensor::new_unchecked(storage, layout.into_dim()?)) }
1240    }
1241}
1242
1243impl<T, D, B> ZerosAPI<(T, D)> for (D, FlagOrder, &B)
1244where
1245    T: Num,
1246    D: DimAPI,
1247    B: DeviceAPI<T> + DeviceCreationNumAPI<T>,
1248{
1249    type Out = Tensor<T, B, IxD>;
1250
1251    fn zeros_f(self) -> Result<Self::Out> {
1252        let (shape, order, device) = self;
1253        let layout = shape.new_contig(None, order);
1254        zeros_f((layout, device))
1255    }
1256}
1257
1258impl<T, D, B> ZerosAPI<(T, D)> for (D, &B)
1259where
1260    T: Num,
1261    D: DimAPI,
1262    B: DeviceAPI<T> + DeviceCreationNumAPI<T>,
1263{
1264    type Out = Tensor<T, B, IxD>;
1265
1266    fn zeros_f(self) -> Result<Self::Out> {
1267        let (shape, device) = self;
1268        let default_order = device.default_order();
1269        let layout = shape.new_contig(None, default_order);
1270        zeros_f((layout, device))
1271    }
1272}
1273
1274impl<T, D> ZerosAPI<(T, D)> for (D, FlagOrder)
1275where
1276    T: Num + Clone,
1277    D: DimAPI,
1278{
1279    type Out = Tensor<T, DeviceCpu, IxD>;
1280
1281    fn zeros_f(self) -> Result<Self::Out> {
1282        let (shape, order) = self;
1283        zeros_f((shape, order, &DeviceCpu::default()))
1284    }
1285}
1286
1287#[duplicate_item(L; [D]; [Layout<D>])]
1288impl<T, D> ZerosAPI<(T, D)> for L
1289where
1290    T: Num + Clone,
1291    D: DimAPI,
1292{
1293    type Out = Tensor<T, DeviceCpu, IxD>;
1294
1295    fn zeros_f(self) -> Result<Self::Out> {
1296        zeros_f((self, &DeviceCpu::default()))
1297    }
1298}
1299
1300/* #endregion */
1301
1302/* #region zeros_like */
1303
1304pub trait ZerosLikeAPI<Inp> {
1305    type Out;
1306
1307    fn zeros_like_f(self) -> Result<Self::Out>;
1308
1309    fn zeros_like(self) -> Self::Out
1310    where
1311        Self: Sized,
1312    {
1313        Self::zeros_like_f(self).rstsr_unwrap()
1314    }
1315}
1316
1317/// New tensor filled with zeros and having the same shape as an input
1318/// tensor.
1319///
1320/// # See also
1321///
1322/// - [Python array API standard: `zeros_like`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.zeros_like.html)
1323pub fn zeros_like<Args, Inp>(param: Args) -> Args::Out
1324where
1325    Args: ZerosLikeAPI<Inp>,
1326{
1327    return ZerosLikeAPI::zeros_like(param);
1328}
1329
1330pub fn zeros_like_f<Args, Inp>(param: Args) -> Result<Args::Out>
1331where
1332    Args: ZerosLikeAPI<Inp>,
1333{
1334    return ZerosLikeAPI::zeros_like_f(param);
1335}
1336
1337impl<R, T, B, D> ZerosLikeAPI<()> for (&TensorAny<R, T, B, D>, TensorIterOrder, &B)
1338where
1339    R: DataAPI<Data = B::Raw>,
1340    T: Num,
1341    D: DimAPI,
1342    B: DeviceAPI<T> + DeviceCreationNumAPI<T>,
1343{
1344    type Out = Tensor<T, B, D>;
1345
1346    fn zeros_like_f(self) -> Result<Self::Out> {
1347        let (tensor, order, device) = self;
1348        let layout = layout_for_array_copy(tensor.layout(), order)?;
1349        let idx_max = layout.size();
1350        let storage = B::zeros_impl(device, idx_max)?;
1351        unsafe { Ok(Tensor::new_unchecked(storage, layout)) }
1352    }
1353}
1354
1355impl<R, T, B, D> ZerosLikeAPI<()> for (&TensorAny<R, T, B, D>, &B)
1356where
1357    R: DataAPI<Data = B::Raw>,
1358    T: Num,
1359    D: DimAPI,
1360    B: DeviceAPI<T> + DeviceCreationNumAPI<T>,
1361{
1362    type Out = Tensor<T, B, D>;
1363
1364    fn zeros_like_f(self) -> Result<Self::Out> {
1365        let (tensor, device) = self;
1366        zeros_like_f((tensor, TensorIterOrder::default(), device))
1367    }
1368}
1369
1370impl<R, T, B, D> ZerosLikeAPI<()> for (&TensorAny<R, T, B, D>, TensorIterOrder)
1371where
1372    R: DataAPI<Data = B::Raw>,
1373    T: Num,
1374    D: DimAPI,
1375    B: DeviceAPI<T> + DeviceCreationNumAPI<T>,
1376{
1377    type Out = Tensor<T, B, D>;
1378
1379    fn zeros_like_f(self) -> Result<Self::Out> {
1380        let (tensor, order) = self;
1381        let device = tensor.device();
1382        zeros_like_f((tensor, order, device))
1383    }
1384}
1385
1386impl<R, T, B, D> ZerosLikeAPI<()> for &TensorAny<R, T, B, D>
1387where
1388    R: DataAPI<Data = B::Raw>,
1389    T: Num,
1390    D: DimAPI,
1391    B: DeviceAPI<T> + DeviceCreationNumAPI<T>,
1392{
1393    type Out = Tensor<T, B, D>;
1394
1395    fn zeros_like_f(self) -> Result<Self::Out> {
1396        zeros_like_f((self, TensorIterOrder::default(), self.device()))
1397    }
1398}
1399
1400impl<R, T, B, D> TensorAny<R, T, B, D>
1401where
1402    R: DataAPI<Data = B::Raw>,
1403    D: DimAPI,
1404    T: Num,
1405    B: DeviceAPI<T> + DeviceCreationNumAPI<T>,
1406{
1407    /// New tensor filled with zeros and having the same shape as an input
1408    /// tensor.
1409    ///
1410    /// # See also
1411    ///
1412    /// [`zeros_like`]
1413    pub fn zeros_like(&self) -> Tensor<T, B, D> {
1414        zeros_like((self, TensorIterOrder::default(), self.device()))
1415    }
1416
1417    pub fn zeros_like_f(&self) -> Result<Tensor<T, B, D>> {
1418        zeros_like_f((self, TensorIterOrder::default(), self.device()))
1419    }
1420}
1421
1422/* #endregion */
1423
1424/* #region tril */
1425
1426pub trait TrilAPI<Inp> {
1427    type Out;
1428
1429    fn tril_f(self) -> Result<Self::Out>;
1430
1431    fn tril(self) -> Self::Out
1432    where
1433        Self: Sized,
1434    {
1435        Self::tril_f(self).rstsr_unwrap()
1436    }
1437}
1438
1439/// Returns the lower triangular part of a matrix (or a stack of matrices) x.
1440///
1441/// # See also
1442///
1443/// - [Python array API standard: `tril`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.tril.html)
1444pub fn tril<Args, Inp>(param: Args) -> Args::Out
1445where
1446    Args: TrilAPI<Inp>,
1447{
1448    return TrilAPI::tril(param);
1449}
1450
1451pub fn tril_f<Args, Inp>(param: Args) -> Result<Args::Out>
1452where
1453    Args: TrilAPI<Inp>,
1454{
1455    return TrilAPI::tril_f(param);
1456}
1457
1458impl<T, D, B> TrilAPI<()> for (TensorView<'_, T, B, D>, isize)
1459where
1460    T: Num + Clone,
1461    D: DimAPI,
1462    B: DeviceAPI<T>
1463        + DeviceRawAPI<MaybeUninit<T>>
1464        + DeviceCreationTriAPI<T>
1465        + DeviceCreationAnyAPI<T>
1466        + OpAssignArbitaryAPI<T, D, D>
1467        + OpAssignAPI<T, D>,
1468    <B as DeviceRawAPI<T>>::Raw: Clone,
1469{
1470    type Out = Tensor<T, B, D>;
1471
1472    fn tril_f(self) -> Result<Self::Out> {
1473        let (x, k) = self;
1474        let default_order = x.device().default_order();
1475        let mut x = x.into_contig_f(default_order)?;
1476        let device = x.device().clone();
1477        let layout = x.layout().clone();
1478        device.tril_impl(x.raw_mut(), &layout, k)?;
1479        Ok(x)
1480    }
1481}
1482
1483impl<T, D, B> TrilAPI<()> for TensorView<'_, T, B, D>
1484where
1485    T: Num + Clone,
1486    D: DimAPI,
1487    B: DeviceAPI<T>
1488        + DeviceRawAPI<MaybeUninit<T>>
1489        + DeviceCreationTriAPI<T>
1490        + DeviceCreationAnyAPI<T>
1491        + OpAssignArbitaryAPI<T, D, D>
1492        + OpAssignAPI<T, D>,
1493    <B as DeviceRawAPI<T>>::Raw: Clone,
1494{
1495    type Out = Tensor<T, B, D>;
1496
1497    fn tril_f(self) -> Result<Self::Out> {
1498        tril_f((self, 0))
1499    }
1500}
1501
1502impl<'a, T, D, B> TrilAPI<()> for (TensorMut<'a, T, B, D>, isize)
1503where
1504    T: Num + Clone,
1505    D: DimAPI,
1506    B: DeviceAPI<T>
1507        + DeviceCreationTriAPI<T>
1508        + DeviceCreationAnyAPI<T>
1509        + OpAssignArbitaryAPI<T, D, D>
1510        + OpAssignAPI<T, D>,
1511{
1512    type Out = TensorMut<'a, T, B, D>;
1513
1514    fn tril_f(self) -> Result<Self::Out> {
1515        let (mut x, k) = self;
1516        let device = x.device().clone();
1517        let layout = x.layout().clone();
1518        device.tril_impl(x.raw_mut(), &layout, k)?;
1519        Ok(x)
1520    }
1521}
1522
1523impl<'a, T, D, B> TrilAPI<()> for TensorMut<'a, T, B, D>
1524where
1525    T: Num + Clone,
1526    D: DimAPI,
1527    B: DeviceAPI<T>
1528        + DeviceCreationTriAPI<T>
1529        + DeviceCreationAnyAPI<T>
1530        + OpAssignArbitaryAPI<T, D, D>
1531        + OpAssignAPI<T, D>,
1532{
1533    type Out = TensorMut<'a, T, B, D>;
1534
1535    fn tril_f(self) -> Result<Self::Out> {
1536        tril_f((self, 0))
1537    }
1538}
1539
1540impl<T, D, B> TrilAPI<()> for (Tensor<T, B, D>, isize)
1541where
1542    T: Num + Clone,
1543    D: DimAPI,
1544    B: DeviceAPI<T> + DeviceCreationTriAPI<T> + DeviceCreationAnyAPI<T>,
1545{
1546    type Out = Tensor<T, B, D>;
1547
1548    fn tril_f(self) -> Result<Self::Out> {
1549        let (mut x, k) = self;
1550        let device = x.device().clone();
1551        let layout = x.layout().clone();
1552        device.tril_impl(x.raw_mut(), &layout, k)?;
1553        Ok(x)
1554    }
1555}
1556
1557impl<T, D, B> TrilAPI<()> for Tensor<T, B, D>
1558where
1559    T: Num + Clone,
1560    D: DimAPI,
1561    B: DeviceAPI<T> + DeviceCreationTriAPI<T> + DeviceCreationAnyAPI<T>,
1562{
1563    type Out = Tensor<T, B, D>;
1564
1565    fn tril_f(self) -> Result<Self::Out> {
1566        tril_f((self, 0))
1567    }
1568}
1569
1570impl<R, T, D, B> TrilAPI<()> for (&TensorAny<R, T, B, D>, isize)
1571where
1572    R: DataAPI<Data = <B as DeviceRawAPI<T>>::Raw>,
1573    T: Num + Clone,
1574    D: DimAPI,
1575    B: DeviceAPI<T>
1576        + DeviceRawAPI<MaybeUninit<T>>
1577        + DeviceCreationTriAPI<T>
1578        + DeviceCreationAnyAPI<T>
1579        + OpAssignArbitaryAPI<T, D, D>
1580        + OpAssignAPI<T, D>,
1581    <B as DeviceRawAPI<T>>::Raw: Clone,
1582{
1583    type Out = Tensor<T, B, D>;
1584
1585    fn tril_f(self) -> Result<Self::Out> {
1586        let (x, k) = self;
1587        tril_f((x.view(), k))
1588    }
1589}
1590
1591impl<R, T, D, B> TrilAPI<()> for &TensorAny<R, T, B, D>
1592where
1593    R: DataAPI<Data = <B as DeviceRawAPI<T>>::Raw>,
1594    T: Num + Clone,
1595    D: DimAPI,
1596    B: DeviceAPI<T>
1597        + DeviceRawAPI<MaybeUninit<T>>
1598        + DeviceCreationTriAPI<T>
1599        + DeviceCreationAnyAPI<T>
1600        + OpAssignArbitaryAPI<T, D, D>
1601        + OpAssignAPI<T, D>,
1602    <B as DeviceRawAPI<T>>::Raw: Clone,
1603{
1604    type Out = Tensor<T, B, D>;
1605
1606    fn tril_f(self) -> Result<Self::Out> {
1607        tril_f((self.view(), 0))
1608    }
1609}
1610
1611/* #endregion */
1612
1613/* #region triu */
1614
1615pub trait TriuAPI<Inp> {
1616    type Out;
1617
1618    fn triu_f(self) -> Result<Self::Out>;
1619
1620    fn triu(self) -> Self::Out
1621    where
1622        Self: Sized,
1623    {
1624        Self::triu_f(self).rstsr_unwrap()
1625    }
1626}
1627
1628/// Returns the upper triangular part of a matrix (or a stack of matrices) x.
1629///
1630/// # See also
1631///
1632/// - [Python array API standard: `triu`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.triu.html)
1633pub fn triu<Args, Inp>(param: Args) -> Args::Out
1634where
1635    Args: TriuAPI<Inp>,
1636{
1637    return TriuAPI::triu(param);
1638}
1639
1640pub fn triu_f<Args, Inp>(param: Args) -> Result<Args::Out>
1641where
1642    Args: TriuAPI<Inp>,
1643{
1644    return TriuAPI::triu_f(param);
1645}
1646
1647impl<T, D, B> TriuAPI<()> for (TensorView<'_, T, B, D>, isize)
1648where
1649    T: Num + Clone,
1650    D: DimAPI,
1651    B: DeviceAPI<T>
1652        + DeviceRawAPI<MaybeUninit<T>>
1653        + DeviceCreationTriAPI<T>
1654        + DeviceCreationAnyAPI<T>
1655        + OpAssignArbitaryAPI<T, D, D>
1656        + OpAssignAPI<T, D>,
1657    <B as DeviceRawAPI<T>>::Raw: Clone,
1658{
1659    type Out = Tensor<T, B, D>;
1660
1661    fn triu_f(self) -> Result<Self::Out> {
1662        let (x, k) = self;
1663        let default_order = x.device().default_order();
1664        let mut x = x.into_contig_f(default_order)?;
1665        let device = x.device().clone();
1666        let layout = x.layout().clone();
1667        device.triu_impl(x.raw_mut(), &layout, k)?;
1668        Ok(x)
1669    }
1670}
1671
1672impl<T, D, B> TriuAPI<()> for TensorView<'_, T, B, D>
1673where
1674    T: Num + Clone,
1675    D: DimAPI,
1676    B: DeviceAPI<T>
1677        + DeviceRawAPI<MaybeUninit<T>>
1678        + DeviceCreationTriAPI<T>
1679        + DeviceCreationAnyAPI<T>
1680        + OpAssignArbitaryAPI<T, D, D>
1681        + OpAssignAPI<T, D>,
1682    <B as DeviceRawAPI<T>>::Raw: Clone,
1683{
1684    type Out = Tensor<T, B, D>;
1685
1686    fn triu_f(self) -> Result<Self::Out> {
1687        triu_f((self, 0))
1688    }
1689}
1690
1691impl<'a, T, D, B> TriuAPI<()> for (TensorMut<'a, T, B, D>, isize)
1692where
1693    T: Num + Clone,
1694    D: DimAPI,
1695    B: DeviceAPI<T>
1696        + DeviceCreationTriAPI<T>
1697        + DeviceCreationAnyAPI<T>
1698        + OpAssignArbitaryAPI<T, D, D>
1699        + OpAssignAPI<T, D>,
1700{
1701    type Out = TensorMut<'a, T, B, D>;
1702
1703    fn triu_f(self) -> Result<Self::Out> {
1704        let (mut x, k) = self;
1705        let device = x.device().clone();
1706        let layout = x.layout().clone();
1707        device.triu_impl(x.raw_mut(), &layout, k)?;
1708        Ok(x)
1709    }
1710}
1711
1712impl<'a, T, D, B> TriuAPI<()> for TensorMut<'a, T, B, D>
1713where
1714    T: Num + Clone,
1715    D: DimAPI,
1716    B: DeviceAPI<T>
1717        + DeviceCreationTriAPI<T>
1718        + DeviceCreationAnyAPI<T>
1719        + OpAssignArbitaryAPI<T, D, D>
1720        + OpAssignAPI<T, D>,
1721{
1722    type Out = TensorMut<'a, T, B, D>;
1723
1724    fn triu_f(self) -> Result<Self::Out> {
1725        triu_f((self, 0))
1726    }
1727}
1728
1729impl<T, D, B> TriuAPI<()> for (Tensor<T, B, D>, isize)
1730where
1731    T: Num + Clone,
1732    D: DimAPI,
1733    B: DeviceAPI<T> + DeviceCreationTriAPI<T> + DeviceCreationAnyAPI<T>,
1734{
1735    type Out = Tensor<T, B, D>;
1736
1737    fn triu_f(self) -> Result<Self::Out> {
1738        let (mut x, k) = self;
1739        let device = x.device().clone();
1740        let layout = x.layout().clone();
1741        device.triu_impl(x.raw_mut(), &layout, k)?;
1742        Ok(x)
1743    }
1744}
1745
1746impl<T, D, B> TriuAPI<()> for Tensor<T, B, D>
1747where
1748    T: Num + Clone,
1749    D: DimAPI,
1750    B: DeviceAPI<T> + DeviceCreationTriAPI<T> + DeviceCreationAnyAPI<T>,
1751{
1752    type Out = Tensor<T, B, D>;
1753
1754    fn triu_f(self) -> Result<Self::Out> {
1755        triu_f((self, 0))
1756    }
1757}
1758
1759impl<R, T, D, B> TriuAPI<()> for (&TensorAny<R, T, B, D>, isize)
1760where
1761    R: DataAPI<Data = <B as DeviceRawAPI<T>>::Raw>,
1762    T: Num + Clone,
1763    D: DimAPI,
1764    B: DeviceAPI<T>
1765        + DeviceRawAPI<MaybeUninit<T>>
1766        + DeviceCreationTriAPI<T>
1767        + DeviceCreationAnyAPI<T>
1768        + OpAssignArbitaryAPI<T, D, D>
1769        + OpAssignAPI<T, D>,
1770    <B as DeviceRawAPI<T>>::Raw: Clone,
1771{
1772    type Out = Tensor<T, B, D>;
1773
1774    fn triu_f(self) -> Result<Self::Out> {
1775        let (x, k) = self;
1776        triu_f((x.view(), k))
1777    }
1778}
1779
1780impl<R, T, D, B> TriuAPI<()> for &TensorAny<R, T, B, D>
1781where
1782    R: DataAPI<Data = <B as DeviceRawAPI<T>>::Raw>,
1783    T: Num + Clone,
1784    D: DimAPI,
1785    B: DeviceAPI<T>
1786        + DeviceRawAPI<MaybeUninit<T>>
1787        + DeviceCreationTriAPI<T>
1788        + DeviceCreationAnyAPI<T>
1789        + OpAssignArbitaryAPI<T, D, D>
1790        + OpAssignAPI<T, D>,
1791    <B as DeviceRawAPI<T>>::Raw: Clone,
1792{
1793    type Out = Tensor<T, B, D>;
1794
1795    fn triu_f(self) -> Result<Self::Out> {
1796        triu_f((self.view(), 0))
1797    }
1798}
1799
1800/* #endregion */
1801
1802/* #region macro tensor_from_nested */
1803
1804pub trait FromNestedArrayAPI<Arr, B> {
1805    fn from_nested_array(arr: Arr, device: &B) -> Self;
1806}
1807
1808/// Implementation of this macro uses the same way of crate `ndarray`:
1809/// <https://docs.rs/ndarray/latest/ndarray/macro.array.html>
1810macro_rules! impl_from_nested_array {
1811    ($arr_type:ty, $ix_type:tt, $($n:ident),+) => {
1812        impl<T, B, $(const $n: usize),+> FromNestedArrayAPI<$arr_type, B> for Tensor<T, B, $ix_type>
1813        where
1814            T: Clone,
1815            B: DeviceAPI<T> + DeviceCreationAnyAPI<T>,
1816        {
1817            #[allow(clippy::missing_transmute_annotations)]
1818            fn from_nested_array(arr: $arr_type, device: &B) -> Self {
1819                let shape: Layout<$ix_type> = [$($n),+].c();
1820                let slc = unsafe {
1821                    core::slice::from_raw_parts(arr.as_ptr() as *const T, shape.size())
1822                };
1823                let vec = slc.to_vec();
1824                asarray((vec, shape, device)).into_dim()
1825            }
1826        }
1827    }
1828}
1829
1830impl_from_nested_array!([T; N1], Ix1, N1);
1831impl_from_nested_array!([[T; N2]; N1], Ix2, N1, N2);
1832impl_from_nested_array!([[[T; N3]; N2]; N1], Ix3, N1, N2, N3);
1833impl_from_nested_array!([[[[T; N4]; N3]; N2]; N1], Ix4, N1, N2, N3, N4);
1834impl_from_nested_array!([[[[[T; N5]; N4]; N3]; N2]; N1], Ix5, N1, N2, N3, N4, N5);
1835impl_from_nested_array!([[[[[[T; N6]; N5]; N4]; N3]; N2]; N1], Ix6, N1, N2, N3, N4, N5, N6);
1836
1837/// Create a tensor from a nested array literal (for development purposes).
1838///
1839/// # Examples
1840///
1841/// ```rust
1842/// use rstsr::prelude::*;
1843///
1844/// let tsr = rt::tensor_from_nested!(
1845///     [[1, 2, 3],
1846///      [4, 5, 6]]
1847/// );
1848/// println!("{tsr:?}");
1849/// // [[ 1 2 3]
1850/// //  [ 4 5 6]]
1851/// // 2-Dim (dyn), contiguous: Cc
1852///
1853/// let tsr = rt::tensor_from_nested!(
1854///     [[[1, 2],
1855///       [3, 4]],
1856///      [[5, 6],
1857///       [7, 8]]]
1858/// );
1859/// println!("{tsr:?}");
1860/// // [[[ 1 2]
1861/// //   [ 3 4]]
1862/// //  [[ 5 6]
1863/// //   [ 7 8]]]
1864/// // 3-Dim (dyn), contiguous: Cc
1865/// ```
1866///
1867/// If you want to specify the device, you can do it like this:
1868/// ```rust
1869/// use rstsr::prelude::*;
1870///
1871/// let device = DeviceFaer::default(); // or other devices
1872/// let tsr = rt::tensor_from_nested!([[1, 2, 3], [4, 5, 6]], &device);
1873/// println!("{tsr:?}"); // you will get a tensor on DeviceFaer
1874/// ```
1875///
1876/// # Notes on usage
1877///
1878/// - This macro is used for testing or prototyping purposes. For production code, it is recommended
1879///   to use other methods to create tensors (e.g., [`asarray`]) to have better control and
1880///   performance.
1881/// - This macro only gives row-major (C-contiguous) layout tensors, even if the device's default
1882///   order is column-major.
1883/// - The macro supports up to 6 dimensions. For 7 or more dimensions, use other methods to create
1884///   tensors.
1885/// - The created tensor is on the [`DeviceCpu`] (depends on crate feature `faer_as_default`) and
1886///   has dynamic dimension type [`IxD`].
1887/// - It is adviced to use brackets `[]` to denote each dimension level, instead of parentheses
1888///   `()`.
1889///
1890/// # See also
1891///
1892/// - [`ndarray::array`](https://docs.rs/ndarray/latest/ndarray/macro.array.html) from rust crate
1893///   ndarray.
1894#[macro_export]
1895macro_rules! tensor_from_nested {
1896    ([$([$([$([$([$([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*], $device:expr) => {{
1897        compile_error!("Tensor of 7 dimensions or more cannot be constructed with the tensor_from_nested! macro.");
1898    }};
1899    ([$([$([$([$([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*], $device:expr) => {{
1900        Tensor::<_, _, Ix6>::from_nested_array([$([$([$([$([$([$($x,)*],)*],)*],)*],)*],)*], $device).into_dyn()
1901    }};
1902    ([$([$([$([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*], $device:expr) => {{
1903        Tensor::<_, _, Ix5>::from_nested_array([$([$([$([$([$($x,)*],)*],)*],)*],)*], $device).into_dyn()
1904    }};
1905    ([$([$([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*], $device:expr) => {{
1906        Tensor::<_, _, Ix4>::from_nested_array([$([$([$([$($x,)*],)*],)*],)*], $device).into_dyn()
1907    }};
1908    ([$([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*], $device:expr) => {{
1909        Tensor::<_, _, Ix3>::from_nested_array([$([$([$($x,)*],)*],)*], $device).into_dyn()
1910    }};
1911    ([$([$($x:expr),* $(,)*]),+ $(,)*], $device:expr) => {{
1912        Tensor::<_, _, Ix2>::from_nested_array([$([$($x,)*],)*], $device).into_dyn()
1913    }};
1914    ([$($x:expr),* $(,)*], $device:expr) => {{
1915        Tensor::<_, _, Ix1>::from_nested_array([$($x,)*], $device).into_dyn()
1916    }};
1917    ([$([$([$([$([$([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]) => {{
1918        compile_error!("Tensor of 7 dimensions or more cannot be constructed with the tensor_from_nested! macro.");
1919    }};
1920    ([$([$([$([$([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]) => {{
1921        let device = DeviceCpu::default();
1922        Tensor::<_, _, Ix6>::from_nested_array([$([$([$([$([$([$($x,)*],)*],)*],)*],)*],)*], &device).into_dyn()
1923    }};
1924    ([$([$([$([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]) => {{
1925        let device = DeviceCpu::default();
1926        Tensor::<_, _, Ix5>::from_nested_array([$([$([$([$([$($x,)*],)*],)*],)*],)*], &device).into_dyn()
1927    }};
1928    ([$([$([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*]),+ $(,)*]) => {{
1929        let device = DeviceCpu::default();
1930        Tensor::<_, _, Ix4>::from_nested_array([$([$([$([$($x,)*],)*],)*],)*], &device).into_dyn()
1931    }};
1932    ([$([$([$($x:expr),* $(,)*]),+ $(,)*]),+ $(,)*]) => {{
1933        let device = DeviceCpu::default();
1934        Tensor::<_, _, Ix3>::from_nested_array([$([$([$($x,)*],)*],)*], &device).into_dyn()
1935    }};
1936    ([$([$($x:expr),* $(,)*]),+ $(,)*]) => {{
1937        let device = DeviceCpu::default();
1938        Tensor::<_, _, Ix2>::from_nested_array([$([$($x,)*],)*], &device).into_dyn()
1939    }};
1940    ([$($x:expr),* $(,)*]) => {{
1941        let device = DeviceCpu::default();
1942        Tensor::<_, _, Ix1>::from_nested_array([$($x,)*], &device).into_dyn()
1943    }};
1944}
1945
1946#[test]
1947fn playground() {
1948    use rstsr::prelude::*;
1949    let tsr = rt::tensor_from_nested!([[1, 2, 3], [4, 5, 6]]);
1950    println!("{tsr:?}");
1951
1952    let mut device = DeviceCpuSerial::default();
1953    device.set_default_order(ColMajor);
1954    let tsr = rt::tensor_from_nested!([[1, 2, 3], [4, 5, 6]], &device);
1955    println!("{tsr:?}");
1956}
1957
1958/* #endregion */
1959
1960#[cfg(test)]
1961mod test {
1962    use super::*;
1963    use num::complex::Complex32;
1964
1965    #[test]
1966    fn playground() {
1967        let a = arange((2.5, 3.2, 0.02));
1968        println!("{a:6.3?}");
1969        let a = arange(15.0);
1970        println!("{a:6.3?}");
1971        let a = arange((15.0, &DeviceCpu::default()));
1972        println!("{a:6.3?}");
1973        let a: Tensor<f64, _> = unsafe { empty(([15, 18].f(), &DeviceCpuSerial::default())) };
1974        println!("{a:6.3?}");
1975        let a = unsafe { a.empty_like() };
1976        println!("{a:6.3?}");
1977        let a = unsafe { empty_like((&a, TensorIterOrder::C)) };
1978        println!("{a:6.3?}");
1979        let a: Tensor<f64, _> = eye(3);
1980        println!("{a:6.3?}");
1981        let a = full(([2, 2].f(), 3.16));
1982        println!("{a:6.3?}");
1983        let a = full_like((&a, 2.71));
1984        println!("{a:6.3?}");
1985        let a = a.full_like(2.71);
1986        println!("{a:6.3?}");
1987        let a = linspace((3.2, 4.7, 12));
1988        println!("{a:6.3?}");
1989        let a = linspace((Complex32::new(1.8, 7.5), Complex32::new(-8.9, 1.6), 12));
1990        println!("{a:6.3?}");
1991        let a: Tensor<f64> = ones(vec![2, 2]);
1992        println!("{a:6.3?}");
1993        let a = a.ones_like();
1994        println!("{a:6.3?}");
1995        let a: Tensor<f64> = zeros([2, 2]);
1996        println!("{a:6.3?}");
1997        let a: Tensor<f64, _> = zeros(([2, 2], &DeviceCpuSerial::default()));
1998        println!("{a:6.3?}");
1999        let a = a.zeros_like();
2000        println!("{a:6.3?}");
2001    }
2002
2003    #[test]
2004    fn test_tril() {
2005        let a = arange((1, 10)).into_shape((3, 3));
2006        let b = a.view().tril();
2007        println!("{b:6.3?}");
2008        let b = triu((a, 1));
2009        println!("{b:6.3?}");
2010    }
2011}