tenferro_runtime/typed_session_ext.rs
1//! Engine-explicit operations on [`TypedTensor`].
2
3use num_complex::Complex64;
4
5use crate::{CompareDir, DotGeneralConfig, Engine, TensorScalar, TypedTensor};
6
7/// AD-free tensor operations on [`TypedTensor`], run on a borrowed engine.
8///
9/// The methods mirror [`crate::TensorSessionOpsExt`] for a statically known
10/// scalar type, with the engine last. Indexing, padding, concatenation and the
11/// triangular/diagonal masks are included: they go through the `*_read` hooks,
12/// so a typed tensor is borrowed rather than copied before the kernel.
13/// Selection with a bool mask is
14/// [`crate::TypedTensorMaskSessionOpsExt::where_select`].
15///
16/// # Examples
17///
18/// ```rust
19/// use tenferro_cpu::CpuEngine;
20/// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
21///
22/// let mut engine = CpuEngine::serial();
23/// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, -3.0])?;
24/// let y = x.reduce_max(None, &mut engine)?;
25/// assert_eq!(y.host_data()?, &[1.0]);
26/// # Ok::<(), Box<dyn std::error::Error>>(())
27/// ```
28pub trait TypedTensorSessionOpsExt<T: TensorScalar> {
29 /// Elementwise addition with NumPy-style broadcasting on an engine.
30 ///
31 /// # Examples
32 ///
33 /// ```rust
34 /// use tenferro_cpu::CpuEngine;
35 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
36 ///
37 ///
38 /// let mut engine = CpuEngine::serial();
39 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 2.0]).unwrap();
40 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![3.0, 4.0]).unwrap();
41 /// let sum = a.add(&b, &mut engine)?;
42 /// assert_eq!(sum.host_data().unwrap(), &[4.0, 6.0]);
43 /// # Ok::<(), Box<dyn std::error::Error>>(())
44 /// ```
45 ///
46 /// # Errors
47 ///
48 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` for
49 /// incompatible operands, or [`tenferro_tensor::Error::BackendSource`] for
50 /// a typed backend failure.
51 fn add(
52 &self,
53 rhs: &TypedTensor<T>,
54 session: &mut dyn Engine,
55 ) -> tenferro_tensor::Result<TypedTensor<T>>;
56 /// Elementwise addition into a caller-owned output on an engine.
57 ///
58 /// The caller keeps the output's storage, so the operation allocates nothing for
59 /// it: this is the caller-output route [`Self::add`] cannot offer, the one the
60 /// dispatch floor in #2139 is measured against. `out` is written in place and must
61 /// have the broadcast result shape with a write-injective layout; the session
62 /// rejects anything else before writing, leaving `out` unchanged on failure.
63 ///
64 /// # Examples
65 ///
66 /// ```rust
67 /// use tenferro_cpu::CpuEngine;
68 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
69 ///
70 ///
71 /// let mut engine = CpuEngine::serial();
72 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 2.0]).unwrap();
73 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![3.0, 4.0]).unwrap();
74 /// let mut out = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![0.0, 0.0]).unwrap();
75 /// a.add_into(&b, &mut out, &mut engine)?;
76 /// assert_eq!(out.host_data().unwrap(), &[4.0, 6.0]);
77 /// # Ok::<(), Box<dyn std::error::Error>>(())
78 /// ```
79 ///
80 /// # Errors
81 ///
82 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` for
83 /// incompatible operands or an output of the wrong shape,
84 /// `ValidationError::OverlappingMutableLayout` for a non-injective output layout,
85 /// or [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
86 fn add_into(
87 &self,
88 rhs: &TypedTensor<T>,
89 out: &mut TypedTensor<T>,
90 session: &mut dyn Engine,
91 ) -> tenferro_tensor::Result<()>;
92 /// Elementwise multiplication with NumPy-style broadcasting on an engine.
93 ///
94 /// # Examples
95 ///
96 /// ```rust
97 /// use tenferro_cpu::CpuEngine;
98 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
99 ///
100 ///
101 /// let mut engine = CpuEngine::serial();
102 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![1], vec![2.0]).unwrap();
103 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![4], vec![3.0; 4]).unwrap();
104 /// let product = a.mul(&b, &mut engine)?;
105 /// assert_eq!(product.host_data().unwrap(), &[6.0; 4]);
106 /// # Ok::<(), Box<dyn std::error::Error>>(())
107 /// ```
108 ///
109 /// # Errors
110 ///
111 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` for
112 /// incompatible operands, or [`tenferro_tensor::Error::BackendSource`] for
113 /// a typed backend failure.
114 fn mul(
115 &self,
116 rhs: &TypedTensor<T>,
117 session: &mut dyn Engine,
118 ) -> tenferro_tensor::Result<TypedTensor<T>>;
119 /// Elementwise exponential on an engine.
120 ///
121 /// # Examples
122 ///
123 /// ```rust
124 /// use tenferro_cpu::CpuEngine;
125 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
126 ///
127 ///
128 /// let mut engine = CpuEngine::serial();
129 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![0.0, 1.0]).unwrap();
130 /// let y = x.exp(&mut engine)?;
131 /// let y = y.host_data().unwrap();
132 /// assert!((y[0] - 1.0).abs() < 1.0e-12);
133 /// assert!((y[1] - std::f64::consts::E).abs() < 1.0e-12);
134 /// # Ok::<(), Box<dyn std::error::Error>>(())
135 /// ```
136 ///
137 /// # Errors
138 ///
139 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
140 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
141 /// failure.
142 fn exp(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
143 /// Sum over the selected axes on an engine. `None` reduces every
144 /// axis and `Some(&[])` keeps the input shape.
145 ///
146 /// # Examples
147 ///
148 /// ```rust
149 /// use tenferro_cpu::CpuEngine;
150 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
151 ///
152 ///
153 /// let mut engine = CpuEngine::serial();
154 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2, 3], vec![1.0; 6]).unwrap();
155 /// let sums = x.reduce_sum(Some(&[1]), &mut engine)?;
156 /// assert_eq!(sums.host_data().unwrap(), &[3.0, 3.0]);
157 /// # Ok::<(), Box<dyn std::error::Error>>(())
158 /// ```
159 ///
160 /// # Errors
161 ///
162 /// Returns [`tenferro_tensor::Error::Validation`] with `AxisOutOfBounds`
163 /// for an axis outside the input rank or `DuplicateAxis` when `axes`
164 /// repeats an axis, or [`tenferro_tensor::Error::BackendSource`] for a
165 /// typed backend failure.
166 fn reduce_sum(
167 &self,
168 axes: Option<&[usize]>,
169 session: &mut dyn Engine,
170 ) -> tenferro_tensor::Result<TypedTensor<T>>;
171 /// Elementwise subtraction with NumPy-style broadcasting on an engine.
172 ///
173 /// # Examples
174 ///
175 /// ```rust
176 /// use tenferro_cpu::CpuEngine;
177 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
178 ///
179 ///
180 /// let mut engine = CpuEngine::serial();
181 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![2.0, 4.0]).unwrap();
182 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 8.0]).unwrap();
183 /// let y = a.sub(&b, &mut engine)?;
184 /// assert_eq!(y.host_data().unwrap(), &[1.0, -4.0]);
185 /// # Ok::<(), Box<dyn std::error::Error>>(())
186 /// ```
187 ///
188 /// # Errors
189 ///
190 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` for
191 /// incompatible operands, or [`tenferro_tensor::Error::BackendSource`] for
192 /// a typed backend failure.
193 fn sub(
194 &self,
195 rhs: &TypedTensor<T>,
196 session: &mut dyn Engine,
197 ) -> tenferro_tensor::Result<TypedTensor<T>>;
198 /// Elementwise division with NumPy-style broadcasting on an engine.
199 ///
200 /// # Examples
201 ///
202 /// ```rust
203 /// use tenferro_cpu::CpuEngine;
204 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
205 ///
206 ///
207 /// let mut engine = CpuEngine::serial();
208 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![4.0, 8.0]).unwrap();
209 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![2.0, 4.0]).unwrap();
210 /// let y = a.div(&b, &mut engine)?;
211 /// assert_eq!(y.host_data().unwrap(), &[2.0, 2.0]);
212 /// # Ok::<(), Box<dyn std::error::Error>>(())
213 /// ```
214 ///
215 /// # Errors
216 ///
217 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` for
218 /// incompatible shapes, a numerical [`tenferro_tensor::Error::Extension`]
219 /// for a detected zero divisor, or [`tenferro_tensor::Error::BackendSource`]
220 /// for a typed backend failure.
221 fn div(
222 &self,
223 rhs: &TypedTensor<T>,
224 session: &mut dyn Engine,
225 ) -> tenferro_tensor::Result<TypedTensor<T>>;
226 /// Elementwise remainder with NumPy-style broadcasting on an engine.
227 ///
228 /// # Examples
229 ///
230 /// ```rust
231 /// use tenferro_cpu::CpuEngine;
232 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
233 ///
234 ///
235 /// let mut engine = CpuEngine::serial();
236 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![5.0, 7.0]).unwrap();
237 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![2.0, 4.0]).unwrap();
238 /// let y = a.rem(&b, &mut engine)?;
239 /// assert_eq!(y.host_data().unwrap(), &[1.0, 3.0]);
240 /// # Ok::<(), Box<dyn std::error::Error>>(())
241 /// ```
242 ///
243 /// # Errors
244 ///
245 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` for
246 /// incompatible shapes, a numerical [`tenferro_tensor::Error::Extension`]
247 /// for a detected zero divisor, or [`tenferro_tensor::Error::BackendSource`]
248 /// for a typed backend failure.
249 fn rem(
250 &self,
251 rhs: &TypedTensor<T>,
252 session: &mut dyn Engine,
253 ) -> tenferro_tensor::Result<TypedTensor<T>>;
254 /// Elementwise power with NumPy-style broadcasting on an engine.
255 ///
256 /// # Examples
257 ///
258 /// ```rust
259 /// use tenferro_cpu::CpuEngine;
260 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
261 ///
262 ///
263 /// let mut engine = CpuEngine::serial();
264 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![2.0, 3.0]).unwrap();
265 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![3.0, 2.0]).unwrap();
266 /// let y = a.pow(&b, &mut engine)?;
267 /// assert_eq!(y.host_data().unwrap(), &[8.0, 9.0]);
268 /// # Ok::<(), Box<dyn std::error::Error>>(())
269 /// ```
270 ///
271 /// # Errors
272 ///
273 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` for
274 /// incompatible shapes, a numerical [`tenferro_tensor::Error::Extension`]
275 /// for a detected negative integer exponent, or
276 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
277 fn pow(
278 &self,
279 rhs: &TypedTensor<T>,
280 session: &mut dyn Engine,
281 ) -> tenferro_tensor::Result<TypedTensor<T>>;
282 /// Elementwise maximum with NumPy-style broadcasting on an engine.
283 ///
284 /// # Examples
285 ///
286 /// ```rust
287 /// use tenferro_cpu::CpuEngine;
288 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
289 ///
290 ///
291 /// let mut engine = CpuEngine::serial();
292 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![2.0, 4.0]).unwrap();
293 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 8.0]).unwrap();
294 /// let y = a.maximum(&b, &mut engine)?;
295 /// assert_eq!(y.host_data().unwrap(), &[2.0, 8.0]);
296 /// # Ok::<(), Box<dyn std::error::Error>>(())
297 /// ```
298 ///
299 /// # Errors
300 ///
301 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` for
302 /// incompatible operands, or [`tenferro_tensor::Error::BackendSource`] for
303 /// a typed backend failure.
304 fn maximum(
305 &self,
306 rhs: &TypedTensor<T>,
307 session: &mut dyn Engine,
308 ) -> tenferro_tensor::Result<TypedTensor<T>>;
309 /// Elementwise minimum with NumPy-style broadcasting on an engine.
310 ///
311 /// # Examples
312 ///
313 /// ```rust
314 /// use tenferro_cpu::CpuEngine;
315 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
316 ///
317 ///
318 /// let mut engine = CpuEngine::serial();
319 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![2.0, 4.0]).unwrap();
320 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 8.0]).unwrap();
321 /// let y = a.minimum(&b, &mut engine)?;
322 /// assert_eq!(y.host_data().unwrap(), &[1.0, 4.0]);
323 /// # Ok::<(), Box<dyn std::error::Error>>(())
324 /// ```
325 ///
326 /// # Errors
327 ///
328 /// Returns [`tenferro_tensor::Error::Validation`] with `ShapeMismatch` for
329 /// incompatible operands, or [`tenferro_tensor::Error::BackendSource`] for
330 /// a typed backend failure.
331 fn minimum(
332 &self,
333 rhs: &TypedTensor<T>,
334 session: &mut dyn Engine,
335 ) -> tenferro_tensor::Result<TypedTensor<T>>;
336 /// Elementwise negation on an engine.
337 ///
338 /// # Examples
339 ///
340 /// ```rust
341 /// use tenferro_cpu::CpuEngine;
342 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
343 ///
344 ///
345 /// let mut engine = CpuEngine::serial();
346 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, -2.0]).unwrap();
347 /// let y = x.neg(&mut engine)?;
348 /// assert_eq!(y.host_data().unwrap(), &[-1.0, 2.0]);
349 /// # Ok::<(), Box<dyn std::error::Error>>(())
350 /// ```
351 ///
352 /// # Errors
353 ///
354 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
355 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
356 /// failure.
357 fn neg(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
358 /// Elementwise absolute value on an engine.
359 ///
360 /// The result has the real counterpart dtype `T::Real`: complex magnitude
361 /// is real, and real or integer inputs keep their own dtype.
362 ///
363 /// # Examples
364 ///
365 /// ```rust
366 /// use num_complex::Complex64;
367 /// use tenferro_cpu::CpuEngine;
368 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
369 ///
370 ///
371 /// let mut engine = CpuEngine::serial();
372 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![-1.0, 2.0])?;
373 /// let y = x.abs(&mut engine)?;
374 /// assert_eq!(y.host_data()?, &[1.0, 2.0]);
375 ///
376 /// let z = TypedTensor::<Complex64>::from_vec_col_major(vec![1], vec![Complex64::new(3.0, 4.0)])?;
377 /// let magnitude: TypedTensor<f64> = z.abs(&mut engine)?;
378 /// assert_eq!(magnitude.host_data()?, &[5.0]);
379 /// # Ok::<(), Box<dyn std::error::Error>>(())
380 /// ```
381 ///
382 /// # Errors
383 ///
384 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
385 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
386 /// failure.
387 fn abs(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T::Real>>;
388 /// Elementwise sign on an engine.
389 ///
390 /// # Examples
391 ///
392 /// ```rust
393 /// use tenferro_cpu::CpuEngine;
394 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
395 ///
396 ///
397 /// let mut engine = CpuEngine::serial();
398 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, -2.0]).unwrap();
399 /// let y = x.sign(&mut engine)?;
400 /// assert_eq!(y.host_data().unwrap(), &[1.0, -1.0]);
401 /// # Ok::<(), Box<dyn std::error::Error>>(())
402 /// ```
403 ///
404 /// # Errors
405 ///
406 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
407 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
408 /// failure.
409 fn sign(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
410 /// Elementwise complex conjugate on an engine.
411 ///
412 /// For real dtypes the conjugate is the identity.
413 ///
414 /// # Examples
415 ///
416 /// ```rust
417 /// use tenferro_cpu::CpuEngine;
418 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
419 ///
420 ///
421 /// let mut engine = CpuEngine::serial();
422 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, -2.0]).unwrap();
423 /// let y = x.conj(&mut engine)?;
424 /// assert_eq!(y.host_data().unwrap(), &[1.0, -2.0]);
425 /// # Ok::<(), Box<dyn std::error::Error>>(())
426 /// ```
427 ///
428 /// # Errors
429 ///
430 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
431 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
432 /// failure.
433 fn conj(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
434 /// Elementwise natural logarithm on an engine.
435 ///
436 /// # Examples
437 ///
438 /// ```rust
439 /// use tenferro_cpu::CpuEngine;
440 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
441 ///
442 ///
443 /// let mut engine = CpuEngine::serial();
444 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, std::f64::consts::E]).unwrap();
445 /// let y = x.log(&mut engine)?;
446 /// let y = y.host_data().unwrap();
447 /// assert!(y[0].abs() < 1.0e-12);
448 /// assert!((y[1] - 1.0).abs() < 1.0e-12);
449 /// # Ok::<(), Box<dyn std::error::Error>>(())
450 /// ```
451 ///
452 /// # Errors
453 ///
454 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
455 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
456 /// failure.
457 fn log(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
458 /// Elementwise `exp(x) - 1` on an engine.
459 ///
460 /// # Examples
461 ///
462 /// ```rust
463 /// use tenferro_cpu::CpuEngine;
464 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
465 ///
466 ///
467 /// let mut engine = CpuEngine::serial();
468 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![0.0, 1.0]).unwrap();
469 /// let y = x.expm1(&mut engine)?;
470 /// let y = y.host_data().unwrap();
471 /// assert!(y[0].abs() < 1.0e-12);
472 /// assert!((y[1] - (std::f64::consts::E - 1.0)).abs() < 1.0e-12);
473 /// # Ok::<(), Box<dyn std::error::Error>>(())
474 /// ```
475 ///
476 /// # Errors
477 ///
478 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
479 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
480 /// failure.
481 fn expm1(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
482 /// Elementwise `log(1 + x)` on an engine.
483 ///
484 /// # Examples
485 ///
486 /// ```rust
487 /// use tenferro_cpu::CpuEngine;
488 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
489 ///
490 ///
491 /// let mut engine = CpuEngine::serial();
492 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![0.0, std::f64::consts::E - 1.0]).unwrap();
493 /// let y = x.log1p(&mut engine)?;
494 /// let y = y.host_data().unwrap();
495 /// assert!(y[0].abs() < 1.0e-12);
496 /// assert!((y[1] - 1.0).abs() < 1.0e-12);
497 /// # Ok::<(), Box<dyn std::error::Error>>(())
498 /// ```
499 ///
500 /// # Errors
501 ///
502 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
503 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
504 /// failure.
505 fn log1p(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
506 /// Elementwise error function `erf(x)` on the engine, for real `f32`/`f64`.
507 ///
508 /// # Examples
509 ///
510 /// ```rust
511 /// use tenferro_cpu::CpuEngine;
512 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
513 ///
514 ///
515 /// let mut engine = CpuEngine::serial();
516 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![0.0, 1.0]).unwrap();
517 /// let y = x.erf(&mut engine)?;
518 /// let y = y.host_data().unwrap();
519 /// assert_eq!(y[0], 0.0);
520 /// assert!((y[1] - 0.842_700_792_949_714_9).abs() < 1.0e-15);
521 /// # Ok::<(), Box<dyn std::error::Error>>(())
522 /// ```
523 ///
524 /// # Errors
525 ///
526 /// Returns [`tenferro_tensor::Error::UnsupportedDType`] for a complex or
527 /// integer element type, or [`tenferro_tensor::Error::BackendSource`] for
528 /// a typed backend failure.
529 fn erf(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
530 /// Elementwise sine on an engine.
531 ///
532 /// # Examples
533 ///
534 /// ```rust
535 /// use tenferro_cpu::CpuEngine;
536 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
537 ///
538 ///
539 /// let mut engine = CpuEngine::serial();
540 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![0.0, std::f64::consts::FRAC_PI_2]).unwrap();
541 /// let y = x.sin(&mut engine)?;
542 /// let y = y.host_data().unwrap();
543 /// assert!(y[0].abs() < 1.0e-12);
544 /// assert!((y[1] - 1.0).abs() < 1.0e-12);
545 /// # Ok::<(), Box<dyn std::error::Error>>(())
546 /// ```
547 ///
548 /// # Errors
549 ///
550 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
551 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
552 /// failure.
553 fn sin(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
554 /// Elementwise cosine on an engine.
555 ///
556 /// # Examples
557 ///
558 /// ```rust
559 /// use tenferro_cpu::CpuEngine;
560 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
561 ///
562 ///
563 /// let mut engine = CpuEngine::serial();
564 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![0.0, std::f64::consts::PI]).unwrap();
565 /// let y = x.cos(&mut engine)?;
566 /// let y = y.host_data().unwrap();
567 /// assert!((y[0] - 1.0).abs() < 1.0e-12);
568 /// assert!((y[1] + 1.0).abs() < 1.0e-12);
569 /// # Ok::<(), Box<dyn std::error::Error>>(())
570 /// ```
571 ///
572 /// # Errors
573 ///
574 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
575 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
576 /// failure.
577 fn cos(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
578 /// Elementwise hyperbolic tangent on an engine.
579 ///
580 /// # Examples
581 ///
582 /// ```rust
583 /// use tenferro_cpu::CpuEngine;
584 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
585 ///
586 ///
587 /// let mut engine = CpuEngine::serial();
588 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![0.0, 1.0]).unwrap();
589 /// let y = x.tanh(&mut engine)?;
590 /// let y = y.host_data().unwrap();
591 /// assert!(y[0].abs() < 1.0e-12);
592 /// assert!((y[1] - 0.7615941559557649).abs() < 1.0e-12);
593 /// # Ok::<(), Box<dyn std::error::Error>>(())
594 /// ```
595 ///
596 /// # Errors
597 ///
598 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
599 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
600 /// failure.
601 fn tanh(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
602 /// Elementwise square root on an engine.
603 ///
604 /// # Examples
605 ///
606 /// ```rust
607 /// use tenferro_cpu::CpuEngine;
608 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
609 ///
610 ///
611 /// let mut engine = CpuEngine::serial();
612 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![4.0, 9.0]).unwrap();
613 /// let y = x.sqrt(&mut engine)?;
614 /// assert_eq!(y.host_data().unwrap(), &[2.0, 3.0]);
615 /// # Ok::<(), Box<dyn std::error::Error>>(())
616 /// ```
617 ///
618 /// # Errors
619 ///
620 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
621 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
622 /// failure.
623 fn sqrt(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
624 /// Elementwise reciprocal square root on an engine.
625 ///
626 /// # Examples
627 ///
628 /// ```rust
629 /// use tenferro_cpu::CpuEngine;
630 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
631 ///
632 ///
633 /// let mut engine = CpuEngine::serial();
634 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![4.0, 1.0]).unwrap();
635 /// let y = x.rsqrt(&mut engine)?;
636 /// let y = y.host_data().unwrap();
637 /// assert!((y[0] - 0.5).abs() < 1.0e-12);
638 /// assert!((y[1] - 1.0).abs() < 1.0e-12);
639 /// # Ok::<(), Box<dyn std::error::Error>>(())
640 /// ```
641 ///
642 /// # Errors
643 ///
644 /// Returns [`tenferro_tensor::Error::Unsupported`] for an unsupported
645 /// dtype or [`tenferro_tensor::Error::BackendSource`] for a typed backend
646 /// failure.
647 fn rsqrt(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
648 /// Elementwise comparison with NumPy-style broadcasting on an engine.
649 ///
650 /// The result is a bool typed tensor.
651 ///
652 /// # Examples
653 ///
654 /// ```rust
655 /// use tenferro_cpu::CpuEngine;
656 /// use tenferro_runtime::{CompareDir, TypedTensor, TypedTensorSessionOpsExt};
657 ///
658 ///
659 /// let mut engine = CpuEngine::serial();
660 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![2.0, 4.0]).unwrap();
661 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 8.0]).unwrap();
662 /// let y = a.compare(&b, CompareDir::Gt, &mut engine)?;
663 /// assert_eq!(y.host_data().unwrap(), &[true, false]);
664 /// # Ok::<(), Box<dyn std::error::Error>>(())
665 /// ```
666 ///
667 /// # Errors
668 ///
669 /// Returns [`tenferro_tensor::Error::Validation`] with
670 /// `ShapeMismatch::IncompatibleShapes` when broadcasting the operands is
671 /// impossible, or [`tenferro_tensor::Error::BackendSource`] for a typed
672 /// backend failure.
673 fn compare(
674 &self,
675 rhs: &TypedTensor<T>,
676 dir: CompareDir,
677 session: &mut dyn Engine,
678 ) -> tenferro_tensor::Result<TypedTensor<bool>>;
679 /// Clamp values elementwise between lower and upper bounds on an engine.
680 ///
681 /// # Examples
682 ///
683 /// ```rust
684 /// use tenferro_cpu::CpuEngine;
685 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
686 ///
687 ///
688 /// let mut engine = CpuEngine::serial();
689 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![-2.0, 4.0]).unwrap();
690 /// let lower = TypedTensor::<f64>::from_vec_col_major(vec![], vec![0.0]).unwrap();
691 /// let upper = TypedTensor::<f64>::from_vec_col_major(vec![], vec![3.0]).unwrap();
692 /// let y = x.clamp(&lower, &upper, &mut engine)?;
693 /// assert_eq!(y.host_data().unwrap(), &[0.0, 3.0]);
694 /// # Ok::<(), Box<dyn std::error::Error>>(())
695 /// ```
696 ///
697 /// # Errors
698 ///
699 /// Returns [`tenferro_tensor::Error::Validation`] with
700 /// `ShapeMismatch::IncompatibleShapes` when a bound cannot broadcast to
701 /// the input, or [`tenferro_tensor::Error::BackendSource`] for a typed
702 /// backend failure.
703 fn clamp(
704 &self,
705 lower: &TypedTensor<T>,
706 upper: &TypedTensor<T>,
707 session: &mut dyn Engine,
708 ) -> tenferro_tensor::Result<TypedTensor<T>>;
709 /// Rank-2 matrix multiplication on an engine.
710 ///
711 /// # Examples
712 ///
713 /// ```rust
714 /// use tenferro_cpu::CpuEngine;
715 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
716 ///
717 ///
718 /// let mut engine = CpuEngine::serial();
719 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2, 3], vec![1.0; 6]).unwrap();
720 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![3, 2], vec![1.0; 6]).unwrap();
721 /// let c = a.matmul(&b, &mut engine)?;
722 /// assert_eq!(c.shape(), &[2, 2]);
723 /// # Ok::<(), Box<dyn std::error::Error>>(())
724 /// ```
725 ///
726 /// # Errors
727 ///
728 /// Returns [`tenferro_tensor::Error::Validation`] with `RankMismatch` when
729 /// either operand is not rank two or `ShapeMismatch::ContractedDimensions`
730 /// when the inner dimensions differ, or
731 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
732 fn matmul(
733 &self,
734 rhs: &TypedTensor<T>,
735 session: &mut dyn Engine,
736 ) -> tenferro_tensor::Result<TypedTensor<T>>;
737 /// Reshape through the backend structural operation on an engine.
738 ///
739 /// # Examples
740 ///
741 /// ```rust
742 /// use tenferro_cpu::CpuEngine;
743 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
744 ///
745 ///
746 /// let mut engine = CpuEngine::serial();
747 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2, 3], vec![1.0; 6]).unwrap();
748 /// let y = x.reshape(&[3, 2], &mut engine)?;
749 /// assert_eq!(y.shape(), &[3, 2]);
750 /// # Ok::<(), Box<dyn std::error::Error>>(())
751 /// ```
752 ///
753 /// # Errors
754 ///
755 /// Returns [`tenferro_tensor::Error::Validation`] with
756 /// `ShapeMismatch::ReshapeElementCount` when the element counts differ,
757 /// `IntegerOverflow` when shape arithmetic overflows, or
758 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
759 fn reshape(
760 &self,
761 shape: &[usize],
762 session: &mut dyn Engine,
763 ) -> tenferro_tensor::Result<TypedTensor<T>>;
764 /// Permute axes through the backend structural operation on an engine.
765 ///
766 /// # Examples
767 ///
768 /// ```rust
769 /// use tenferro_cpu::CpuEngine;
770 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
771 ///
772 ///
773 /// let mut engine = CpuEngine::serial();
774 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2, 3], vec![1.0; 6]).unwrap();
775 /// let y = x.transpose(&[1, 0], &mut engine)?;
776 /// assert_eq!(y.shape(), &[3, 2]);
777 /// # Ok::<(), Box<dyn std::error::Error>>(())
778 /// ```
779 ///
780 /// # Errors
781 ///
782 /// Returns [`tenferro_tensor::Error::Validation`] with
783 /// `InvalidPermutationLength` when `perm` has the wrong length,
784 /// `AxisOutOfBounds` for an invalid axis, or `DuplicateAxis` for a
785 /// repeated axis, or [`tenferro_tensor::Error::BackendSource`] for a typed
786 /// backend failure.
787 fn transpose(
788 &self,
789 perm: &[usize],
790 session: &mut dyn Engine,
791 ) -> tenferro_tensor::Result<TypedTensor<T>>;
792 /// Broadcast into a larger shape on an engine.
793 ///
794 /// # Examples
795 ///
796 /// ```rust
797 /// use tenferro_cpu::CpuEngine;
798 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
799 ///
800 ///
801 /// let mut engine = CpuEngine::serial();
802 /// let row = TypedTensor::<f64>::from_vec_col_major(vec![3], vec![1.0, 2.0, 3.0]).unwrap();
803 /// let matrix = row.broadcast_in_dim(&[2, 3], &[1], &mut engine)?;
804 /// assert_eq!(matrix.shape(), &[2, 3]);
805 /// # Ok::<(), Box<dyn std::error::Error>>(())
806 /// ```
807 ///
808 /// # Errors
809 ///
810 /// Returns [`tenferro_tensor::Error::Validation`] with `RankMismatch` when
811 /// `dims` does not match the input rank, `AxisOutOfBounds` or
812 /// `DuplicateAxis` for an invalid mapping, or
813 /// `ShapeMismatch::IncompatibleShapes` when known dimensions cannot
814 /// broadcast. [`tenferro_tensor::Error::BackendSource`] reports a typed
815 /// backend failure.
816 fn broadcast_in_dim(
817 &self,
818 shape: &[usize],
819 dims: &[usize],
820 session: &mut dyn Engine,
821 ) -> tenferro_tensor::Result<TypedTensor<T>>;
822 /// Take the maximum over the selected axes on an engine. `None` reduces every axis and `Some(&[])` keeps the input shape.
823 ///
824 /// # Examples
825 ///
826 /// ```rust
827 /// use tenferro_cpu::CpuEngine;
828 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
829 ///
830 ///
831 /// let mut engine = CpuEngine::serial();
832 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2, 2], vec![1.0, 5.0, 3.0, 2.0])?;
833 /// let y = x.reduce_max(Some(&[0]), &mut engine)?;
834 /// assert_eq!(y.host_data()?, &[5.0, 3.0]);
835 /// # Ok::<(), Box<dyn std::error::Error>>(())
836 /// ```
837 ///
838 /// # Errors
839 ///
840 /// Returns [`tenferro_tensor::Error::Validation`] for an out-of-range or repeated axis, or
841 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
842 /// An unsupported dtype returns [`tenferro_tensor::Error::Unsupported`].
843 fn reduce_max(
844 &self,
845 axes: Option<&[usize]>,
846 session: &mut dyn Engine,
847 ) -> tenferro_tensor::Result<TypedTensor<T>>;
848 /// Take the minimum over the selected axes on an engine. `None` reduces every axis and `Some(&[])` keeps the input shape.
849 ///
850 /// # Examples
851 ///
852 /// ```rust
853 /// use tenferro_cpu::CpuEngine;
854 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
855 ///
856 ///
857 /// let mut engine = CpuEngine::serial();
858 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2, 2], vec![1.0, 5.0, 3.0, 2.0])?;
859 /// let y = x.reduce_min(Some(&[0]), &mut engine)?;
860 /// assert_eq!(y.host_data()?, &[1.0, 2.0]);
861 /// # Ok::<(), Box<dyn std::error::Error>>(())
862 /// ```
863 ///
864 /// # Errors
865 ///
866 /// Returns [`tenferro_tensor::Error::Validation`] for an out-of-range or repeated axis, or
867 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
868 /// An unsupported dtype returns [`tenferro_tensor::Error::Unsupported`].
869 fn reduce_min(
870 &self,
871 axes: Option<&[usize]>,
872 session: &mut dyn Engine,
873 ) -> tenferro_tensor::Result<TypedTensor<T>>;
874 /// Multiply over the selected axes on an engine. `None` reduces every axis and `Some(&[])` keeps the input shape.
875 ///
876 /// # Examples
877 ///
878 /// ```rust
879 /// use tenferro_cpu::CpuEngine;
880 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
881 ///
882 ///
883 /// let mut engine = CpuEngine::serial();
884 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2, 2], vec![1.0, 5.0, 3.0, 2.0])?;
885 /// let y = x.reduce_prod(Some(&[0]), &mut engine)?;
886 /// assert_eq!(y.host_data()?, &[5.0, 6.0]);
887 /// # Ok::<(), Box<dyn std::error::Error>>(())
888 /// ```
889 ///
890 /// # Errors
891 ///
892 /// Returns [`tenferro_tensor::Error::Validation`] for an out-of-range or repeated axis, or
893 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
894 /// An unsupported dtype returns [`tenferro_tensor::Error::Unsupported`].
895 fn reduce_prod(
896 &self,
897 axes: Option<&[usize]>,
898 session: &mut dyn Engine,
899 ) -> tenferro_tensor::Result<TypedTensor<T>>;
900 /// Sum elementwise squares over the selected axes on the engine (`f32`/`f64`). `None` reduces every axis and `Some(&[])` keeps the input shape.
901 ///
902 /// # Examples
903 ///
904 /// ```rust
905 /// use tenferro_cpu::CpuEngine;
906 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
907 ///
908 ///
909 /// let mut engine = CpuEngine::serial();
910 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2, 2], vec![1.0, 5.0, 3.0, 2.0])?;
911 /// let y = x.reduce_sum_squares(Some(&[0]), &mut engine)?;
912 /// assert_eq!(y.host_data()?, &[26.0, 13.0]);
913 /// # Ok::<(), Box<dyn std::error::Error>>(())
914 /// ```
915 ///
916 /// # Errors
917 ///
918 /// Returns [`tenferro_tensor::Error::Validation`] for an out-of-range or repeated axis, or
919 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
920 /// An unsupported dtype returns [`tenferro_tensor::Error::Unsupported`].
921 fn reduce_sum_squares(
922 &self,
923 axes: Option<&[usize]>,
924 session: &mut dyn Engine,
925 ) -> tenferro_tensor::Result<TypedTensor<T>>;
926 /// Contract this tensor with `rhs` on the engine (StableHLO `dot_general`).
927 ///
928 /// The output layout is `[lhs free..., rhs free..., batch...]` (batch axes trail).
929 ///
930 /// # Examples
931 ///
932 /// ```rust
933 /// use tenferro_cpu::CpuEngine;
934 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
935 ///
936 ///
937 /// let mut engine = CpuEngine::serial();
938 /// use tenferro_runtime::DotGeneralConfig;
939 /// let lhs = TypedTensor::<f64>::from_vec_col_major(vec![1, 2], vec![2.0, 3.0])?;
940 /// let rhs = TypedTensor::<f64>::from_vec_col_major(vec![2, 1], vec![4.0, 5.0])?;
941 /// let config = DotGeneralConfig {
942 /// lhs_contracting_dims: [1].as_slice().into(),
943 /// rhs_contracting_dims: [0].as_slice().into(),
944 /// lhs_batch_dims: [].as_slice().into(),
945 /// rhs_batch_dims: [].as_slice().into(),
946 /// };
947 /// let y = lhs.dot_general(&rhs, config, &mut engine)?;
948 /// assert_eq!(y.host_data()?, &[23.0]);
949 /// # Ok::<(), Box<dyn std::error::Error>>(())
950 /// ```
951 ///
952 /// # Errors
953 ///
954 /// Returns [`tenferro_tensor::Error::Validation`] for incompatible contraction or batch dimensions, or
955 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
956 fn dot_general(
957 &self,
958 rhs: &TypedTensor<T>,
959 config: DotGeneralConfig,
960 session: &mut dyn Engine,
961 ) -> tenferro_tensor::Result<TypedTensor<T>>;
962 /// Contract with optional conjugation of either operand on an engine.
963 ///
964 /// # Examples
965 ///
966 /// ```rust
967 /// use tenferro_cpu::CpuEngine;
968 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
969 ///
970 ///
971 /// let mut engine = CpuEngine::serial();
972 /// use num_complex::Complex64;
973 /// use tenferro_runtime::DotGeneralConfig;
974 /// let lhs = TypedTensor::<Complex64>::from_vec_col_major(vec![1, 1], vec![Complex64::new(0.0, 1.0)])?;
975 /// let rhs = TypedTensor::<Complex64>::from_vec_col_major(vec![1, 1], vec![Complex64::new(0.0, 1.0)])?;
976 /// let config = DotGeneralConfig {
977 /// lhs_contracting_dims: [1].as_slice().into(),
978 /// rhs_contracting_dims: [0].as_slice().into(),
979 /// lhs_batch_dims: [].as_slice().into(),
980 /// rhs_batch_dims: [].as_slice().into(),
981 /// };
982 /// let y = lhs.dot_general_with_conj(&rhs, config, true, false, &mut engine)?;
983 /// assert_eq!(y.host_data()?, &[Complex64::new(1.0, 0.0)]);
984 /// # Ok::<(), Box<dyn std::error::Error>>(())
985 /// ```
986 ///
987 /// # Errors
988 ///
989 /// Returns [`tenferro_tensor::Error::Validation`] for incompatible contraction or batch dimensions, or
990 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
991 fn dot_general_with_conj(
992 &self,
993 rhs: &TypedTensor<T>,
994 config: DotGeneralConfig,
995 lhs_conj: bool,
996 rhs_conj: bool,
997 session: &mut dyn Engine,
998 ) -> tenferro_tensor::Result<TypedTensor<T>>;
999 /// Multiply by a real scalar on the engine, with the eager `scale_real` dtype rules.
1000 ///
1001 /// Integer dtypes round the factor.
1002 ///
1003 /// # Examples
1004 ///
1005 /// ```rust
1006 /// use tenferro_cpu::CpuEngine;
1007 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1008 ///
1009 ///
1010 /// let mut engine = CpuEngine::serial();
1011 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 2.0])?;
1012 /// let y = x.scale_real(2.0, &mut engine)?;
1013 /// assert_eq!(y.host_data()?, &[2.0, 4.0]);
1014 /// # Ok::<(), Box<dyn std::error::Error>>(())
1015 /// ```
1016 ///
1017 /// # Errors
1018 ///
1019 /// Returns [`tenferro_tensor::Error::Validation`] with `InvalidArgument` for a
1020 /// non-finite factor or an integer factor out of range, or
1021 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
1022 fn scale_real(
1023 &self,
1024 factor: f64,
1025 session: &mut dyn Engine,
1026 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1027 /// Multiply a complex tensor by a complex scalar on an engine.
1028 ///
1029 /// # Examples
1030 ///
1031 /// ```rust
1032 /// use tenferro_cpu::CpuEngine;
1033 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1034 ///
1035 ///
1036 /// let mut engine = CpuEngine::serial();
1037 /// use num_complex::Complex64;
1038 /// let x = TypedTensor::<Complex64>::from_vec_col_major(vec![1], vec![Complex64::new(1.0, 2.0)])?;
1039 /// let y = x.scale_complex(Complex64::new(0.0, 1.0), &mut engine)?;
1040 /// assert_eq!(y.host_data()?, &[Complex64::new(-2.0, 1.0)]);
1041 /// # Ok::<(), Box<dyn std::error::Error>>(())
1042 /// ```
1043 ///
1044 /// # Errors
1045 ///
1046 /// Returns [`tenferro_tensor::Error::Validation`] with `InvalidArgument` when
1047 /// `T` is not complex, or [`tenferro_tensor::Error::BackendSource`] for a typed
1048 /// backend failure.
1049 fn scale_complex(
1050 &self,
1051 factor: Complex64,
1052 session: &mut dyn Engine,
1053 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1054 /// Logistic sigmoid `1 / (1 + exp(-x))` on the engine, overflow-free.
1055 ///
1056 /// Evaluated as `1 / (1 + e)` for `x > 0` and `e / (1 + e)` otherwise, with
1057 /// `e = exp(-|x|)`. Real `F32`/`F64` only.
1058 ///
1059 /// # Examples
1060 ///
1061 /// ```rust
1062 /// use tenferro_cpu::CpuEngine;
1063 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1064 ///
1065 ///
1066 /// let mut engine = CpuEngine::serial();
1067 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![3], vec![-700.0, 0.0, 1000.0])?;
1068 /// let y = x.sigmoid(&mut engine)?;
1069 /// let y = y.host_data()?;
1070 /// assert_eq!(y[1], 0.5);
1071 /// assert!(y[0] > 0.0 && y[0] < 1e-300);
1072 /// assert_eq!(y[2], 1.0);
1073 /// # Ok::<(), Box<dyn std::error::Error>>(())
1074 /// ```
1075 ///
1076 /// # Errors
1077 ///
1078 /// Returns [`tenferro_tensor::Error::UnsupportedDType`] for complex,
1079 /// integer, or `Bool` input, or [`tenferro_tensor::Error::BackendSource`]
1080 /// for a typed backend failure.
1081 fn sigmoid(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
1082 /// SiLU (swish) `x * sigmoid(x)` on an engine.
1083 ///
1084 /// Real `F32`/`F64` only.
1085 ///
1086 /// # Examples
1087 ///
1088 /// ```rust
1089 /// use tenferro_cpu::CpuEngine;
1090 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1091 ///
1092 ///
1093 /// let mut engine = CpuEngine::serial();
1094 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![3], vec![-1.0, 0.0, 1.0])?;
1095 /// let y = x.silu(&mut engine)?;
1096 /// let y = y.host_data()?;
1097 /// assert_eq!(y[1], 0.0);
1098 /// assert!((y[2] - 1.0 / (1.0 + (-1.0_f64).exp())).abs() < 1e-15);
1099 /// # Ok::<(), Box<dyn std::error::Error>>(())
1100 /// ```
1101 ///
1102 /// # Errors
1103 ///
1104 /// Returns [`tenferro_tensor::Error::UnsupportedDType`] for complex,
1105 /// integer, or `Bool` input, or [`tenferro_tensor::Error::BackendSource`]
1106 /// for a typed backend failure.
1107 fn silu(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
1108 /// Softplus `log(1 + exp(x))` on the engine, in the stable form `max(x, 0) + log1p(exp(-|x|))`.
1109 ///
1110 /// Real `F32`/`F64` only; never overflows.
1111 ///
1112 /// # Examples
1113 ///
1114 /// ```rust
1115 /// use tenferro_cpu::CpuEngine;
1116 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1117 ///
1118 ///
1119 /// let mut engine = CpuEngine::serial();
1120 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![3], vec![-1000.0, 0.0, 1000.0])?;
1121 /// let y = x.softplus(&mut engine)?;
1122 /// let y = y.host_data()?;
1123 /// assert_eq!(y[0], 0.0);
1124 /// assert!((y[1] - 2.0_f64.ln()).abs() < 1e-15);
1125 /// assert_eq!(y[2], 1000.0);
1126 /// # Ok::<(), Box<dyn std::error::Error>>(())
1127 /// ```
1128 ///
1129 /// # Errors
1130 ///
1131 /// Returns [`tenferro_tensor::Error::UnsupportedDType`] for complex,
1132 /// integer, or `Bool` input, or [`tenferro_tensor::Error::BackendSource`]
1133 /// for a typed backend failure.
1134 fn softplus(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
1135 /// Exact GELU `x/2 * (1 + erf(x / sqrt(2)))` on an engine.
1136 ///
1137 /// Real `F32`/`F64` only (PyTorch `approximate="none"`).
1138 ///
1139 /// # Examples
1140 ///
1141 /// ```rust
1142 /// use tenferro_cpu::CpuEngine;
1143 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1144 ///
1145 ///
1146 /// let mut engine = CpuEngine::serial();
1147 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![3], vec![-1.0, 0.0, 1.0])?;
1148 /// let y = x.gelu(&mut engine)?;
1149 /// let y = y.host_data()?;
1150 /// assert_eq!(y[1], 0.0);
1151 /// assert!((y[2] - 0.841_344_746_068_542_9).abs() < 1e-15);
1152 /// # Ok::<(), Box<dyn std::error::Error>>(())
1153 /// ```
1154 ///
1155 /// # Errors
1156 ///
1157 /// Returns [`tenferro_tensor::Error::UnsupportedDType`] for complex,
1158 /// integer, or `Bool` input, or [`tenferro_tensor::Error::BackendSource`]
1159 /// for a typed backend failure.
1160 fn gelu(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
1161 /// GELU tanh approximation on the engine (PyTorch `approximate="tanh"`).
1162 ///
1163 /// `x/2 * (1 + tanh(sqrt(2/pi) * (x + 0.044715 x^3)))`; real `F32`/`F64` only.
1164 ///
1165 /// # Examples
1166 ///
1167 /// ```rust
1168 /// use tenferro_cpu::CpuEngine;
1169 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1170 ///
1171 ///
1172 /// let mut engine = CpuEngine::serial();
1173 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![3], vec![-1.0, 0.0, 1.0])?;
1174 /// let y = x.gelu_tanh(&mut engine)?;
1175 /// let y = y.host_data()?;
1176 /// assert_eq!(y[1], 0.0);
1177 /// assert!((y[2] - 0.841_191_990_608_276_8).abs() < 1e-12);
1178 /// # Ok::<(), Box<dyn std::error::Error>>(())
1179 /// ```
1180 ///
1181 /// # Errors
1182 ///
1183 /// Returns [`tenferro_tensor::Error::UnsupportedDType`] for complex,
1184 /// integer, or `Bool` input, or [`tenferro_tensor::Error::BackendSource`]
1185 /// for a typed backend failure.
1186 fn gelu_tanh(&self, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
1187 /// Arithmetic mean over `axes` on the engine (`None` reduces every axis).
1188 ///
1189 /// Float and complex dtypes. The sum is divided by the element count; a mean
1190 /// over zero elements is `NaN`, and `Some(&[])` is the identity.
1191 ///
1192 /// # Examples
1193 ///
1194 /// ```rust
1195 /// use tenferro_cpu::CpuEngine;
1196 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1197 ///
1198 ///
1199 /// let mut engine = CpuEngine::serial();
1200 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2, 2], vec![1.0, 2.0, 3.0, 4.0])?;
1201 /// let y = x.reduce_mean(None, &mut engine)?;
1202 /// assert_eq!(y.host_data()?, &[2.5]);
1203 /// # Ok::<(), Box<dyn std::error::Error>>(())
1204 /// ```
1205 ///
1206 /// # Errors
1207 ///
1208 /// Returns [`tenferro_tensor::Error::UnsupportedDType`] for integer or
1209 /// `Bool` input, [`tenferro_tensor::Error::Validation`] with
1210 /// `AxisOutOfBounds` or `DuplicateAxis` for invalid axes, or
1211 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
1212 fn reduce_mean(
1213 &self,
1214 axes: Option<&[usize]>,
1215 session: &mut dyn Engine,
1216 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1217 /// Max-subtracted softmax along `axis` on an engine.
1218 ///
1219 /// Real `F32`/`F64` only. A slice that is entirely `-inf` returns zeros
1220 /// instead of `NaN`; a `NaN` or `+inf` entry makes its slice `NaN`.
1221 ///
1222 /// # Examples
1223 ///
1224 /// ```rust
1225 /// use tenferro_cpu::CpuEngine;
1226 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1227 ///
1228 ///
1229 /// let mut engine = CpuEngine::serial();
1230 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 1.0])?;
1231 /// let y = x.softmax(0, &mut engine)?;
1232 /// assert_eq!(y.host_data()?, &[0.5, 0.5]);
1233 /// # Ok::<(), Box<dyn std::error::Error>>(())
1234 /// ```
1235 ///
1236 /// # Errors
1237 ///
1238 /// Returns [`tenferro_tensor::Error::UnsupportedDType`] for complex,
1239 /// integer, or `Bool` input, [`tenferro_tensor::Error::Validation`] with
1240 /// `AxisOutOfBounds` for an invalid axis, or
1241 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
1242 fn softmax(
1243 &self,
1244 axis: usize,
1245 session: &mut dyn Engine,
1246 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1247 /// Max-subtracted log-softmax along `axis` on an engine.
1248 ///
1249 /// Real `F32`/`F64` only. A slice that is entirely `-inf` returns `-inf`
1250 /// instead of `NaN`.
1251 ///
1252 /// # Examples
1253 ///
1254 /// ```rust
1255 /// use tenferro_cpu::CpuEngine;
1256 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1257 ///
1258 ///
1259 /// let mut engine = CpuEngine::serial();
1260 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 1.0])?;
1261 /// let y = x.log_softmax(0, &mut engine)?;
1262 /// assert_eq!(y.host_data()?, &[-std::f64::consts::LN_2; 2]);
1263 /// # Ok::<(), Box<dyn std::error::Error>>(())
1264 /// ```
1265 ///
1266 /// # Errors
1267 ///
1268 /// Returns [`tenferro_tensor::Error::UnsupportedDType`] for complex,
1269 /// integer, or `Bool` input, [`tenferro_tensor::Error::Validation`] with
1270 /// `AxisOutOfBounds` for an invalid axis, or
1271 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
1272 fn log_softmax(
1273 &self,
1274 axis: usize,
1275 session: &mut dyn Engine,
1276 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1277 /// Softmax along `axis` over the entries where the `Bool` `mask` is true.
1278 ///
1279 /// `mask` broadcasts to the input shape. Masked-out entries are `0` whatever
1280 /// their value; a slice with no unmasked entry is all zeros.
1281 ///
1282 /// # Examples
1283 ///
1284 /// ```rust
1285 /// use tenferro_cpu::CpuEngine;
1286 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1287 ///
1288 ///
1289 /// let mut engine = CpuEngine::serial();
1290 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![3.0, 4.0])?;
1291 /// let mask = TypedTensor::<bool>::from_vec_col_major(vec![2], vec![false, false])?;
1292 /// let y = x.masked_softmax(&mask, 0, &mut engine)?;
1293 /// assert_eq!(y.host_data()?, &[0.0, 0.0]);
1294 /// # Ok::<(), Box<dyn std::error::Error>>(())
1295 /// ```
1296 ///
1297 /// # Errors
1298 ///
1299 /// Returns [`tenferro_tensor::Error::UnsupportedDType`] for complex,
1300 /// integer, or `Bool` input, [`tenferro_tensor::Error::Validation`] with
1301 /// `DTypeMismatch` for a non-`Bool` mask, `ShapeMismatch` for a mask that
1302 /// does not broadcast to the input, or `AxisOutOfBounds` for an invalid
1303 /// axis, or [`tenferro_tensor::Error::BackendSource`] for a typed backend
1304 /// failure.
1305 fn masked_softmax(
1306 &self,
1307 mask: &TypedTensor<bool>,
1308 axis: usize,
1309 session: &mut dyn Engine,
1310 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1311 /// Log-softmax along `axis` over the entries where the `Bool` `mask` is true.
1312 ///
1313 /// Masked-out entries are `-inf`; a slice with no unmasked entry is all `-inf`.
1314 ///
1315 /// # Examples
1316 ///
1317 /// ```rust
1318 /// use tenferro_cpu::CpuEngine;
1319 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1320 ///
1321 ///
1322 /// let mut engine = CpuEngine::serial();
1323 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![3.0, 4.0])?;
1324 /// let mask = TypedTensor::<bool>::from_vec_col_major(vec![2], vec![true, false])?;
1325 /// let y = x.masked_log_softmax(&mask, 0, &mut engine)?;
1326 /// assert_eq!(y.host_data()?, &[0.0, f64::NEG_INFINITY]);
1327 /// # Ok::<(), Box<dyn std::error::Error>>(())
1328 /// ```
1329 ///
1330 /// # Errors
1331 ///
1332 /// Returns [`tenferro_tensor::Error::UnsupportedDType`] for complex,
1333 /// integer, or `Bool` input, [`tenferro_tensor::Error::Validation`] with
1334 /// `DTypeMismatch` for a non-`Bool` mask, `ShapeMismatch` for a mask that
1335 /// does not broadcast to the input, or `AxisOutOfBounds` for an invalid
1336 /// axis, or [`tenferro_tensor::Error::BackendSource`] for a typed backend
1337 /// failure.
1338 fn masked_log_softmax(
1339 &self,
1340 mask: &TypedTensor<bool>,
1341 axis: usize,
1342 session: &mut dyn Engine,
1343 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1344 /// Layer normalization along `axis` with optional affine `weight` / `bias`, on an engine.
1345 ///
1346 /// `(x - mean) / sqrt(var + eps) * weight + bias` with the biased variance;
1347 /// `weight` and `bias` are rank-1 of length `shape[axis]`. Real `F32`/`F64` only.
1348 ///
1349 /// # Examples
1350 ///
1351 /// ```rust
1352 /// use tenferro_cpu::CpuEngine;
1353 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1354 ///
1355 ///
1356 /// let mut engine = CpuEngine::serial();
1357 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 3.0])?;
1358 /// let y = x.layer_norm(0, None, None, 0.0, &mut engine)?;
1359 /// assert_eq!(y.host_data()?, &[-1.0, 1.0]);
1360 /// # Ok::<(), Box<dyn std::error::Error>>(())
1361 /// ```
1362 ///
1363 /// # Errors
1364 ///
1365 /// Returns [`tenferro_tensor::Error::UnsupportedDType`] for complex,
1366 /// integer, or `Bool` input, [`tenferro_tensor::Error::Validation`] with
1367 /// `AxisOutOfBounds` for an invalid axis, `InvalidArgument` for a negative
1368 /// or non-finite `eps`, or `DTypeMismatch` / `ShapeMismatch` for a weight or
1369 /// bias that is not a same-dtype vector of the axis length, or
1370 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
1371 fn layer_norm(
1372 &self,
1373 axis: usize,
1374 weight: Option<&TypedTensor<T>>,
1375 bias: Option<&TypedTensor<T>>,
1376 eps: f64,
1377 session: &mut dyn Engine,
1378 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1379 /// RMS normalization along `axis` with optional affine `weight` / `bias`, on an engine.
1380 ///
1381 /// `x / sqrt(mean(x^2) + eps) * weight + bias`; `weight` and `bias` are rank-1
1382 /// of length `shape[axis]`. Real `F32`/`F64` only.
1383 ///
1384 /// # Examples
1385 ///
1386 /// ```rust
1387 /// use tenferro_cpu::CpuEngine;
1388 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1389 ///
1390 ///
1391 /// let mut engine = CpuEngine::serial();
1392 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![0.0, 0.0])?;
1393 /// let y = x.rms_norm(0, None, None, 1e-6, &mut engine)?;
1394 /// assert_eq!(y.host_data()?, &[0.0, 0.0]);
1395 /// # Ok::<(), Box<dyn std::error::Error>>(())
1396 /// ```
1397 ///
1398 /// # Errors
1399 ///
1400 /// Returns [`tenferro_tensor::Error::UnsupportedDType`] for complex,
1401 /// integer, or `Bool` input, [`tenferro_tensor::Error::Validation`] with
1402 /// `AxisOutOfBounds` for an invalid axis, `InvalidArgument` for a negative
1403 /// or non-finite `eps`, or `DTypeMismatch` / `ShapeMismatch` for a weight or
1404 /// bias that is not a same-dtype vector of the axis length, or
1405 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
1406 fn rms_norm(
1407 &self,
1408 axis: usize,
1409 weight: Option<&TypedTensor<T>>,
1410 bias: Option<&TypedTensor<T>>,
1411 eps: f64,
1412 session: &mut dyn Engine,
1413 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1414
1415 /// Gather windows of this tensor at `indices` on an engine (StableHLO `gather`).
1416 ///
1417 /// Mirrors [`crate::TensorSessionOpsExt::gather`]; the index tensor stays
1418 /// dtype-erased, as on that surface.
1419 ///
1420 /// # Examples
1421 ///
1422 /// ```rust
1423 /// use tenferro_cpu::CpuEngine;
1424 /// use tenferro_runtime::{GatherConfig, Tensor, TypedTensor, TypedTensorSessionOpsExt};
1425 ///
1426 /// let mut engine = CpuEngine::serial();
1427 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![3, 2], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])?;
1428 /// // Row 1 of a 3x2 matrix.
1429 /// let idx = Tensor::from_vec_col_major(vec![1, 1], vec![1_i64])?;
1430 /// let config = GatherConfig {
1431 /// offset_dims: vec![1],
1432 /// collapsed_slice_dims: vec![0],
1433 /// start_index_map: vec![0],
1434 /// index_vector_dim: 1,
1435 /// slice_sizes: vec![1, 2],
1436 /// };
1437 /// let row = x.gather(&idx, config, &mut engine)?;
1438 /// assert_eq!(row.host_data()?, &[2.0, 5.0]);
1439 /// # Ok::<(), Box<dyn std::error::Error>>(())
1440 /// ```
1441 ///
1442 /// # Errors
1443 ///
1444 /// Returns [`tenferro_tensor::Error::Validation`] for an invalid shape,
1445 /// axis, dtype or configuration, or [`tenferro_tensor::Error::BackendSource`]
1446 /// for a typed backend failure.
1447 fn gather(
1448 &self,
1449 indices: &tenferro_tensor::Tensor,
1450 config: crate::GatherConfig,
1451 session: &mut dyn Engine,
1452 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1453 /// Scatter `updates` into a copy of this tensor at `indices` on an engine.
1454 ///
1455 /// # Examples
1456 ///
1457 /// ```rust
1458 /// use tenferro_cpu::CpuEngine;
1459 /// use tenferro_runtime::{ScatterConfig, Tensor, TypedTensor, TypedTensorSessionOpsExt};
1460 ///
1461 /// let mut engine = CpuEngine::serial();
1462 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![3, 2], vec![0.0; 6])?;
1463 /// // Add `[10, 20]` into row 1.
1464 /// let idx = Tensor::from_vec_col_major(vec![1, 1], vec![1_i64])?;
1465 /// let updates = Tensor::from_vec_col_major(vec![1, 2], vec![10.0_f64, 20.0])?;
1466 /// let config = ScatterConfig {
1467 /// update_window_dims: vec![1],
1468 /// inserted_window_dims: vec![0],
1469 /// scatter_dims_to_operand_dims: vec![0],
1470 /// index_vector_dim: 1,
1471 /// };
1472 /// let y = x.scatter(&idx, &updates, config, &mut engine)?;
1473 /// assert_eq!(y.host_data()?, &[0.0, 10.0, 0.0, 0.0, 20.0, 0.0]);
1474 /// # Ok::<(), Box<dyn std::error::Error>>(())
1475 /// ```
1476 ///
1477 /// # Errors
1478 ///
1479 /// Returns [`tenferro_tensor::Error::Validation`] for an invalid shape,
1480 /// axis, dtype or configuration, or [`tenferro_tensor::Error::BackendSource`]
1481 /// for a typed backend failure.
1482 fn scatter(
1483 &self,
1484 indices: &tenferro_tensor::Tensor,
1485 updates: &tenferro_tensor::Tensor,
1486 config: crate::ScatterConfig,
1487 session: &mut dyn Engine,
1488 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1489 /// Slice this tensor with start, limit and stride per axis on an engine.
1490 ///
1491 /// # Examples
1492 ///
1493 /// ```rust
1494 /// use tenferro_cpu::CpuEngine;
1495 /// use tenferro_runtime::{SliceConfig, TypedTensor, TypedTensorSessionOpsExt};
1496 ///
1497 /// let mut engine = CpuEngine::serial();
1498 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![3, 2], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])?;
1499 /// let config = SliceConfig {
1500 /// starts: vec![1, 0],
1501 /// limits: vec![3, 2],
1502 /// strides: vec![1, 1],
1503 /// };
1504 /// let y = x.slice(config, &mut engine)?;
1505 /// assert_eq!(y.shape(), &[2, 2]);
1506 /// assert_eq!(y.host_data()?, &[2.0, 3.0, 5.0, 6.0]);
1507 /// # Ok::<(), Box<dyn std::error::Error>>(())
1508 /// ```
1509 ///
1510 /// # Errors
1511 ///
1512 /// Returns [`tenferro_tensor::Error::Validation`] for an invalid shape,
1513 /// axis, dtype or configuration, or [`tenferro_tensor::Error::BackendSource`]
1514 /// for a typed backend failure.
1515 fn slice(
1516 &self,
1517 config: crate::SliceConfig,
1518 session: &mut dyn Engine,
1519 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1520 /// Slice at runtime `starts` with static `sizes` on an engine.
1521 ///
1522 /// # Examples
1523 ///
1524 /// ```rust
1525 /// use tenferro_cpu::CpuEngine;
1526 /// use tenferro_runtime::{Tensor, TypedTensor, TypedTensorSessionOpsExt};
1527 ///
1528 /// let mut engine = CpuEngine::serial();
1529 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![5], vec![0.0, 1.0, 2.0, 3.0, 4.0])?;
1530 /// // A start of 4 is clamped so the window of 2 fits.
1531 /// let starts = Tensor::from_vec_col_major(vec![1], vec![4_i64])?;
1532 /// let y = x.dynamic_slice(&starts, &[2], &mut engine)?;
1533 /// assert_eq!(y.host_data()?, &[3.0, 4.0]);
1534 /// # Ok::<(), Box<dyn std::error::Error>>(())
1535 /// ```
1536 ///
1537 /// # Errors
1538 ///
1539 /// Returns [`tenferro_tensor::Error::Validation`] for an invalid shape,
1540 /// axis, dtype or configuration, or [`tenferro_tensor::Error::BackendSource`]
1541 /// for a typed backend failure.
1542 fn dynamic_slice(
1543 &self,
1544 starts: &tenferro_tensor::Tensor,
1545 sizes: &[usize],
1546 session: &mut dyn Engine,
1547 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1548 /// Return this tensor with `update` written at runtime `starts` on an engine.
1549 ///
1550 /// Mirrors [`crate::TensorSessionOpsExt::dynamic_update_slice`]; `starts`
1551 /// stays dtype-erased, as on that surface.
1552 ///
1553 /// # Examples
1554 ///
1555 /// ```rust
1556 /// use tenferro_cpu::CpuEngine;
1557 /// use tenferro_runtime::{Tensor, TypedTensor, TypedTensorSessionOpsExt};
1558 ///
1559 /// let mut engine = CpuEngine::serial();
1560 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![5], vec![0.0; 5])?;
1561 /// let update = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![3.0, 4.0])?;
1562 /// let starts = Tensor::from_vec_col_major(vec![1], vec![1_i64])?;
1563 /// let y = x.dynamic_update_slice(&update, &starts, &mut engine)?;
1564 /// assert_eq!(y.host_data()?, &[0.0, 3.0, 4.0, 0.0, 0.0]);
1565 /// # Ok::<(), Box<dyn std::error::Error>>(())
1566 /// ```
1567 ///
1568 /// # Errors
1569 ///
1570 /// Returns [`tenferro_tensor::Error::Validation`] for an invalid shape,
1571 /// axis, dtype or configuration, or [`tenferro_tensor::Error::BackendSource`]
1572 /// for a typed backend failure.
1573 fn dynamic_update_slice(
1574 &self,
1575 update: &TypedTensor<T>,
1576 starts: &tenferro_tensor::Tensor,
1577 session: &mut dyn Engine,
1578 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1579 /// Pad this tensor with zeros on an engine.
1580 ///
1581 /// # Examples
1582 ///
1583 /// ```rust
1584 /// use tenferro_cpu::CpuEngine;
1585 /// use tenferro_runtime::{PadConfig, TypedTensor, TypedTensorSessionOpsExt};
1586 ///
1587 /// let mut engine = CpuEngine::serial();
1588 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 2.0])?;
1589 /// let config = PadConfig {
1590 /// edge_padding_low: vec![1],
1591 /// edge_padding_high: vec![0],
1592 /// interior_padding: vec![0],
1593 /// };
1594 /// let y = x.pad(config, &mut engine)?;
1595 /// assert_eq!(y.host_data()?, &[0.0, 1.0, 2.0]);
1596 /// # Ok::<(), Box<dyn std::error::Error>>(())
1597 /// ```
1598 ///
1599 /// # Errors
1600 ///
1601 /// Returns [`tenferro_tensor::Error::Validation`] for an invalid shape,
1602 /// axis, dtype or configuration, or [`tenferro_tensor::Error::BackendSource`]
1603 /// for a typed backend failure.
1604 fn pad(
1605 &self,
1606 config: crate::PadConfig,
1607 session: &mut dyn Engine,
1608 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1609 /// Concatenate typed tensors along `axis` on an engine.
1610 ///
1611 /// N-ary, so it stays an associated function, matching the erased surface.
1612 ///
1613 /// # Examples
1614 ///
1615 /// ```rust
1616 /// use tenferro_cpu::CpuEngine;
1617 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1618 ///
1619 /// let mut engine = CpuEngine::serial();
1620 /// let a = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 2.0])?;
1621 /// let b = TypedTensor::<f64>::from_vec_col_major(vec![1], vec![3.0])?;
1622 /// let y = TypedTensor::concatenate(&[&a, &b], 0, &mut engine)?;
1623 /// assert_eq!(y.host_data()?, &[1.0, 2.0, 3.0]);
1624 /// # Ok::<(), Box<dyn std::error::Error>>(())
1625 /// ```
1626 ///
1627 /// # Errors
1628 ///
1629 /// Returns [`tenferro_tensor::Error::Validation`] for an invalid shape,
1630 /// axis, dtype or configuration, or [`tenferro_tensor::Error::BackendSource`]
1631 /// for a typed backend failure.
1632 fn concatenate(
1633 inputs: &[&TypedTensor<T>],
1634 axis: usize,
1635 session: &mut dyn Engine,
1636 ) -> tenferro_tensor::Result<TypedTensor<T>>
1637 where
1638 Self: Sized;
1639 /// Reverse the elements along `axes` on an engine.
1640 ///
1641 /// # Examples
1642 ///
1643 /// ```rust
1644 /// use tenferro_cpu::CpuEngine;
1645 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1646 ///
1647 /// let mut engine = CpuEngine::serial();
1648 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![3], vec![1.0, 2.0, 3.0])?;
1649 /// let y = x.reverse(&[0], &mut engine)?;
1650 /// assert_eq!(y.host_data()?, &[3.0, 2.0, 1.0]);
1651 /// # Ok::<(), Box<dyn std::error::Error>>(())
1652 /// ```
1653 ///
1654 /// # Errors
1655 ///
1656 /// Returns [`tenferro_tensor::Error::Validation`] for an invalid shape,
1657 /// axis, dtype or configuration, or [`tenferro_tensor::Error::BackendSource`]
1658 /// for a typed backend failure.
1659 fn reverse(
1660 &self,
1661 axes: &[usize],
1662 session: &mut dyn Engine,
1663 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1664 /// Zero the elements above the `k`-th diagonal on an engine (keep the lower triangle).
1665 ///
1666 /// # Examples
1667 ///
1668 /// ```rust
1669 /// use tenferro_cpu::CpuEngine;
1670 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1671 ///
1672 /// let mut engine = CpuEngine::serial();
1673 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2, 2], vec![1.0, 2.0, 3.0, 4.0])?;
1674 /// let lower = x.tril(0, &mut engine)?;
1675 /// assert_eq!(lower.host_data()?, &[1.0, 2.0, 0.0, 4.0]);
1676 /// # Ok::<(), Box<dyn std::error::Error>>(())
1677 /// ```
1678 ///
1679 /// # Errors
1680 ///
1681 /// Returns [`tenferro_tensor::Error::Validation`] for an invalid shape,
1682 /// axis, dtype or configuration, or [`tenferro_tensor::Error::BackendSource`]
1683 /// for a typed backend failure.
1684 fn tril(&self, k: i64, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
1685 /// Zero the elements below the `k`-th diagonal on an engine (keep the upper triangle).
1686 ///
1687 /// # Examples
1688 ///
1689 /// ```rust
1690 /// use tenferro_cpu::CpuEngine;
1691 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1692 ///
1693 /// let mut engine = CpuEngine::serial();
1694 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2, 2], vec![1.0, 2.0, 3.0, 4.0])?;
1695 /// let upper = x.triu(0, &mut engine)?;
1696 /// assert_eq!(upper.host_data()?, &[1.0, 0.0, 3.0, 4.0]);
1697 /// # Ok::<(), Box<dyn std::error::Error>>(())
1698 /// ```
1699 ///
1700 /// # Errors
1701 ///
1702 /// Returns [`tenferro_tensor::Error::Validation`] for an invalid shape,
1703 /// axis, dtype or configuration, or [`tenferro_tensor::Error::BackendSource`]
1704 /// for a typed backend failure.
1705 fn triu(&self, k: i64, session: &mut dyn Engine) -> tenferro_tensor::Result<TypedTensor<T>>;
1706 /// Extract the diagonal over `axis_a` and `axis_b` on an engine.
1707 ///
1708 /// # Examples
1709 ///
1710 /// ```rust
1711 /// use tenferro_cpu::CpuEngine;
1712 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1713 ///
1714 /// let mut engine = CpuEngine::serial();
1715 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2, 2], vec![1.0, 2.0, 3.0, 4.0])?;
1716 /// let diagonal = x.extract_diag(0, 1, &mut engine)?;
1717 /// assert_eq!(diagonal.host_data()?, &[1.0, 4.0]);
1718 /// # Ok::<(), Box<dyn std::error::Error>>(())
1719 /// ```
1720 ///
1721 /// # Errors
1722 ///
1723 /// Returns [`tenferro_tensor::Error::Validation`] for an invalid shape,
1724 /// axis, dtype or configuration, or [`tenferro_tensor::Error::BackendSource`]
1725 /// for a typed backend failure.
1726 fn extract_diag(
1727 &self,
1728 axis_a: usize,
1729 axis_b: usize,
1730 session: &mut dyn Engine,
1731 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1732 /// Embed this tensor along the diagonal of `axis_a` and `axis_b` on an engine.
1733 ///
1734 /// # Examples
1735 ///
1736 /// ```rust
1737 /// use tenferro_cpu::CpuEngine;
1738 /// use tenferro_runtime::{TypedTensor, TypedTensorSessionOpsExt};
1739 ///
1740 /// let mut engine = CpuEngine::serial();
1741 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 2.0])?;
1742 /// let y = x.embed_diag(0, 1, &mut engine)?;
1743 /// assert_eq!(y.shape(), &[2, 2]);
1744 /// assert_eq!(y.host_data()?, &[1.0, 0.0, 0.0, 2.0]);
1745 /// # Ok::<(), Box<dyn std::error::Error>>(())
1746 /// ```
1747 ///
1748 /// # Errors
1749 ///
1750 /// Returns [`tenferro_tensor::Error::Validation`] for an invalid shape,
1751 /// axis, dtype or configuration, or [`tenferro_tensor::Error::BackendSource`]
1752 /// for a typed backend failure.
1753 fn embed_diag(
1754 &self,
1755 axis_a: usize,
1756 axis_b: usize,
1757 session: &mut dyn Engine,
1758 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1759 /// NumPy-style `take_along_axis` over `gather`, on an engine.
1760 ///
1761 /// Mirrors [`crate::TensorSessionOpsExt::take_along_axis`]; the index
1762 /// tensor stays dtype-erased, as on that surface.
1763 ///
1764 /// # Examples
1765 ///
1766 /// ```rust
1767 /// use tenferro_cpu::CpuEngine;
1768 /// use tenferro_runtime::{Tensor, TypedTensor, TypedTensorSessionOpsExt};
1769 ///
1770 /// let mut engine = CpuEngine::serial();
1771 /// // Per-batch row gather: out[i, j, b] = x[idx[i, b], j, b].
1772 /// let x = TypedTensor::<f64>::from_vec_col_major(vec![2, 2, 2], (0..8).map(f64::from).collect())?;
1773 /// let idx = Tensor::from_vec_col_major(vec![2, 1, 2], vec![1_i64, 0, 0, 0])?;
1774 /// let y = x.take_along_axis(&idx, 0, &mut engine)?;
1775 /// assert_eq!(y.host_data()?, &[1.0, 0.0, 3.0, 2.0, 4.0, 4.0, 6.0, 6.0]);
1776 /// # Ok::<(), Box<dyn std::error::Error>>(())
1777 /// ```
1778 ///
1779 /// # Errors
1780 ///
1781 /// Returns [`tenferro_tensor::Error::Validation`] with `RankMismatch` or
1782 /// `ShapeMismatch` for incompatible index shapes, `AxisOutOfBounds` for an
1783 /// invalid axis, or `InvalidArgument` when taking from a zero-length axis;
1784 /// [`tenferro_tensor::Error::UnsupportedDType`] for a non-integer index
1785 /// dtype; or [`tenferro_tensor::Error::BackendSource`] for a typed backend
1786 /// failure.
1787 fn take_along_axis(
1788 &self,
1789 indices: &tenferro_tensor::Tensor,
1790 axis: usize,
1791 session: &mut dyn Engine,
1792 ) -> tenferro_tensor::Result<TypedTensor<T>>;
1793}
1794
1795/// Engine-explicit bool-mask operations for typed tensors.
1796///
1797/// This trait keeps `where_select` available as a method on bool
1798/// `TypedTensor`s while preserving the crate-root extension-trait surface. It
1799/// is public because downstream users call it directly; the implementation
1800/// helper in the private `typed_tensor` module is not a compatibility API.
1801///
1802/// # Examples
1803///
1804/// ```rust
1805/// use tenferro_cpu::CpuEngine;
1806/// use tenferro_runtime::{TypedTensor, TypedTensorMaskSessionOpsExt};
1807///
1808/// let mut engine = CpuEngine::serial();
1809/// let condition =
1810/// TypedTensor::<bool>::from_vec_col_major(vec![2], vec![true, false]).unwrap();
1811/// let on_true = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![1.0, 2.0]).unwrap();
1812/// let on_false = TypedTensor::<f64>::from_vec_col_major(vec![2], vec![3.0, 4.0]).unwrap();
1813/// let selected = condition.where_select(&on_true, &on_false, &mut engine)?;
1814/// assert_eq!(selected.host_data().unwrap(), &[1.0, 4.0]);
1815/// # Ok::<(), Box<dyn std::error::Error>>(())
1816/// ```
1817pub trait TypedTensorMaskSessionOpsExt {
1818 /// Select typed values using this bool tensor as condition.
1819 ///
1820 /// The condition broadcasts against both branches (NumPy rules).
1821 ///
1822 /// # Examples
1823 ///
1824 /// ```rust
1825 /// use tenferro_cpu::CpuEngine;
1826 /// use tenferro_runtime::{TypedTensor, TypedTensorMaskSessionOpsExt};
1827 ///
1828 ///
1829 /// let mut engine = CpuEngine::serial();
1830 /// let mask = TypedTensor::<bool>::from_vec_col_major(vec![], vec![false])?;
1831 /// let x = TypedTensor::<i64>::from_vec_col_major(vec![2], vec![1, 2])?;
1832 /// let y = TypedTensor::<i64>::from_vec_col_major(vec![2], vec![3, 4])?;
1833 /// let picked = mask.where_select(&x, &y, &mut engine)?;
1834 /// assert_eq!(picked.host_data()?, &[3, 4]);
1835 /// # Ok::<(), Box<dyn std::error::Error>>(())
1836 /// ```
1837 ///
1838 /// # Errors
1839 ///
1840 /// Returns [`tenferro_tensor::Error::Validation`] with
1841 /// `ShapeMismatch::IncompatibleShapes` when the condition or either branch
1842 /// cannot broadcast to the other operands, or
1843 /// [`tenferro_tensor::Error::BackendSource`] for a typed backend failure.
1844 fn where_select<U: TensorScalar>(
1845 &self,
1846 on_true: &TypedTensor<U>,
1847 on_false: &TypedTensor<U>,
1848 session: &mut dyn Engine,
1849 ) -> tenferro_tensor::Result<TypedTensor<U>>;
1850}
1851
1852#[cfg(test)]
1853mod tests;