use crate::{MattenError, Tensor};
impl Tensor {
fn map_unchecked(&self, f: impl Fn(f64) -> f64) -> Tensor {
Tensor {
data: self.data.iter().map(|&v| f(v)).collect(),
shape: self.shape.clone(),
#[cfg(feature = "dynamic")]
dynamic: None,
}
}
#[must_use]
pub fn abs(&self) -> Tensor {
#[cfg(feature = "dynamic")]
self.panic_if_dynamic("abs");
self.map_unchecked(f64::abs)
}
#[must_use]
pub fn sqrt(&self) -> Tensor {
#[cfg(feature = "dynamic")]
self.panic_if_dynamic("sqrt");
self.map_unchecked(f64::sqrt)
}
#[must_use]
pub fn exp(&self) -> Tensor {
#[cfg(feature = "dynamic")]
self.panic_if_dynamic("exp");
self.map_unchecked(f64::exp)
}
#[must_use]
pub fn ln(&self) -> Tensor {
#[cfg(feature = "dynamic")]
self.panic_if_dynamic("ln");
self.map_unchecked(f64::ln)
}
#[must_use]
pub fn clip(&self, min: f64, max: f64) -> Tensor {
#[cfg(feature = "dynamic")]
self.panic_if_dynamic("clip");
assert!(
min <= max,
"matten invalid argument error in clip: min/max: min must be <= max (got min={min}, max={max})"
);
self.map_unchecked(|v| v.clamp(min, max))
}
pub fn try_clip(&self, min: f64, max: f64) -> Result<Tensor, MattenError> {
#[cfg(feature = "dynamic")]
if self.is_dynamic() {
return Err(MattenError::Unsupported {
operation: "clip",
message: "clip is not supported on dynamic tensors; call try_numeric() first"
.to_string(),
});
}
if min.is_nan() || max.is_nan() || min > max {
return Err(MattenError::InvalidArgument {
operation: "clip",
argument: "min/max",
message: format!("min must be <= max (got min={min}, max={max})"),
});
}
Ok(self.map_unchecked(|v| v.clamp(min, max)))
}
}