summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorHydroH <ixlesis@gmail.com>2024-10-31 20:41:50 +0800
committerGitHub <noreply@github.com>2024-10-31 12:41:50 +0000
commit066e9349f96b7bc56536d48aaae29d98f0ee76fa (patch)
tree1d2f4e6a6edb7a279dac3c75a1c6ebfbaa9bb1ca /crates
parent30427ac842000d10666b602a2a313058bc32708e (diff)
Add `calc.norm()` function to compute euclidean norms (#4581)
Co-authored-by: +merlan #flirora <uruwi@protonmail.com> Co-authored-by: Yip Coekjan <69834864+Coekjan@users.noreply.github.com> Co-authored-by: Malo <57839069+MDLC01@users.noreply.github.com> Co-authored-by: Laurenz <laurmaedje@gmail.com>
Diffstat (limited to 'crates')
-rw-r--r--crates/typst-library/src/foundations/calc.rs33
1 files changed, 33 insertions, 0 deletions
diff --git a/crates/typst-library/src/foundations/calc.rs b/crates/typst-library/src/foundations/calc.rs
index f12ca74c..e7eb1405 100644
--- a/crates/typst-library/src/foundations/calc.rs
+++ b/crates/typst-library/src/foundations/calc.rs
@@ -50,6 +50,7 @@ pub fn module() -> Module {
scope.define_func::<div_euclid>();
scope.define_func::<rem_euclid>();
scope.define_func::<quo>();
+ scope.define_func::<norm>();
scope.define("inf", f64::INFINITY);
scope.define("pi", std::f64::consts::PI);
scope.define("tau", std::f64::consts::TAU);
@@ -1056,6 +1057,38 @@ pub fn quo(
floor(divided).at(span)
}
+/// Calculates the p-norm of a sequence of values.
+///
+/// ```example
+/// #calc.norm(1, 2, -3, 0.5) \
+/// #calc.norm(p: 3, 1, 2)
+/// ```
+#[func(title = "𝑝-Norm")]
+pub fn norm(
+ /// The p value to calculate the p-norm of.
+ #[named]
+ #[default(Spanned::new(2.0, Span::detached()))]
+ p: Spanned<f64>,
+ /// The sequence of values from which to calculate the p-norm.
+ /// Returns `0.0` if empty.
+ #[variadic]
+ values: Vec<f64>,
+) -> SourceResult<f64> {
+ if p.v <= 0.0 {
+ bail!(p.span, "p must be greater than zero");
+ }
+
+ // Create an iterator over the absolute values.
+ let abs = values.into_iter().map(f64::abs);
+
+ Ok(if p.v.is_infinite() {
+ // When p is infinity, the p-norm is the maximum of the absolute values.
+ abs.max_by(|a, b| a.total_cmp(b)).unwrap_or(0.0)
+ } else {
+ abs.map(|v| v.powf(p.v)).sum::<f64>().powf(1.0 / p.v)
+ })
+}
+
/// A value which can be passed to functions that work with integers and floats.
#[derive(Debug, Copy, Clone)]
pub enum Num {