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}