tenferro_ad/eager_ops_elementwise.rs
1use tenferro_ops::std_tensor_op::StdTensorOp;
2
3use crate::eager::EagerTensor;
4use crate::eager_ops::{broadcast_binary, broadcast_ternary};
5use crate::error::Result;
6use crate::CompareDir;
7
8impl EagerTensor {
9 /// Elementwise absolute value.
10 ///
11 /// # Examples
12 ///
13 /// ```
14 /// use tenferro_cpu::CpuBackend;
15 /// use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
16 ///
17 /// let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
18 /// let x = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![2], vec![-1.0_f64, 2.0]).unwrap(), ctx.clone()).unwrap();
19 /// let y = x.abs().unwrap();
20 ///
21 /// assert_eq!(y.materialized().unwrap().as_slice::<f64>().unwrap(), &[1.0, 2.0]);
22 /// ```
23 pub fn abs(&self) -> Result<Self> {
24 self.unary_op(StdTensorOp::Abs)
25 }
26
27 /// Elementwise complex conjugate.
28 ///
29 /// # Examples
30 ///
31 /// ```
32 /// use tenferro_cpu::CpuBackend;
33 /// use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
34 ///
35 /// let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
36 /// let x = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![2], vec![1.0_f64, -2.0]).unwrap(), ctx.clone()).unwrap();
37 /// let y = x.conj().unwrap();
38 ///
39 /// assert_eq!(y.materialized().unwrap().as_slice::<f64>().unwrap(), &[1.0, -2.0]);
40 /// ```
41 pub fn conj(&self) -> Result<Self> {
42 self.unary_op(StdTensorOp::Conj)
43 }
44
45 /// Elementwise sign.
46 ///
47 /// # Examples
48 ///
49 /// ```
50 /// use tenferro_cpu::CpuBackend;
51 /// use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
52 ///
53 /// let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
54 /// let x = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![2], vec![-2.0_f64, 3.0]).unwrap(), ctx.clone()).unwrap();
55 /// let y = x.sign().unwrap();
56 ///
57 /// assert_eq!(y.materialized().unwrap().as_slice::<f64>().unwrap(), &[-1.0, 1.0]);
58 /// ```
59 pub fn sign(&self) -> Result<Self> {
60 self.unary_op(StdTensorOp::Sign)
61 }
62
63 /// Elementwise natural logarithm.
64 ///
65 /// # Examples
66 ///
67 /// ```
68 /// use tenferro_cpu::CpuBackend;
69 /// use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
70 ///
71 /// let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
72 /// let x = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![1], vec![1.0_f64]).unwrap(), ctx.clone()).unwrap();
73 /// let y = x.log().unwrap();
74 ///
75 /// assert_eq!(y.materialized().unwrap().as_slice::<f64>().unwrap(), &[0.0]);
76 /// ```
77 pub fn log(&self) -> Result<Self> {
78 self.unary_op(StdTensorOp::Log)
79 }
80
81 /// Elementwise square root.
82 ///
83 /// # Examples
84 ///
85 /// ```
86 /// use tenferro_cpu::CpuBackend;
87 /// use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
88 ///
89 /// let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
90 /// let x = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![1], vec![4.0_f64]).unwrap(), ctx.clone()).unwrap();
91 /// let y = x.sqrt().unwrap();
92 ///
93 /// assert_eq!(y.materialized().unwrap().as_slice::<f64>().unwrap(), &[2.0]);
94 /// ```
95 pub fn sqrt(&self) -> Result<Self> {
96 self.unary_op(StdTensorOp::Sqrt)
97 }
98
99 /// Elementwise reciprocal square root.
100 ///
101 /// # Examples
102 ///
103 /// ```
104 /// use tenferro_cpu::CpuBackend;
105 /// use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
106 ///
107 /// let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
108 /// let x = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![1], vec![4.0_f64]).unwrap(), ctx.clone()).unwrap();
109 /// let y = x.rsqrt().unwrap();
110 ///
111 /// assert_eq!(y.materialized().unwrap().as_slice::<f64>().unwrap(), &[0.5]);
112 /// ```
113 pub fn rsqrt(&self) -> Result<Self> {
114 self.unary_op(StdTensorOp::Rsqrt)
115 }
116
117 /// Elementwise sine.
118 ///
119 /// # Examples
120 ///
121 /// ```
122 /// use tenferro_cpu::CpuBackend;
123 /// use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
124 ///
125 /// let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
126 /// let x = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![1], vec![0.0_f64]).unwrap(), ctx.clone()).unwrap();
127 /// let y = x.sin().unwrap();
128 ///
129 /// assert_eq!(y.materialized().unwrap().as_slice::<f64>().unwrap(), &[0.0]);
130 /// ```
131 pub fn sin(&self) -> Result<Self> {
132 self.unary_op(StdTensorOp::Sin)
133 }
134
135 /// Elementwise cosine.
136 ///
137 /// # Examples
138 ///
139 /// ```
140 /// use tenferro_cpu::CpuBackend;
141 /// use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
142 ///
143 /// let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
144 /// let x = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![1], vec![0.0_f64]).unwrap(), ctx.clone()).unwrap();
145 /// let y = x.cos().unwrap();
146 ///
147 /// assert_eq!(y.materialized().unwrap().as_slice::<f64>().unwrap(), &[1.0]);
148 /// ```
149 pub fn cos(&self) -> Result<Self> {
150 self.unary_op(StdTensorOp::Cos)
151 }
152
153 /// Elementwise hyperbolic tangent.
154 ///
155 /// # Examples
156 ///
157 /// ```
158 /// use tenferro_cpu::CpuBackend;
159 /// use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
160 ///
161 /// let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
162 /// let x = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![1], vec![0.0_f64]).unwrap(), ctx.clone()).unwrap();
163 /// let y = x.tanh().unwrap();
164 ///
165 /// assert_eq!(y.materialized().unwrap().as_slice::<f64>().unwrap(), &[0.0]);
166 /// ```
167 pub fn tanh(&self) -> Result<Self> {
168 self.unary_op(StdTensorOp::Tanh)
169 }
170
171 /// Elementwise `exp(x) - 1`.
172 ///
173 /// # Examples
174 ///
175 /// ```
176 /// use tenferro_cpu::CpuBackend;
177 /// use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
178 ///
179 /// let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
180 /// let x = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![1], vec![0.0_f64]).unwrap(), ctx.clone()).unwrap();
181 /// let y = x.expm1().unwrap();
182 ///
183 /// assert_eq!(y.materialized().unwrap().as_slice::<f64>().unwrap(), &[0.0]);
184 /// ```
185 pub fn expm1(&self) -> Result<Self> {
186 self.unary_op(StdTensorOp::Expm1)
187 }
188
189 /// Elementwise `log(1 + x)`.
190 ///
191 /// # Examples
192 ///
193 /// ```
194 /// use tenferro_cpu::CpuBackend;
195 /// use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
196 ///
197 /// let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
198 /// let x = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![1], vec![0.0_f64]).unwrap(), ctx.clone()).unwrap();
199 /// let y = x.log1p().unwrap();
200 ///
201 /// assert_eq!(y.materialized().unwrap().as_slice::<f64>().unwrap(), &[0.0]);
202 /// ```
203 pub fn log1p(&self) -> Result<Self> {
204 self.unary_op(StdTensorOp::Log1p)
205 }
206
207 /// Elementwise division.
208 ///
209 /// # Examples
210 ///
211 /// ```
212 /// use tenferro_cpu::CpuBackend;
213 /// use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
214 ///
215 /// let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
216 /// let x = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![3], vec![8.0_f64, -6.0, 9.0]).unwrap(), ctx.clone()).unwrap();
217 /// let y = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![3], vec![2.0_f64, 3.0, 3.0]).unwrap(), ctx.clone()).unwrap();
218 /// let z = x.div(&y).unwrap();
219 ///
220 /// assert_eq!(z.materialized().unwrap().as_slice::<f64>().unwrap(), &[4.0, -2.0, 3.0]);
221 /// ```
222 pub fn div(&self, other: &Self) -> Result<Self> {
223 let (lhs, rhs) = broadcast_binary("div", self, other)?;
224 lhs.binary_op(&rhs, StdTensorOp::Div)
225 }
226
227 /// Elementwise remainder.
228 pub fn rem(&self, other: &Self) -> Result<Self> {
229 let (lhs, rhs) = broadcast_binary("rem", self, other)?;
230 lhs.binary_op(&rhs, StdTensorOp::Rem)
231 }
232
233 /// Elementwise power.
234 ///
235 /// # Examples
236 ///
237 /// ```
238 /// use tenferro_cpu::CpuBackend;
239 /// use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
240 ///
241 /// let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
242 /// let base = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![2], vec![2.0_f64, 3.0]).unwrap(), ctx.clone()).unwrap();
243 /// let exp = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![2], vec![3.0_f64, 2.0]).unwrap(), ctx.clone()).unwrap();
244 /// let y = base.pow(&exp).unwrap();
245 ///
246 /// assert_eq!(y.materialized().unwrap().as_slice::<f64>().unwrap(), &[8.0, 9.0]);
247 /// ```
248 pub fn pow(&self, other: &Self) -> Result<Self> {
249 let (lhs, rhs) = broadcast_binary("pow", self, other)?;
250 lhs.binary_op(&rhs, StdTensorOp::Pow)
251 }
252
253 /// Elementwise maximum.
254 ///
255 /// # Examples
256 ///
257 /// ```
258 /// use tenferro_cpu::CpuBackend;
259 /// use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
260 ///
261 /// let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
262 /// let x = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![2], vec![1.0_f64, 5.0]).unwrap(), ctx.clone()).unwrap();
263 /// let y = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![2], vec![3.0_f64, 4.0]).unwrap(), ctx.clone()).unwrap();
264 /// let z = x.maximum(&y).unwrap();
265 ///
266 /// assert_eq!(z.materialized().unwrap().as_slice::<f64>().unwrap(), &[3.0, 5.0]);
267 /// ```
268 pub fn maximum(&self, other: &Self) -> Result<Self> {
269 let (lhs, rhs) = broadcast_binary("maximum", self, other)?;
270 lhs.binary_op(&rhs, StdTensorOp::Maximum)
271 }
272
273 /// Elementwise minimum.
274 ///
275 /// # Examples
276 ///
277 /// ```
278 /// use tenferro_cpu::CpuBackend;
279 /// use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
280 ///
281 /// let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
282 /// let x = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![2], vec![1.0_f64, 5.0]).unwrap(), ctx.clone()).unwrap();
283 /// let y = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![2], vec![3.0_f64, 4.0]).unwrap(), ctx.clone()).unwrap();
284 /// let z = x.minimum(&y).unwrap();
285 ///
286 /// assert_eq!(z.materialized().unwrap().as_slice::<f64>().unwrap(), &[1.0, 4.0]);
287 /// ```
288 pub fn minimum(&self, other: &Self) -> Result<Self> {
289 let (lhs, rhs) = broadcast_binary("minimum", self, other)?;
290 lhs.binary_op(&rhs, StdTensorOp::Minimum)
291 }
292
293 /// Elementwise comparison.
294 pub fn compare(&self, other: &Self, dir: CompareDir) -> Result<Self> {
295 let (lhs, rhs) = broadcast_binary("compare", self, other)?;
296 lhs.binary_op(&rhs, StdTensorOp::Compare(dir))
297 }
298
299 /// Select values from `on_true` or `on_false` using `condition`.
300 ///
301 /// # Examples
302 ///
303 /// ```
304 /// use tenferro_cpu::CpuBackend;
305 /// use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
306 ///
307 /// let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
308 /// let condition = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![2], vec![false, true]).unwrap(), ctx.clone()).unwrap();
309 /// let on_true = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![2], vec![10.0_f64, 20.0]).unwrap(), ctx.clone()).unwrap();
310 /// let on_false = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![2], vec![1.0_f64, 2.0]).unwrap(), ctx.clone()).unwrap();
311 /// let y = EagerTensor::select(&condition, &on_true, &on_false).unwrap();
312 ///
313 /// assert_eq!(y.materialized().unwrap().as_slice::<f64>().unwrap(), &[1.0, 20.0]);
314 /// ```
315 pub fn select(condition: &Self, on_true: &Self, on_false: &Self) -> Result<Self> {
316 Self::where_select(condition, on_true, on_false)
317 }
318
319 /// Select values from `on_true` or `on_false` using `condition`.
320 pub fn where_select(condition: &Self, on_true: &Self, on_false: &Self) -> Result<Self> {
321 let (condition, on_true, on_false) =
322 broadcast_ternary("where_select", condition, on_true, on_false)?;
323 condition.ternary_op(&on_true, &on_false, StdTensorOp::Select)
324 }
325
326 /// Clamp values elementwise between lower and upper bounds.
327 ///
328 /// # Examples
329 ///
330 /// ```
331 /// use tenferro_cpu::CpuBackend;
332 /// use tenferro_ad::{EagerRuntime, EagerTensor, Tensor};
333 ///
334 /// let ctx = EagerRuntime::with_cpu_backend(CpuBackend::new());
335 /// let x = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![3], vec![-2.0_f64, 0.5, 5.0]).unwrap(), ctx.clone()).unwrap();
336 /// let lower = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![3], vec![-1.0_f64, 0.0, 1.0]).unwrap(), ctx.clone()).unwrap();
337 /// let upper = EagerTensor::from_tensor_in(Tensor::from_vec_col_major(vec![3], vec![1.0_f64, 2.0, 4.0]).unwrap(), ctx.clone()).unwrap();
338 /// let y = x.clamp(&lower, &upper).unwrap();
339 ///
340 /// assert_eq!(y.materialized().unwrap().as_slice::<f64>().unwrap(), &[-1.0, 0.5, 4.0]);
341 /// ```
342 pub fn clamp(&self, lower: &Self, upper: &Self) -> Result<Self> {
343 let (input, lower, upper) = broadcast_ternary("clamp", self, lower, upper)?;
344 input.ternary_op(&lower, &upper, StdTensorOp::Clamp)
345 }
346}