Skip to main content

candela/tensor/
convenience.rs

1/// Build the [`SliceRange`](crate::SliceRange) list for [`slice`](crate::Tensor::slice), one entry per axis.
2///
3/// Accepts ordinary range syntax (`a..b`, `a..`, `..b`, `..`) and bare integers
4/// for single indices; negative bounds count from the end.
5///
6/// # Examples
7///
8/// ```
9/// use candela::{s, Dimension, Tensor};
10/// let t = Tensor::from_slice(&[0.0, 1.0, 2.0, 3.0, 4.0, 5.0], &[2, 3]);
11/// let sub = t.slice(s![1..2, 0..2]).unwrap().materialize();
12/// assert_eq!(sub.shape(), &[1, 2]);
13/// ```
14#[macro_export]
15macro_rules! s {
16    ($($range: expr),*) => {
17        &[$($crate::SliceRange::from($range)),*]
18    };
19}
20
21/// Build a tensor of the given shape filled with zeros.
22///
23/// The element type is inferred from the binding: `let t: Tensor<f64> = zeros!(&[2, 3]);`.
24///
25/// # Examples
26///
27/// ```
28/// use candela::{zeros, Tensor};
29/// let t: Tensor<f64> = zeros!(&[2, 2]);
30/// assert_eq!(t.data(), &[0.0; 4]);
31/// ```
32#[macro_export]
33macro_rules! zeros {
34    ($shape:expr) => {
35        $crate::Tensor::from_scalar(0.0, $shape)
36    };
37}
38
39/// Build a tensor of the given shape filled with ones.
40///
41/// The element type is inferred from the binding: `let t: Tensor<f64> = ones!(&[2, 3]);`.
42///
43/// # Examples
44///
45/// ```
46/// use candela::{ones, Tensor};
47/// let t: Tensor<f64> = ones!(&[3]);
48/// assert_eq!(t.data(), &[1.0, 1.0, 1.0]);
49/// ```
50#[macro_export]
51macro_rules! ones {
52    ($shape:expr) => {
53        $crate::Tensor::from_scalar(1.0, $shape)
54    };
55}
56
57#[allow(private_bounds)]
58pub mod arange {
59    use crate::tensor::Tensor;
60    use crate::tensor::backend::{ComputeFor, DefaultBackend};
61    use crate::tensor::traits::FromIndex;
62
63    /// Build a 1D tensor of evenly spaced values, NumPy-`arange` style.
64    ///
65    /// Every form produces a rank-1 tensor of shape `[size]`. Use `srange!`
66    /// when you want the same values reshaped to an arbitrary shape in one step.
67    ///
68    /// - `arange!(end)` - values `0..end`, shape `[end]`.
69    /// - `arange!(start, end)` - values `start..end`, shape `[end - start]`.
70    /// - `arange!(start, end, step)` - values `start..end` stepping by `step`.
71    ///
72    /// The element type is inferred from the binding, so annotate when it is
73    /// otherwise ambiguous: `let t: Tensor<f64> = arange!(4);`.
74    ///
75    /// # Examples
76    ///
77    /// ```
78    /// use candela::{arange, Dimension, Tensor};
79    /// let t: Tensor<f64> = arange!(2, 6); // [2.0, 3.0, 4.0, 5.0]
80    /// assert_eq!(t.shape(), &[4]);
81    /// assert_eq!(t.data(), &[2.0, 3.0, 4.0, 5.0]);
82    /// ```
83    #[macro_export]
84    macro_rules! arange {
85        ($size: expr) => {
86            $crate::arange::_arange_default($size)
87        };
88
89        ($start: expr, $end: expr) => {
90            $crate::arange::_arange_start($start, $end)
91        };
92
93        ($start: expr, $end: expr, $step: expr) => {
94            $crate::arange::_arange_step($start, $end, $step)
95        };
96    }
97
98    #[doc(hidden)]
99    pub fn _arange_default<T: FromIndex + ComputeFor<DefaultBackend>>(size: usize) -> Tensor<T> {
100        let v: Vec<T> = (0..size).map(T::from_index).collect();
101        Tensor::from_vec(v, &[size])
102    }
103
104    #[doc(hidden)]
105    pub fn _arange_start<T: FromIndex + ComputeFor<DefaultBackend>>(
106        start: usize,
107        end: usize,
108    ) -> Tensor<T> {
109        let v: Vec<T> = (start..end).map(T::from_index).collect();
110        let size = v.len();
111        Tensor::from_vec(v, &[size])
112    }
113
114    #[doc(hidden)]
115    pub fn _arange_step<T: FromIndex + ComputeFor<DefaultBackend>>(
116        start: usize,
117        end: usize,
118        step: usize,
119    ) -> Tensor<T> {
120        let v: Vec<T> = (start..end).step_by(step).map(T::from_index).collect();
121        let size = v.len();
122        Tensor::from_vec(v, &[size])
123    }
124
125    /// Build a tensor of evenly spaced values and reshape it in one step.
126    ///
127    /// Like [`arange!`], but takes a target shape as the final argument and lays
128    /// the values out row-major into it. Panics if the number of values doesn't
129    /// equal the product of `shape`.
130    ///
131    /// - `srange!(size, shape)` - values `0..size`, reshaped to `shape`.
132    /// - `srange!(start, end, shape)` - values `start..end`, reshaped to `shape`.
133    /// - `srange!(start, end, step, shape)` - values `start..end` by `step`, reshaped to `shape`.
134    ///
135    /// # Examples
136    ///
137    /// ```
138    /// use candela::{srange, Dimension, Tensor};
139    /// let t: Tensor<f64> = srange![6, &[2, 3]];
140    /// assert_eq!(t.shape(), &[2, 3]);
141    /// assert_eq!(t.data(), &[0.0, 1.0, 2.0, 3.0, 4.0, 5.0]);
142    /// ```
143    #[macro_export]
144    macro_rules! srange {
145        ($size: expr, $shape: expr) => {
146            $crate::arange::_arange_default_shape($size, $shape)
147        };
148
149        ($start: expr, $end: expr, $shape: expr) => {
150            $crate::arange::_arange_start_shape($start, $end, $shape)
151        };
152
153        ($start: expr, $end: expr, $step: expr, $shape: expr) => {
154            $crate::arange::_arange_step_shape($start, $end, $step, $shape)
155        };
156    }
157
158    #[doc(hidden)]
159    pub fn _arange_default_shape<T: FromIndex + ComputeFor<DefaultBackend>>(
160        size: usize,
161        shape: &[usize],
162    ) -> Tensor<T> {
163        let v: Vec<T> = (0..size).map(T::from_index).collect();
164        Tensor::from_vec(v, shape)
165    }
166
167    #[doc(hidden)]
168    pub fn _arange_start_shape<T: FromIndex + ComputeFor<DefaultBackend>>(
169        start: usize,
170        end: usize,
171        shape: &[usize],
172    ) -> Tensor<T> {
173        let v: Vec<T> = (start..end).map(T::from_index).collect();
174        Tensor::from_vec(v, shape)
175    }
176
177    #[doc(hidden)]
178    pub fn _arange_step_shape<T: FromIndex + ComputeFor<DefaultBackend>>(
179        start: usize,
180        end: usize,
181        step: usize,
182        shape: &[usize],
183    ) -> Tensor<T> {
184        let v: Vec<T> = (start..end).step_by(step).map(T::from_index).collect();
185        Tensor::from_vec(v, shape)
186    }
187}