Skip to main content

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}