From 4806e56baad8c456106b88d620113ceaf7035065 Mon Sep 17 00:00:00 2001 From: Hayleigh Thompson Date: Sat, 17 Aug 2024 11:21:44 +0100 Subject: [PATCH 1/4] :recycle: Remove type annotations in let bindings. --- src/gleam_community/maths/arithmetics.gleam | 80 +++--- src/gleam_community/maths/elementary.gleam | 38 +-- src/gleam_community/maths/metrics.gleam | 272 +++++++++--------- src/gleam_community/maths/piecewise.gleam | 68 ++--- src/gleam_community/maths/predicates.gleam | 98 +++---- src/gleam_community/maths/sequences.gleam | 40 +-- src/gleam_community/maths/special.gleam | 30 +- test/gleam_community/maths/metrics_test.gleam | 46 ++- .../maths/predicates_test.gleam | 20 +- 9 files changed, 344 insertions(+), 348 deletions(-) diff --git a/src/gleam_community/maths/arithmetics.gleam b/src/gleam_community/maths/arithmetics.gleam index dfa3c8d..ab8eb12 100644 --- a/src/gleam_community/maths/arithmetics.gleam +++ b/src/gleam_community/maths/arithmetics.gleam @@ -20,11 +20,11 @@ //// -//// +//// //// --- -//// +//// //// Arithmetics: A module containing a collection of fundamental mathematical functions relating to simple arithmetics (addition, subtraction, multiplication, etc.), but also number theory. -//// +//// //// * **Division functions** //// * [`gcd`](#gcd) //// * [`lcm`](#lcm) @@ -40,7 +40,7 @@ //// * [`int_cumulative_sum`](#int_cumulative_sum) //// * [`float_cumulative_product`](#float_cumulative_product) //// * [`int_cumulative_product`](#int_cumulative_product) -//// +//// import gleam/int import gleam/list @@ -57,7 +57,7 @@ import gleam_community/maths/piecewise /// /// /// -/// The function calculates the greatest common divisor of two integers +/// The function calculates the greatest common divisor of two integers /// \\(x, y \in \mathbb{Z}\\). The greatest common divisor is the largest positive /// integer that is divisible by both \\(x\\) and \\(y\\). /// @@ -70,7 +70,7 @@ import gleam_community/maths/piecewise /// pub fn example() { /// arithmetics.gcd(1, 1) /// |> should.equal(1) -/// +/// /// arithmetics.gcd(100, 10) /// |> should.equal(10) /// @@ -86,8 +86,8 @@ import gleam_community/maths/piecewise /// /// pub fn gcd(x: Int, y: Int) -> Int { - let absx: Int = piecewise.int_absolute_value(x) - let absy: Int = piecewise.int_absolute_value(y) + let absx = piecewise.int_absolute_value(x) + let absy = piecewise.int_absolute_value(y) do_gcd(absx, absy) } @@ -107,24 +107,24 @@ fn do_gcd(x: Int, y: Int) -> Int { /// /// /// -/// +/// /// Given two integers, \\(x\\) (dividend) and \\(y\\) (divisor), the Euclidean modulo -/// of \\(x\\) by \\(y\\), denoted as \\(x \mod y\\), is the remainder \\(r\\) of the +/// of \\(x\\) by \\(y\\), denoted as \\(x \mod y\\), is the remainder \\(r\\) of the /// division of \\(x\\) by \\(y\\), such that: -/// +/// /// \\[ /// x = q \cdot y + r \quad \text{and} \quad 0 \leq r < |y|, /// \\] -/// +/// /// where \\(q\\) is an integer that represents the quotient of the division. /// -/// The Euclidean modulo function of two numbers, is the remainder operation most -/// commonly utilized in mathematics. This differs from the standard truncating -/// modulo operation frequently employed in programming via the `%` operator. -/// Unlike the `%` operator, which may return negative results depending on the -/// divisor's sign, the Euclidean modulo function is designed to always yield a +/// The Euclidean modulo function of two numbers, is the remainder operation most +/// commonly utilized in mathematics. This differs from the standard truncating +/// modulo operation frequently employed in programming via the `%` operator. +/// Unlike the `%` operator, which may return negative results depending on the +/// divisor's sign, the Euclidean modulo function is designed to always yield a /// positive outcome, ensuring consistency with mathematical conventions. -/// +/// /// Note that like the Gleam division operator `/` this will return `0` if one of /// the arguments is `0`. /// @@ -138,7 +138,7 @@ fn do_gcd(x: Int, y: Int) -> Int { /// pub fn example() { /// arithmetics.euclidean_modulo(15, 4) /// |> should.equal(3) -/// +/// /// arithmetics.euclidean_modulo(-3, -2) /// |> should.equal(1) /// @@ -168,7 +168,7 @@ pub fn int_euclidean_modulo(x: Int, y: Int) -> Int { /// /// /// -/// The function calculates the least common multiple of two integers +/// The function calculates the least common multiple of two integers /// \\(x, y \in \mathbb{Z}\\). The least common multiple is the smallest positive /// integer that has both \\(x\\) and \\(y\\) as factors. /// @@ -181,7 +181,7 @@ pub fn int_euclidean_modulo(x: Int, y: Int) -> Int { /// pub fn example() { /// arithmetics.lcm(1, 1) /// |> should.equal(1) -/// +/// /// arithmetics.lcm(100, 10) /// |> should.equal(100) /// @@ -197,8 +197,8 @@ pub fn int_euclidean_modulo(x: Int, y: Int) -> Int { /// /// pub fn lcm(x: Int, y: Int) -> Int { - let absx: Int = piecewise.int_absolute_value(x) - let absy: Int = piecewise.int_absolute_value(y) + let absx = piecewise.int_absolute_value(x) + let absy = piecewise.int_absolute_value(y) absx * absy / do_gcd(absx, absy) } @@ -208,7 +208,7 @@ pub fn lcm(x: Int, y: Int) -> Int { /// /// /// -/// The function returns all the positive divisors of an integer, including the +/// The function returns all the positive divisors of an integer, including the /// number itself. /// ///
@@ -240,9 +240,9 @@ pub fn divisors(n: Int) -> List(Int) { } fn find_divisors(n: Int) -> List(Int) { - let nabs: Float = piecewise.float_absolute_value(conversion.int_to_float(n)) + let nabs = piecewise.float_absolute_value(conversion.int_to_float(n)) let assert Ok(sqrt_result) = elementary.square_root(nabs) - let max: Int = conversion.float_to_int(sqrt_result) + 1 + let max = conversion.float_to_int(sqrt_result) + 1 list.range(2, max) |> list.fold([1, n], fn(acc: List(Int), i: Int) -> List(Int) { case n % i == 0 { @@ -260,7 +260,7 @@ fn find_divisors(n: Int) -> List(Int) { /// /// /// -/// The function returns all the positive divisors of an integer, excluding the +/// The function returns all the positive divisors of an integer, excluding the /// number iteself. /// ///
@@ -288,7 +288,7 @@ fn find_divisors(n: Int) -> List(Int) { /// /// pub fn proper_divisors(n: Int) -> List(Int) { - let divisors: List(Int) = find_divisors(n) + let divisors = find_divisors(n) divisors |> list.take(list.length(divisors) - 1) } @@ -362,7 +362,7 @@ pub fn float_sum(arr: List(Float), weights: option.Option(List(Float))) -> Float /// \sum_{i=1}^n x_i /// \\] /// -/// In the formula, \\(n\\) is the length of the list and \\(x_i \in \mathbb{Z}\\) is +/// In the formula, \\(n\\) is the length of the list and \\(x_i \in \mathbb{Z}\\) is /// the value in the input list indexed by \\(i\\). /// ///
@@ -414,7 +414,7 @@ pub fn int_sum(arr: List(Int)) -> Int { /// In the formula, \\(n\\) is the length of the list and \\(x_i \in \mathbb{R}\\) is /// the value in the input list indexed by \\(i\\), while the \\(w_i \in \mathbb{R}\\) /// are corresponding weights (\\(w_i = 1.0\\;\forall i=1...n\\) by default). -/// +/// ///
/// Example: /// @@ -486,7 +486,7 @@ pub fn float_product( /// \prod_{i=1}^n x_i /// \\] /// -/// In the formula, \\(n\\) is the length of the list and \\(x_i \in \mathbb{Z}\\) is +/// In the formula, \\(n\\) is the length of the list and \\(x_i \in \mathbb{Z}\\) is /// the value in the input list indexed by \\(i\\). /// ///
@@ -536,7 +536,7 @@ pub fn int_product(arr: List(Int)) -> Int { /// \\] /// /// In the formula, \\(v_j\\) is the \\(j\\)'th element in the cumulative sum of \\(n\\) -/// elements. That is, \\(n\\) is the length of the list and \\(x_i \in \mathbb{R}\\) +/// elements. That is, \\(n\\) is the length of the list and \\(x_i \in \mathbb{R}\\) /// is the value in the input list indexed by \\(i\\). The value \\(v_j\\) is thus the /// sum of the \\(1\\) to \\(j\\) first elements in the given list. /// @@ -586,7 +586,7 @@ pub fn float_cumulative_sum(arr: List(Float)) -> List(Float) { /// \\] /// /// In the formula, \\(v_j\\) is the \\(j\\)'th element in the cumulative sum of \\(n\\) -/// elements. That is, \\(n\\) is the length of the list and \\(x_i \in \mathbb{Z}\\) +/// elements. That is, \\(n\\) is the length of the list and \\(x_i \in \mathbb{Z}\\) /// is the value in the input list indexed by \\(i\\). The value \\(v_j\\) is thus the /// sum of the \\(1\\) to \\(j\\) first elements in the given list. /// @@ -635,10 +635,10 @@ pub fn int_cumulative_sum(arr: List(Int)) -> List(Int) { /// v_j = \prod_{i=1}^j x_i \\;\\; \forall j = 1,\dots, n /// \\] /// -/// In the formula, \\(v_j\\) is the \\(j\\)'th element in the cumulative product of -/// \\(n\\) elements. That is, \\(n\\) is the length of the list and -/// \\(x_i \in \mathbb{R}\\) is the value in the input list indexed by \\(i\\). The -/// value \\(v_j\\) is thus the sum of the \\(1\\) to \\(j\\) first elements in the +/// In the formula, \\(v_j\\) is the \\(j\\)'th element in the cumulative product of +/// \\(n\\) elements. That is, \\(n\\) is the length of the list and +/// \\(x_i \in \mathbb{R}\\) is the value in the input list indexed by \\(i\\). The +/// value \\(v_j\\) is thus the sum of the \\(1\\) to \\(j\\) first elements in the /// given list. /// ///
@@ -687,9 +687,9 @@ pub fn float_cumulative_product(arr: List(Float)) -> List(Float) { /// v_j = \prod_{i=1}^j x_i \\;\\; \forall j = 1,\dots, n /// \\] /// -/// In the formula, \\(v_j\\) is the \\(j\\)'th element in the cumulative product of -/// \\(n\\) elements. That is, \\(n\\) is the length of the list and -/// \\(x_i \in \mathbb{Z}\\) is the value in the input list indexed by \\(i\\). The +/// In the formula, \\(v_j\\) is the \\(j\\)'th element in the cumulative product of +/// \\(n\\) elements. That is, \\(n\\) is the length of the list and +/// \\(x_i \in \mathbb{Z}\\) is the value in the input list indexed by \\(i\\). The /// value \\(v_j\\) is thus the product of the \\(1\\) to \\(j\\) first elements in the /// given list. /// diff --git a/src/gleam_community/maths/elementary.gleam b/src/gleam_community/maths/elementary.gleam index 25e6b47..9c9be4a 100644 --- a/src/gleam_community/maths/elementary.gleam +++ b/src/gleam_community/maths/elementary.gleam @@ -20,11 +20,11 @@ //// -//// +//// //// --- -//// +//// //// Elementary: A module containing a comprehensive set of foundational mathematical functions and constants. -//// +//// //// * **Trigonometric and hyperbolic functions** //// * [`acos`](#acos) //// * [`acosh`](#acosh) @@ -53,7 +53,7 @@ //// * [`pi`](#pi) //// * [`tau`](#tau) //// * [`e`](#e) -//// +//// import gleam/int import gleam/option @@ -178,7 +178,7 @@ fn do_acosh(a: Float) -> Float /// \\] /// /// The function takes a number \\(x\\) in its domain \\(\[-1, 1\]\\) as input and returns a numeric -/// value \\(y\\) that lies in the range \\(\[-\frac{\pi}{2}, \frac{\pi}{2}\]\\) (an angle in +/// value \\(y\\) that lies in the range \\(\[-\frac{\pi}{2}, \frac{\pi}{2}\]\\) (an angle in /// radians). If the input value is outside the domain of the function an error is returned. /// ///
@@ -232,8 +232,8 @@ fn do_asin(a: Float) -> Float /// \forall x \in \(-\infty, \infty\), \\; \sinh^{-1}{(x)} = y \in \(-\infty, +\infty\) /// \\] /// -/// The function takes a number \\(x\\) in its domain \\(\(-\infty, +\infty\)\\) as input and -/// returns a numeric value \\(y\\) that lies in the range \\(\(-\infty, +\infty\)\\) (an angle in +/// The function takes a number \\(x\\) in its domain \\(\(-\infty, +\infty\)\\) as input and +/// returns a numeric value \\(y\\) that lies in the range \\(\(-\infty, +\infty\)\\) (an angle in /// radians). /// ///
@@ -274,7 +274,7 @@ fn do_asinh(a: Float) -> Float /// \forall x \in \(-\infty, \infty\), \\; \tan^{-1}{(x)} = y \in \[-\frac{\pi}{2}, \frac{\pi}{2}\] /// \\] /// -/// The function takes a number \\(x\\) in its domain \\(\(-\infty, +\infty\)\\) as input and +/// The function takes a number \\(x\\) in its domain \\(\(-\infty, +\infty\)\\) as input and /// returns a numeric value \\(y\\) that lies in the range \\(\[-\frac{\pi}{2}, \frac{\pi}{2}\]\\) /// (an angle in radians). /// @@ -421,7 +421,7 @@ fn do_atanh(a: Float) -> Float /// \forall x \in \(-\infty, +\infty\), \\; \cos{(x)} = y \in \[-1, 1\] /// \\] /// -/// The function takes a number \\(x\\) in its domain \\(\(-\infty, \infty\)\\) (an angle in +/// The function takes a number \\(x\\) in its domain \\(\(-\infty, \infty\)\\) (an angle in /// radians) as input and returns a numeric value \\(y\\) that lies in the range \\(\[-1, 1\]\\). /// ///
@@ -465,8 +465,8 @@ fn do_cos(a: Float) -> Float /// \forall x \in \(-\infty, \infty\), \\; \cosh{(x)} = y \in \(-\infty, +\infty\) /// \\] /// -/// The function takes a number \\(x\\) in its domain \\(\(-\infty, \infty\)\\) as input (an angle -/// in radians) and returns a numeric value \\(y\\) that lies in the range +/// The function takes a number \\(x\\) in its domain \\(\(-\infty, \infty\)\\) as input (an angle +/// in radians) and returns a numeric value \\(y\\) that lies in the range /// \\(\(-\infty, \infty\)\\). If the input value is too large an overflow error might occur. /// ///
@@ -507,7 +507,7 @@ fn do_cosh(a: Float) -> Float /// \forall x \in \(-\infty, +\infty\), \\; \sin{(x)} = y \in \[-1, 1\] /// \\] /// -/// The function takes a number \\(x\\) in its domain \\(\(-\infty, \infty\)\\) (an angle in +/// The function takes a number \\(x\\) in its domain \\(\(-\infty, \infty\)\\) (an angle in /// radians) as input and returns a numeric value \\(y\\) that lies in the range \\(\[-1, 1\]\\). /// ///
@@ -780,7 +780,7 @@ fn do_natural_logarithm(a: Float) -> Float /// \forall x \in \(0, \infty\) \textnormal{ and } b > 1, \\; \log_{b}{(x)} = y \in \(-\infty, +\infty\) /// \\] /// -/// The function takes a number \\(x\\) in its domain \\(\(0, \infty\)\\) and a base \\(b > 1\\) +/// The function takes a number \\(x\\) in its domain \\(\(0, \infty\)\\) and a base \\(b > 1\\) /// as input and returns a numeric value \\(y\\) that lies in the range \\(\(-\infty, \infty\)\\). /// If the input value is outside the domain of the function an error is returned. /// @@ -849,7 +849,7 @@ pub fn logarithm(x: Float, base: option.Option(Float)) -> Result(Float, String) /// \forall x \in \(0, \infty), \\; \log_{2}{(x)} = y \in \(-\infty, +\infty\) /// \\] /// -/// The function takes a number \\(x\\) in its domain \\(\(0, \infty\)\\) as input and returns a +/// The function takes a number \\(x\\) in its domain \\(\(0, \infty\)\\) as input and returns a /// numeric value \\(y\\) that lies in the range \\(\(-\infty, \infty\)\\). /// If the input value is outside the domain of the function an error is returned. /// @@ -904,7 +904,7 @@ fn do_logarithm_2(a: Float) -> Float /// \forall x \in \(0, \infty), \\; \log_{10}{(x)} = y \in \(-\infty, +\infty\) /// \\] /// -/// The function takes a number \\(x\\) in its domain \\(\(0, \infty\)\\) as input and returns a +/// The function takes a number \\(x\\) in its domain \\(\(0, \infty\)\\) as input and returns a /// numeric value \\(y\\) that lies in the range \\(\(-\infty, \infty\)\\). /// If the input value is outside the domain of the function an error is returned. /// @@ -994,7 +994,7 @@ fn do_logarithm_10(a: Float) -> Float /// /// pub fn power(x: Float, y: Float) -> Result(Float, String) { - let fractional: Bool = do_ceiling(y) -. y >. 0.0 + let fractional = do_ceiling(y) -. y >. 0.0 // In the following check: // 1. If the base (x) is negative and the exponent (y) is fractional // then return an error as it will otherwise be an imaginary number @@ -1057,7 +1057,7 @@ fn do_ceiling(a: Float) -> Float /// pub fn square_root(x: Float) -> Result(Float, String) { // In the following check: - // 1. If x is negative then return an error as it will otherwise be an + // 1. If x is negative then return an error as it will otherwise be an // imaginary number case x <. 0.0 { True -> @@ -1109,7 +1109,7 @@ pub fn square_root(x: Float) -> Result(Float, String) { /// pub fn cube_root(x: Float) -> Result(Float, String) { // In the following check: - // 1. If x is negative then return an error as it will otherwise be an + // 1. If x is negative then return an error as it will otherwise be an // imaginary number case x <. 0.0 { True -> @@ -1164,7 +1164,7 @@ pub fn cube_root(x: Float) -> Result(Float, String) { /// pub fn nth_root(x: Float, n: Int) -> Result(Float, String) { // In the following check: - // 1. If x is negative then return an error as it will otherwise be an + // 1. If x is negative then return an error as it will otherwise be an // imaginary number case x <. 0.0 { True -> diff --git a/src/gleam_community/maths/metrics.gleam b/src/gleam_community/maths/metrics.gleam index f4862eb..7f550c3 100644 --- a/src/gleam_community/maths/metrics.gleam +++ b/src/gleam_community/maths/metrics.gleam @@ -20,18 +20,18 @@ //// -//// +//// //// --- -//// -//// Metrics: A module offering functions for calculating distances and other +//// +//// Metrics: A module offering functions for calculating distances and other //// types of metrics. -//// +//// //// Disclaimer: In this module, the terms "distance" and "metric" are used in //// a broad and practical sense. That is, they are used to denote any difference -//// or discrepancy between two inputs. Consequently, they may not align with their +//// or discrepancy between two inputs. Consequently, they may not align with their //// precise mathematical definitions (in particular, some "distance" functions in //// this module do not satisfy the triangle inequality). -//// +//// //// * **Distance measures** //// * [`norm`](#norm) //// * [`manhattan_distance`](#manhattan_distance) @@ -51,7 +51,7 @@ //// * [`median`](#median) //// * [`variance`](#variance) //// * [`standard_deviation`](#standard_deviation) -//// +//// import gleam/bool import gleam/float @@ -81,8 +81,8 @@ fn validate_lists( "Invalid input argument: The list yarr is empty." |> Error _, _ -> { - let xarr_length: Int = list.length(xarr) - let yarr_length: Int = list.length(yarr) + let xarr_length = list.length(xarr) + let yarr_length = list.length(yarr) case xarr_length == yarr_length, weights { False, _ -> "Invalid input argument: length(xarr) != length(yarr). Valid input is when length(xarr) == length(yarr)." @@ -92,7 +92,7 @@ fn validate_lists( |> Ok } True, option.Some(warr) -> { - let warr_length: Int = list.length(warr) + let warr_length = list.length(warr) case xarr_length == warr_length { True -> { validate_weights(warr) @@ -132,7 +132,7 @@ fn validate_weights(warr: List(Float)) -> Result(Bool, String) { /// \left( \sum_{i=1}^n w_{i} \left|x_{i}\right|^{p} \right)^{\frac{1}{p}} /// \\] /// -/// In the formula, \\(n\\) is the length of the list and \\(x_i\\) is the value in +/// In the formula, \\(n\\) is the length of the list and \\(x_i\\) is the value in /// the input list indexed by \\(i\\), while \\(w_i \in \mathbb{R}_{+}\\) is /// a corresponding positive weight (\\(w_i = 1.0\\;\forall i=1...n\\) by default). /// @@ -147,14 +147,14 @@ fn validate_weights(warr: List(Float)) -> Result(Bool, String) { /// /// pub fn example() { /// let assert Ok(tol) = elementary.power(-10.0, -6.0) -/// +/// /// let assert Ok(result) = /// [1.0, 1.0, 1.0] /// |> metrics.norm(1.0, option.None) /// result /// |> predicates.is_close(3.0, 0.0, tol) /// |> should.be_true() -/// +/// /// let assert Ok(result) = /// [1.0, 1.0, 1.0] /// |> metrics.norm(-1.0, option.None) @@ -180,7 +180,7 @@ pub fn norm( 0.0 |> Ok _, option.None -> { - let aggregate: Float = + let aggregate = arr |> list.fold(0.0, fn(accumulator: Float, element: Float) -> Float { let assert Ok(result) = @@ -193,20 +193,20 @@ pub fn norm( |> Ok } _, option.Some(warr) -> { - let arr_length: Int = list.length(arr) - let warr_length: Int = list.length(warr) + let arr_length = list.length(arr) + let warr_length = list.length(warr) case arr_length == warr_length { True -> { case validate_weights(warr) { Ok(_) -> { - let tuples: List(#(Float, Float)) = list.zip(arr, warr) - let aggregate: Float = + let tuples = list.zip(arr, warr) + let aggregate = tuples |> list.fold( 0.0, fn(accumulator: Float, tuple: #(Float, Float)) -> Float { - let first_element: Float = pair.first(tuple) - let second_element: Float = pair.second(tuple) + let first_element = pair.first(tuple) + let second_element = pair.second(tuple) let assert Ok(result) = elementary.power( piecewise.float_absolute_value(first_element), @@ -239,16 +239,16 @@ pub fn norm( /// /// /// -/// Calculate the (weighted) Manhattan distance between two lists (representing +/// Calculate the (weighted) Manhattan distance between two lists (representing /// vectors): /// /// \\[ /// \sum_{i=1}^n w_{i} \left|x_i - y_i \right| /// \\] /// -/// In the formula, \\(n\\) is the length of the two lists and \\(x_i, y_i\\) are the +/// In the formula, \\(n\\) is the length of the two lists and \\(x_i, y_i\\) are the /// values in the respective input lists indexed by \\(i\\), while the -/// \\(w_i \in \mathbb{R}_{+}\\) are corresponding positive weights +/// \\(w_i \in \mathbb{R}_{+}\\) are corresponding positive weights /// (\\(w_i = 1.0\\;\forall i=1...n\\) by default). /// ///
@@ -266,11 +266,11 @@ pub fn norm( /// // Empty lists returns an error /// metrics.manhattan_distance([], [], option.None) /// |> should.be_error() -/// +/// /// // Differing lengths returns error /// metrics.manhattan_distance([], [1.0], option.None) /// |> should.be_error() -/// +/// /// let assert Ok(result) = /// metrics.manhattan_distance([0.0, 0.0], [1.0, 2.0], option.None) /// result @@ -306,12 +306,12 @@ pub fn manhattan_distance( /// \left( \sum_{i=1}^n w_{i} \left|x_i - y_i \right|^{p} \right)^{\frac{1}{p}} /// \\] /// -/// In the formula, \\(p >= 1\\) is the order, \\(n\\) is the length of the two lists +/// In the formula, \\(p >= 1\\) is the order, \\(n\\) is the length of the two lists /// and \\(x_i, y_i\\) are the values in the respective input lists indexed by \\(i\\). -/// The \\(w_i \in \mathbb{R}_{+}\\) are corresponding positive weights +/// The \\(w_i \in \mathbb{R}_{+}\\) are corresponding positive weights /// (\\(w_i = 1.0\\;\forall i=1...n\\) by default). /// -/// The Minkowski distance is a generalization of both the Euclidean distance +/// The Minkowski distance is a generalization of both the Euclidean distance /// (\\(p=2\\)) and the Manhattan distance (\\(p = 1\\)). /// ///
@@ -325,11 +325,11 @@ pub fn manhattan_distance( /// /// pub fn example() { /// let assert Ok(tol) = elementary.power(-10.0, -6.0) -/// +/// /// // Empty lists returns an error /// metrics.minkowski_distance([], [], 1.0, option.None) /// |> should.be_error() -/// +/// /// // Differing lengths returns error /// metrics.minkowski_distance([], [1.0], 1.0, option.None) /// |> should.be_error() @@ -337,7 +337,7 @@ pub fn manhattan_distance( /// // Test order < 1 /// metrics.minkowski_distance([0.0, 0.0], [0.0, 0.0], -1.0, option.None) /// |> should.be_error() -/// +/// /// let assert Ok(result) = /// metrics.minkowski_distance([0.0, 0.0], [1.0, 2.0], 1.0, option.None) /// result @@ -368,7 +368,7 @@ pub fn minkowski_distance( "Invalid input argument: p < 1. Valid input is p >= 1." |> Error False -> { - let differences: List(Float) = + let differences = list.zip(xarr, yarr) |> list.map(fn(tuple: #(Float, Float)) -> Float { pair.first(tuple) -. pair.second(tuple) @@ -389,7 +389,7 @@ pub fn minkowski_distance( /// /// /// -/// Calculate the (weighted) Euclidean distance between two lists (representing +/// Calculate the (weighted) Euclidean distance between two lists (representing /// vectors): /// /// \\[ @@ -398,7 +398,7 @@ pub fn minkowski_distance( /// /// In the formula, \\(n\\) is the length of the two lists and \\(x_i, y_i\\) are the /// values in the respective input lists indexed by \\(i\\), while the -/// \\(w_i \in \mathbb{R}_{+}\\) are corresponding positive weights +/// \\(w_i \in \mathbb{R}_{+}\\) are corresponding positive weights /// (\\(w_i = 1.0\\;\forall i=1...n\\) by default). /// ///
@@ -412,15 +412,15 @@ pub fn minkowski_distance( /// /// pub fn example() { /// let assert Ok(tol) = elementary.power(-10.0, -6.0) -/// +/// /// // Empty lists returns an error /// metrics.euclidean_distance([], [], option.None) /// |> should.be_error() -/// +/// /// // Differing lengths returns an error /// metrics.euclidean_distance([], [1.0], option.None) /// |> should.be_error() -/// +/// /// let assert Ok(result) = /// metrics.euclidean_distance([0.0, 0.0], [1.0, 2.0], option.None) /// result @@ -455,7 +455,7 @@ pub fn euclidean_distance( /// \text{max}_{i=1}^n \left|x_i - y_i \right| /// \\] /// -/// In the formula, \\(n\\) is the length of the two lists and \\(x_i, y_i\\) are the +/// In the formula, \\(n\\) is the length of the two lists and \\(x_i, y_i\\) are the /// values in the respective input lists indexed by \\(i\\). /// ///
@@ -470,11 +470,11 @@ pub fn euclidean_distance( /// // Empty lists returns an error /// metrics.chebyshev_distance([], []) /// |> should.be_error() -/// +/// /// // Differing lengths returns error /// metrics.chebyshev_distance([], [1.0]) /// |> should.be_error() -/// +/// /// metrics.chebyshev_distance([-5.0, -10.0, -3.0], [-1.0, -12.0, -3.0]) /// |> should.equal(Ok(4.0)) /// } @@ -632,14 +632,14 @@ fn do_median( /// /// /// Calculate the sample variance of the elements in a list: -/// +/// /// \\[ /// s^{2} = \frac{1}{n - d} \sum_{i=1}^{n}(x_i - \bar{x}) /// \\] /// -/// In the formula, \\(n\\) is the sample size (the length of the list) and \\(x_i\\) -/// is the sample point in the input list indexed by \\(i\\). -/// Furthermore, \\(\bar{x}\\) is the sample mean and \\(d\\) is the "Delta +/// In the formula, \\(n\\) is the sample size (the length of the list) and \\(x_i\\) +/// is the sample point in the input list indexed by \\(i\\). +/// Furthermore, \\(\bar{x}\\) is the sample mean and \\(d\\) is the "Delta /// Degrees of Freedom", and is by default set to \\(d = 0\\), which gives a biased /// estimate of the sample variance. Setting \\(d = 1\\) gives an unbiased estimate. /// @@ -651,7 +651,7 @@ fn do_median( /// /// pub fn example () { /// // Degrees of freedom -/// let ddof: Int = 1 +/// let ddof = 1 /// /// // An empty list returns an error /// [] @@ -713,11 +713,11 @@ pub fn variance(arr: List(Float), ddof: Int) -> Result(Float, String) { /// s = \left(\frac{1}{n - d} \sum_{i=1}^{n}(x_i - \bar{x})\right)^{\frac{1}{2}} /// \\] /// -/// In the formula, \\(n\\) is the sample size (the length of the list) and \\(x_i\\) -/// is the sample point in the input list indexed by \\(i\\). -/// Furthermore, \\(\bar{x}\\) is the sample mean and \\(d\\) is the "Delta +/// In the formula, \\(n\\) is the sample size (the length of the list) and \\(x_i\\) +/// is the sample point in the input list indexed by \\(i\\). +/// Furthermore, \\(\bar{x}\\) is the sample mean and \\(d\\) is the "Delta /// Degrees of Freedom", and is by default set to \\(d = 0\\), which gives a biased -/// estimate of the sample standard deviation. Setting \\(d = 1\\) gives an unbiased +/// estimate of the sample standard deviation. Setting \\(d = 1\\) gives an unbiased /// estimate. /// ///
@@ -728,7 +728,7 @@ pub fn variance(arr: List(Float), ddof: Int) -> Result(Float, String) { /// /// pub fn example () { /// // Degrees of freedom -/// let ddof: Int = 1 +/// let ddof = 1 /// /// // An empty list returns an error /// [] @@ -776,24 +776,24 @@ pub fn standard_deviation(arr: List(Float), ddof: Int) -> Result(Float, String) /// /// /// -/// The Jaccard index measures similarity between two sets of elements. +/// The Jaccard index measures similarity between two sets of elements. /// Mathematically, the Jaccard index is defined as: -/// +/// /// \\[ /// \frac{|X \cap Y|}{|X \cup Y|} \\; \in \\; \left[0, 1\right] /// \\] -/// +/// /// where: /// /// - \\(X\\) and \\(Y\\) are two sets being compared, /// - \\(|X \cap Y|\\) represents the size of the intersection of the two sets /// - \\(|X \cup Y|\\) denotes the size of the union of the two sets -/// -/// The value of the Jaccard index ranges from 0 to 1, where 0 indicates that the -/// two sets share no elements and 1 indicates that the sets are identical. The +/// +/// The value of the Jaccard index ranges from 0 to 1, where 0 indicates that the +/// two sets share no elements and 1 indicates that the sets are identical. The /// Jaccard index is a special case of the [Tversky index](#tversky_index) (with /// \\(\alpha=\beta=1\\)). -/// +/// ///
/// Example: /// @@ -802,8 +802,8 @@ pub fn standard_deviation(arr: List(Float), ddof: Int) -> Result(Float, String) /// import gleam/set /// /// pub fn example () { -/// let xset: set.Set(String) = set.from_list(["cat", "dog", "hippo", "monkey"]) -/// let yset: set.Set(String) = +/// let xset = set.from_list(["cat", "dog", "hippo", "monkey"]) +/// let yset = /// set.from_list(["monkey", "rhino", "ostrich", "salmon"]) /// metrics.jaccard_index(xset, yset) /// |> should.equal(1.0 /. 7.0) @@ -827,25 +827,25 @@ pub fn jaccard_index(xset: set.Set(a), yset: set.Set(a)) -> Float { /// /// /// -/// The Sørensen-Dice coefficient measures the similarity between two sets of +/// The Sørensen-Dice coefficient measures the similarity between two sets of /// elements. Mathematically, the coefficient is defined as: -/// +/// /// \\[ /// \frac{2 |X \cap Y|}{|X| + |Y|} \\; \in \\; \left[0, 1\right] /// \\] -/// +/// /// where: /// - \\(X\\) and \\(Y\\) are two sets being compared -/// - \\(|X \cap Y|\\) is the size of the intersection of the two sets (i.e., the +/// - \\(|X \cap Y|\\) is the size of the intersection of the two sets (i.e., the /// number of elements common to both sets) /// - \\(|X|\\) and \\(|Y|\\) are the sizes of the sets \\(X\\) and \\(Y\\), respectively -/// +/// /// The coefficient ranges from 0 to 1, where 0 indicates no similarity (the sets /// share no elements) and 1 indicates perfect similarity (the sets are identical). -/// The higher the coefficient, the greater the similarity between the two sets. -/// The Sørensen-Dice coefficient is a special case of the +/// The higher the coefficient, the greater the similarity between the two sets. +/// The Sørensen-Dice coefficient is a special case of the /// [Tversky index](#tversky_index) (with \\(\alpha=\beta=0.5\\)). -/// +/// ///
/// Example: /// @@ -854,8 +854,8 @@ pub fn jaccard_index(xset: set.Set(a), yset: set.Set(a)) -> Float { /// import gleam/set /// /// pub fn example () { -/// let xset: set.Set(String) = set.from_list(["cat", "dog", "hippo", "monkey"]) -/// let yset: set.Set(String) = +/// let xset = set.from_list(["cat", "dog", "hippo", "monkey"]) +/// let yset = /// set.from_list(["monkey", "rhino", "ostrich", "salmon", "spider"]) /// metrics.sorensen_dice_coefficient(xset, yset) /// |> should.equal(2.0 *. 1.0 /. { 4.0 +. 5.0 }) @@ -878,31 +878,31 @@ pub fn sorensen_dice_coefficient(xset: set.Set(a), yset: set.Set(a)) -> Float { /// Spot a typo? Open an issue! /// /// -/// -/// The Tversky index is a generalization of the Jaccard index and Sørensen-Dice -/// coefficient, which adds flexibility through two parameters, \\(\alpha\\) and -/// \\(\beta\\), allowing for asymmetric similarity measures between sets. The +/// +/// The Tversky index is a generalization of the Jaccard index and Sørensen-Dice +/// coefficient, which adds flexibility through two parameters, \\(\alpha\\) and +/// \\(\beta\\), allowing for asymmetric similarity measures between sets. The /// Tversky index is defined as: -/// +/// /// \\[ /// \frac{|X \cap Y|}{|X \cap Y| + \alpha|X - Y| + \beta|Y - X|} /// \\] -/// +/// /// where: -/// +/// /// - \\(X\\) and \\(Y\\) are the sets being compared -/// - \\(|X - Y|\\) and \\(|Y - X|\\) are the sizes of the relative complements of +/// - \\(|X - Y|\\) and \\(|Y - X|\\) are the sizes of the relative complements of /// \\(Y\\) in \\(X\\) and \\(X\\) in \\(Y\\), respectively, /// - \\(\alpha\\) and \\(\beta\\) are parameters that weigh the relative importance /// of the elements unique to \\(X\\) and \\(Y\\) -/// +/// /// The Tversky index reduces to the Jaccard index when \\(\alpha = \beta = 1\\) and /// to the Sørensen-Dice coefficient when \\(\alpha = \beta = 0.5\\). In general, the /// Tversky index can take on any non-negative value, including 0. The index equals -/// 0 when there is no intersection between the two sets, indicating no similarity. -/// However, unlike similarity measures bounded strictly between 0 and 1, the +/// 0 when there is no intersection between the two sets, indicating no similarity. +/// However, unlike similarity measures bounded strictly between 0 and 1, the /// Tversky index does not have a strict upper limit of 1 when \\(\alpha \neq \beta\\). -/// +/// ///
/// Example: /// @@ -911,8 +911,8 @@ pub fn sorensen_dice_coefficient(xset: set.Set(a), yset: set.Set(a)) -> Float { /// import gleam/set /// /// pub fn example () { -/// let yset: set.Set(String) = set.from_list(["cat", "dog", "hippo", "monkey"]) -/// let xset: set.Set(String) = +/// let yset = set.from_list(["cat", "dog", "hippo", "monkey"]) +/// let xset = /// set.from_list(["monkey", "rhino", "ostrich", "salmon"]) /// // Test Jaccard index (alpha = beta = 1) /// metrics.tversky_index(xset, yset, 1.0, 1.0) @@ -934,15 +934,15 @@ pub fn tversky_index( ) -> Result(Float, String) { case alpha >=. 0.0, beta >=. 0.0 { True, True -> { - let intersection: Float = + let intersection = set.intersection(xset, yset) |> set.size() |> conversion.int_to_float() - let difference1: Float = + let difference1 = set.difference(xset, yset) |> set.size() |> conversion.int_to_float() - let difference2: Float = + let difference2 = set.difference(yset, xset) |> set.size() |> conversion.int_to_float() @@ -970,10 +970,10 @@ pub fn tversky_index( /// Spot a typo? Open an issue! /// /// -/// +/// /// The Overlap coefficient, also known as the Szymkiewicz–Simpson coefficient, is -/// a measure of similarity between two sets that focuses on the size of the -/// intersection relative to the smaller of the two sets. It is defined +/// a measure of similarity between two sets that focuses on the size of the +/// intersection relative to the smaller of the two sets. It is defined /// mathematically as: /// /// \\[ @@ -986,10 +986,10 @@ pub fn tversky_index( /// - \\(|X \cap Y|\\) is the size of the intersection of the sets /// - \\(\min(|X|, |Y|)\\) is the size of the smaller set among \\(X\\) and \\(Y\\) /// -/// The coefficient ranges from 0 to 1, where 0 indicates no overlap and 1 -/// indicates that the smaller set is a suyset of the larger set. This +/// The coefficient ranges from 0 to 1, where 0 indicates no overlap and 1 +/// indicates that the smaller set is a suyset of the larger set. This /// measure is especially useful in situations where the similarity in terms -/// of the proportion of overlap is more relevant than the difference in sizes +/// of the proportion of overlap is more relevant than the difference in sizes /// between the two sets. /// ///
@@ -1000,9 +1000,9 @@ pub fn tversky_index( /// import gleam/set /// /// pub fn example () { -/// let set_a: set.Set(String) = +/// let set_a = /// set.from_list(["horse", "dog", "hippo", "monkey", "bird"]) -/// let set_b: set.Set(String) = +/// let set_b = /// set.from_list(["monkey", "bird", "ostrich", "salmon"]) /// metrics.overlap_coefficient(set_a, set_b) /// |> should.equal(2.0 /. 4.0) @@ -1016,11 +1016,11 @@ pub fn tversky_index( /// /// pub fn overlap_coefficient(xset: set.Set(a), yset: set.Set(a)) -> Float { - let intersection: Float = + let intersection = set.intersection(xset, yset) |> set.size() |> conversion.int_to_float() - let minsize: Float = + let minsize = piecewise.minimum(set.size(xset), set.size(yset), int.compare) |> conversion.int_to_float() intersection /. minsize @@ -1031,27 +1031,27 @@ pub fn overlap_coefficient(xset: set.Set(a), yset: set.Set(a)) -> Float { /// Spot a typo? Open an issue! /// /// -/// +/// /// Calculate the (weighted) cosine similarity between two lists (representing /// vectors): /// /// \\[ /// \frac{\sum_{i=1}^n w_{i} \cdot x_i \cdot y_i} /// {\left(\sum_{i=1}^n w_{i} \cdot x_i^2\right)^{\frac{1}{2}} -/// \cdot -/// \left(\sum_{i=1}^n w_{i} \cdot y_i^2\right)^{\frac{1}{2}}} +/// \cdot +/// \left(\sum_{i=1}^n w_{i} \cdot y_i^2\right)^{\frac{1}{2}}} /// \\; \in \\; \left[-1, 1\right] /// \\] /// /// In the formula, \\(n\\) is the length of the two lists and \\(x_i\\), \\(y_i\\) are /// the values in the respective input lists indexed by \\(i\\), while the -/// \\(w_i \in \mathbb{R}_{+}\\) are corresponding positive weights -/// (\\(w_i = 1.0\\;\forall i=1...n\\) by default). -/// -/// The cosine similarity provides a value between -1 and 1, where 1 means the -/// vectors are in the same direction, -1 means they are in exactly opposite -/// directions, and 0 indicates orthogonality. -/// +/// \\(w_i \in \mathbb{R}_{+}\\) are corresponding positive weights +/// (\\(w_i = 1.0\\;\forall i=1...n\\) by default). +/// +/// The cosine similarity provides a value between -1 and 1, where 1 means the +/// vectors are in the same direction, -1 means they are in exactly opposite +/// directions, and 0 indicates orthogonality. +/// ///
/// Example: /// @@ -1063,11 +1063,11 @@ pub fn overlap_coefficient(xset: set.Set(a), yset: set.Set(a)) -> Float { /// // Two orthogonal vectors /// metrics.cosine_similarity([-1.0, 1.0, 0.0], [1.0, 1.0, -1.0], option.None) /// |> should.equal(Ok(0.0)) -/// +/// /// // Two identical (parallel) vectors /// metrics.cosine_similarity([1.0, 2.0, 3.0], [1.0, 2.0, 3.0], option.None) /// |> should.equal(Ok(1.0)) -/// +/// /// // Two parallel, but oppositely oriented vectors /// metrics.cosine_similarity([-1.0, -2.0, -3.0], [1.0, 2.0, 3.0], option.None) /// |> should.equal(Ok(-1.0)) @@ -1090,9 +1090,9 @@ pub fn cosine_similarity( msg |> Error Ok(_) -> { - let zipped_arr: List(#(Float, Float)) = list.zip(xarr, yarr) + let zipped_arr = list.zip(xarr, yarr) - let numerator_elements: List(Float) = + let numerator_elements = zipped_arr |> list.map(fn(tuple: #(Float, Float)) -> Float { pair.first(tuple) *. pair.second(tuple) @@ -1100,26 +1100,26 @@ pub fn cosine_similarity( case weights { option.None -> { - let numerator: Float = + let numerator = numerator_elements |> arithmetics.float_sum(option.None) let assert Ok(xarr_norm) = norm(xarr, 2.0, option.None) let assert Ok(yarr_norm) = norm(yarr, 2.0, option.None) - let denominator: Float = { + let denominator = { xarr_norm *. yarr_norm } numerator /. denominator |> Ok } _ -> { - let numerator: Float = + let numerator = numerator_elements |> arithmetics.float_sum(weights) let assert Ok(xarr_norm) = norm(xarr, 2.0, weights) let assert Ok(yarr_norm) = norm(yarr, 2.0, weights) - let denominator: Float = { + let denominator = { xarr_norm *. yarr_norm } numerator /. denominator @@ -1135,7 +1135,7 @@ pub fn cosine_similarity( /// Spot a typo? Open an issue! /// /// -/// +/// /// Calculate the (weighted) Canberra distance between two lists: /// /// \\[ @@ -1143,10 +1143,10 @@ pub fn cosine_similarity( /// {\left| x_i \right| + \left| y_i \right|} /// \\] /// -/// In the formula, \\(n\\) is the length of the two lists, and \\(x_i, y_i\\) are the -/// values in the respective input lists indexed by \\(i\\), while the -/// \\(w_i \in \mathbb{R}_{+}\\) are corresponding positive weights -/// (\\(w_i = 1.0\\;\forall i=1...n\\) by default). +/// In the formula, \\(n\\) is the length of the two lists, and \\(x_i, y_i\\) are the +/// values in the respective input lists indexed by \\(i\\), while the +/// \\(w_i \in \mathbb{R}_{+}\\) are corresponding positive weights +/// (\\(w_i = 1.0\\;\forall i=1...n\\) by default). /// ///
/// Example: @@ -1159,15 +1159,15 @@ pub fn cosine_similarity( /// // Empty lists returns an error /// metrics.canberra_distance([], [], option.None) /// |> should.be_error() -/// +/// /// // Different sized lists returns an error /// metrics.canberra_distance([1.0, 2.0], [1.0, 2.0, 3.0, 4.0], option.None) /// |> should.be_error() -/// +/// /// // Valid inputs /// metrics.canberra_distance([1.0, 2.0], [-2.0, -1.0], option.None) /// |> should.equal(Ok(2.0)) -/// +/// /// metrics.canberra_distance([1.0, 0.0], [0.0, 2.0], option.Some([1.0, 0.5])) /// } ///
@@ -1188,7 +1188,7 @@ pub fn canberra_distance( msg |> Error Ok(_) -> { - let arr: List(Float) = + let arr = list.zip(xarr, yarr) |> list.map(canberra_distance_helper) @@ -1209,9 +1209,9 @@ pub fn canberra_distance( } fn canberra_distance_helper(tuple: #(Float, Float)) -> Float { - let numerator: Float = + let numerator = piecewise.float_absolute_value({ pair.first(tuple) -. pair.second(tuple) }) - let denominator: Float = { + let denominator = { piecewise.float_absolute_value(pair.first(tuple)) +. piecewise.float_absolute_value(pair.second(tuple)) } @@ -1223,7 +1223,7 @@ fn canberra_distance_helper(tuple: #(Float, Float)) -> Float { /// Spot a typo? Open an issue! /// /// -/// +/// /// Calculate the (weighted) Bray-Curtis distance between two lists: /// /// \\[ @@ -1231,11 +1231,11 @@ fn canberra_distance_helper(tuple: #(Float, Float)) -> Float { /// {\sum_{i=1}^n w_{i}\left| x_i + y_i \right|} /// \\] /// -/// In the formula, \\(n\\) is the length of the two lists, and \\(x_i, y_i\\) are the values -/// in the respective input lists indexed by \\(i\\), while the -/// \\(w_i \in \mathbb{R}_{+}\\) are corresponding positive weights +/// In the formula, \\(n\\) is the length of the two lists, and \\(x_i, y_i\\) are the values +/// in the respective input lists indexed by \\(i\\), while the +/// \\(w_i \in \mathbb{R}_{+}\\) are corresponding positive weights /// (\\(w_i = 1.0\\;\forall i=1...n\\) by default). -/// +/// /// The Bray-Curtis distance is in the range \\([0, 1]\\) if all entries \\(x_i, y_i\\) are /// positive. /// @@ -1250,15 +1250,15 @@ fn canberra_distance_helper(tuple: #(Float, Float)) -> Float { /// // Empty lists returns an error /// metrics.braycurtis_distance([], [], option.None) /// |> should.be_error() -/// +/// /// // Different sized lists returns an error /// metrics.braycurtis_distance([1.0, 2.0], [1.0, 2.0, 3.0, 4.0], option.None) /// |> should.be_error() -/// +/// /// // Valid inputs /// metrics.braycurtis_distance([1.0, 0.0], [0.0, 2.0], option.None) /// |> should.equal(Ok(1.0)) -/// +/// /// metrics.braycurtis_distance([1.0, 2.0], [3.0, 4.0], option.Some([0.5, 1.0])) /// |> should.equal(Ok(0.375)) /// } @@ -1281,15 +1281,15 @@ pub fn braycurtis_distance( msg |> Error Ok(_) -> { - let zipped_arr: List(#(Float, Float)) = list.zip(xarr, yarr) - let numerator_elements: List(Float) = + let zipped_arr = list.zip(xarr, yarr) + let numerator_elements = zipped_arr |> list.map(fn(tuple: #(Float, Float)) -> Float { piecewise.float_absolute_value({ pair.first(tuple) -. pair.second(tuple) }) }) - let denominator_elements: List(Float) = + let denominator_elements = zipped_arr |> list.map(fn(tuple: #(Float, Float)) -> Float { piecewise.float_absolute_value({ diff --git a/src/gleam_community/maths/piecewise.gleam b/src/gleam_community/maths/piecewise.gleam index 36a18dc..d7e8a3c 100644 --- a/src/gleam_community/maths/piecewise.gleam +++ b/src/gleam_community/maths/piecewise.gleam @@ -69,7 +69,7 @@ import gleam_community/maths/elementary /// The ceiling function rounds a given input value \\(x \in \mathbb{R}\\) to the nearest integer /// value (at the specified digit) that is larger than or equal to the input \\(x\\). /// -/// Note: The ceiling function is used as an alias for the rounding function [`round`](#round) +/// Note: The ceiling function is used as an alias for the rounding function [`round`](#round) /// with rounding mode `RoundUp`. /// ///
@@ -124,10 +124,10 @@ pub fn ceiling(x: Float, digits: option.Option(Int)) -> Float { /// /// /// -/// The floor function rounds input \\(x \in \mathbb{R}\\) to the nearest integer value (at the +/// The floor function rounds input \\(x \in \mathbb{R}\\) to the nearest integer value (at the /// specified digit) that is less than or equal to the input \\(x\\). /// -/// Note: The floor function is used as an alias for the rounding function [`round`](#round) +/// Note: The floor function is used as an alias for the rounding function [`round`](#round) /// with rounding mode `RoundDown`. /// ///
@@ -139,7 +139,7 @@ pub fn ceiling(x: Float, digits: option.Option(Int)) -> Float { /// - \\(12.06\\) for 2 digits after the decimal point (`digits = 2`) /// - \\(12.065\\) for 3 digits after the decimal point (`digits = 3`) /// -/// It is also possible to specify a negative number of digits. In that case, the negative +/// It is also possible to specify a negative number of digits. In that case, the negative /// number refers to the digits before the decimal point. /// - \\(10.0\\) for 1 digit before the decimal point (`digits = -1`) /// - \\(0.0\\) for 2 digits before the decimal point (`digits = -2`) @@ -182,11 +182,11 @@ pub fn floor(x: Float, digits: option.Option(Int)) -> Float { /// /// /// -/// The truncate function rounds a given input \\(x \in \mathbb{R}\\) to the nearest integer -/// value (at the specified digit) that is less than or equal to the absolute value of the +/// The truncate function rounds a given input \\(x \in \mathbb{R}\\) to the nearest integer +/// value (at the specified digit) that is less than or equal to the absolute value of the /// input \\(x\\). /// -/// Note: The truncate function is used as an alias for the rounding function [`round`](#round) +/// Note: The truncate function is used as an alias for the rounding function [`round`](#round) /// with rounding mode `RoundToZero`. /// ///
@@ -198,7 +198,7 @@ pub fn floor(x: Float, digits: option.Option(Int)) -> Float { /// - \\(12.06\\) for 2 digits after the decimal point (`digits = 2`) /// - \\(12.065\\) for 3 digits after the decimal point (`digits = 3`) /// -/// It is also possible to specify a negative number of digits. In that case, the negative +/// It is also possible to specify a negative number of digits. In that case, the negative /// number refers to the digits before the decimal point. /// - \\(10.0\\) for 1 digit before the decimal point (`digits = -1`) /// - \\(0.0\\) for 2 digits before the decimal point (`digits = -2`) @@ -241,18 +241,18 @@ pub fn truncate(x: Float, digits: option.Option(Int)) -> Float { /// /// /// -/// The function rounds a float to a specific number of digits (after the decimal place or before +/// The function rounds a float to a specific number of digits (after the decimal place or before /// if negative) using a specified rounding mode. /// /// Valid rounding modes include: -/// - `RoundNearest` (default): The input \\(x\\) is rounded to the nearest integer value (at the -/// specified digit) with ties (fractional values of 0.5) being rounded to the nearest even +/// - `RoundNearest` (default): The input \\(x\\) is rounded to the nearest integer value (at the +/// specified digit) with ties (fractional values of 0.5) being rounded to the nearest even /// integer. /// - `RoundTiesAway`: The input \\(x\\) is rounded to the nearest integer value (at the -/// specified digit) with ties (fractional values of 0.5) being rounded away from zero (C/C++ +/// specified digit) with ties (fractional values of 0.5) being rounded away from zero (C/C++ /// rounding behavior). -/// - `RoundTiesUp`: The input \\(x\\) is rounded to the nearest integer value (at the specified -/// digit) with ties (fractional values of 0.5) being rounded towards \\(+\infty\\) +/// - `RoundTiesUp`: The input \\(x\\) is rounded to the nearest integer value (at the specified +/// digit) with ties (fractional values of 0.5) being rounded towards \\(+\infty\\) /// (Java/JavaScript rounding behaviour). /// - `RoundToZero`: The input \\(x\\) is rounded to the nearest integer value (at the specified /// digit) that is less than or equal to the absolute value of the input \\(x\\). An alias for @@ -260,8 +260,8 @@ pub fn truncate(x: Float, digits: option.Option(Int)) -> Float { /// - `RoundDown`: The input \\(x\\) is rounded to the nearest integer value (at the specified /// digit) that is less than or equal to the input \\(x\\). An alias for this rounding mode is /// [`floor`](#floor). -/// - `RoundUp`: The input \\(x\\) is rounded to the nearest integer value (at the specified -/// digit) that is larger than or equal to the input \\(x\\). An alias for this rounding mode +/// - `RoundUp`: The input \\(x\\) is rounded to the nearest integer value (at the specified +/// digit) that is larger than or equal to the input \\(x\\). An alias for this rounding mode /// is [`ceiling`](#ceiling). /// ///
@@ -273,7 +273,7 @@ pub fn truncate(x: Float, digits: option.Option(Int)) -> Float { /// - \\(12.07\\) for 2 digits after the decimal point (`digits = 2`) /// - \\(12.065\\) for 3 digits after the decimal point (`digits = 3`) /// -/// It is also possible to specify a negative number of digits. In that case, the negative +/// It is also possible to specify a negative number of digits. In that case, the negative /// number refers to the digits before the decimal point. /// - \\(10.0\\) for 1 digit before the decimal point (`digits = -1`) /// - \\(0.0\\) for 2 digits before the decimal point (`digits = -2`) @@ -285,7 +285,7 @@ pub fn truncate(x: Float, digits: option.Option(Int)) -> Float { /// - \\(12.07\\) for 2 digits after the decimal point (`digits = 2`) /// - \\(12.065\\) for 3 digits after the decimal point (`digits = 3`) /// -/// It is also possible to specify a negative number of digits. In that case, the negative +/// It is also possible to specify a negative number of digits. In that case, the negative /// number refers to the digits before the decimal point. /// - \\(10.0\\) for 1 digit before the decimal point (`digits = -1`) /// - \\(0.0\\) for 2 digits before the decimal point (`digits = -2`) @@ -309,7 +309,7 @@ pub fn truncate(x: Float, digits: option.Option(Int)) -> Float { /// - \\(12.06\\) for 2 digits after the decimal point (`digits = 2`) /// - \\(12.065\\) for 3 digits after the decimal point (`digits = 3`) /// -/// It is also possible to specify a negative number of digits. In that case, the negative +/// It is also possible to specify a negative number of digits. In that case, the negative /// number refers to the digits before the decimal point. /// - \\(10.0\\) for 1 digit before the decimal point (`digits = -1`) /// - \\(0.0\\) for 2 digits before the decimal point (`digits = -2`) @@ -321,7 +321,7 @@ pub fn truncate(x: Float, digits: option.Option(Int)) -> Float { /// - \\(12.06\\) for 2 digits after the decimal point (`digits = 2`) /// - \\(12.065\\) for 3 digits after the decimal point (`digits = 3`) /// -/// It is also possible to specify a negative number of digits. In that case, the negative +/// It is also possible to specify a negative number of digits. In that case, the negative /// number refers to the digits before the decimal point. /// - \\(10.0\\) for 1 digit before the decimal point (`digits = -1`) /// - \\(0.0\\) for 2 digits before the decimal point (`digits = -2`) @@ -424,9 +424,9 @@ fn do_round(p: Float, x: Float, mode: option.Option(RoundingMode)) -> Float { } fn round_to_nearest(p: Float, x: Float) -> Float { - let xabs: Float = float_absolute_value(x) *. p - let xabs_truncated: Float = truncate_float(xabs) - let remainder: Float = xabs -. xabs_truncated + let xabs = float_absolute_value(x) *. p + let xabs_truncated = truncate_float(xabs) + let remainder = xabs -. xabs_truncated case remainder { _ if remainder >. 0.5 -> float_sign(x) *. truncate_float(xabs +. 1.0) /. p _ if remainder == 0.5 -> { @@ -441,8 +441,8 @@ fn round_to_nearest(p: Float, x: Float) -> Float { } fn round_ties_away(p: Float, x: Float) -> Float { - let xabs: Float = float_absolute_value(x) *. p - let remainder: Float = xabs -. truncate_float(xabs) + let xabs = float_absolute_value(x) *. p + let remainder = xabs -. truncate_float(xabs) case remainder { _ if remainder >=. 0.5 -> float_sign(x) *. truncate_float(xabs +. 1.0) /. p _ -> float_sign(x) *. truncate_float(xabs) /. p @@ -450,9 +450,9 @@ fn round_ties_away(p: Float, x: Float) -> Float { } fn round_ties_up(p: Float, x: Float) -> Float { - let xabs: Float = float_absolute_value(x) *. p - let xabs_truncated: Float = truncate_float(xabs) - let remainder: Float = xabs -. xabs_truncated + let xabs = float_absolute_value(x) *. p + let xabs_truncated = truncate_float(xabs) + let remainder = xabs -. xabs_truncated case remainder { _ if remainder >=. 0.5 && x >=. 0.0 -> float_sign(x) *. truncate_float(xabs +. 1.0) /. p @@ -500,7 +500,7 @@ fn do_ceiling(a: Float) -> Float /// The absolute value: /// /// \\[ -/// \forall x \in \mathbb{R}, \\; |x| \in \mathbb{R}_{+}. +/// \forall x \in \mathbb{R}, \\; |x| \in \mathbb{R}_{+}. /// \\] /// /// The function takes an input \\(x\\) and returns a positive float value. @@ -529,7 +529,7 @@ pub fn float_absolute_value(x: Float) -> Float { /// The absolute value: /// /// \\[ -/// \forall x \in \mathbb{Z}, \\; |x| \in \mathbb{Z}_{+}. +/// \forall x \in \mathbb{Z}, \\; |x| \in \mathbb{Z}_{+}. /// \\] /// /// The function takes an input \\(x\\) and returns a positive integer value. @@ -709,7 +709,7 @@ fn do_int_sign(a: Int) -> Int /// /// /// -/// The function takes two arguments \\(x, y \in \mathbb{R}\\) and returns \\(x\\) +/// The function takes two arguments \\(x, y \in \mathbb{R}\\) and returns \\(x\\) /// such that it has the same sign as \\(y\\). /// ///
@@ -735,7 +735,7 @@ pub fn float_copy_sign(x: Float, y: Float) -> Float { /// ///
/// -/// The function takes two arguments \\(x, y \in \mathbb{Z}\\) and returns \\(x\\) +/// The function takes two arguments \\(x, y \in \mathbb{Z}\\) and returns \\(x\\) /// such that it has the same sign as \\(y\\). /// ///
@@ -1211,8 +1211,8 @@ pub fn extrema( [x, ..rest] -> Ok( list.fold(rest, #(x, x), fn(acc: #(a, a), element: a) { - let first: a = pair.first(acc) - let second: a = pair.second(acc) + let first = pair.first(acc) + let second = pair.second(acc) case compare(element, first), compare(second, element) { order.Lt, order.Lt -> #(element, element) order.Lt, _ -> #(element, second) diff --git a/src/gleam_community/maths/predicates.gleam b/src/gleam_community/maths/predicates.gleam index 9cdd74c..eca553e 100644 --- a/src/gleam_community/maths/predicates.gleam +++ b/src/gleam_community/maths/predicates.gleam @@ -20,12 +20,12 @@ //// -//// +//// //// --- -//// -//// Predicates: A module containing functions for testing various mathematical +//// +//// Predicates: A module containing functions for testing various mathematical //// properties of numbers. -//// +//// //// * **Tests** //// * [`is_close`](#is_close) //// * [`list_all_close`](#all_close) @@ -38,7 +38,7 @@ //// * [`is_divisible`](#is_divisible) //// * [`is_multiple`](#is_multiple) //// * [`is_prime`](#is_prime) -//// +//// import gleam/int import gleam/list @@ -54,16 +54,16 @@ import gleam_community/maths/piecewise /// ///
/// -/// Determine if a given value \\(a\\) is close to or equivalent to a reference value +/// Determine if a given value \\(a\\) is close to or equivalent to a reference value /// \\(b\\) based on supplied relative \\(r_{tol}\\) and absolute \\(a_{tol}\\) tolerance -/// values. The equivalance of the two given values are then determined based on +/// values. The equivalance of the two given values are then determined based on /// the equation: /// /// \\[ /// \|a - b\| \leq (a_{tol} + r_{tol} \cdot \|b\|) /// \\] /// -/// `True` is returned if statement holds, otherwise `False` is returned. +/// `True` is returned if statement holds, otherwise `False` is returned. ///
/// Example /// @@ -71,12 +71,12 @@ import gleam_community/maths/piecewise /// import gleam_community/maths/predicates /// /// pub fn example () { -/// let val: Float = 99. -/// let ref_val: Float = 100. +/// let val = 99. +/// let ref_val = 100. /// // We set 'atol' and 'rtol' such that the values are equivalent /// // if 'val' is within 1 percent of 'ref_val' +/- 0.1 -/// let rtol: Float = 0.01 -/// let atol: Float = 0.10 +/// let rtol = 0.01 +/// let atol = 0.10 /// floatx.is_close(val, ref_val, rtol, atol) /// |> should.be_true() /// } @@ -89,8 +89,8 @@ import gleam_community/maths/piecewise /// /// pub fn is_close(a: Float, b: Float, rtol: Float, atol: Float) -> Bool { - let x: Float = float_absolute_difference(a, b) - let y: Float = atol +. rtol *. float_absolute_value(b) + let x = float_absolute_difference(a, b) + let y = atol +. rtol *. float_absolute_value(b) case x <=. y { True -> True False -> False @@ -126,14 +126,14 @@ fn float_absolute_difference(a: Float, b: Float) -> Float { /// import gleam_community/maths/predicates /// /// pub fn example () { -/// let val: Float = 99. -/// let ref_val: Float = 100. -/// let xarr: List(Float) = list.repeat(val, 42) -/// let yarr: List(Float) = list.repeat(ref_val, 42) +/// let val = 99. +/// let ref_val = 100. +/// let xarr = list.repeat(val, 42) +/// let yarr = list.repeat(ref_val, 42) /// // We set 'atol' and 'rtol' such that the values are equivalent /// // if 'val' is within 1 percent of 'ref_val' +/- 0.1 -/// let rtol: Float = 0.01 -/// let atol: Float = 0.10 +/// let rtol = 0.01 +/// let atol = 0.10 /// predicates.all_close(xarr, yarr, rtol, atol) /// |> fn(zarr: Result(List(Bool), String)) -> Result(Bool, Nil) { /// case zarr { @@ -160,8 +160,8 @@ pub fn all_close( rtol: Float, atol: Float, ) -> Result(List(Bool), String) { - let xlen: Int = list.length(xarr) - let ylen: Int = list.length(yarr) + let xlen = list.length(xarr) + let ylen = list.length(yarr) case xlen == ylen { False -> "Invalid input argument: length(xarr) != length(yarr). Valid input is when length(xarr) == length(yarr)." @@ -182,10 +182,10 @@ pub fn all_close( /// /// /// Determine if a given value is fractional. -/// -/// `True` is returned if the given value is fractional, otherwise `False` is -/// returned. -/// +/// +/// `True` is returned if the given value is fractional, otherwise `False` is +/// returned. +/// ///
/// Example /// @@ -195,7 +195,7 @@ pub fn all_close( /// pub fn example () { /// predicates.is_fractional(0.3333) /// |> should.equal(True) -/// +/// /// predicates.is_fractional(1.0) /// |> should.equal(False) /// } @@ -222,7 +222,7 @@ fn do_ceiling(a: Float) -> Float /// /// /// A function that tests whether a given integer value \\(x \in \mathbb{Z}\\) is a -/// power of another integer value \\(y \in \mathbb{Z}\\). +/// power of another integer value \\(y \in \mathbb{Z}\\). /// ///
/// Example: @@ -262,9 +262,9 @@ pub fn is_power(x: Int, y: Int) -> Bool { /// /// /// A function that tests whether a given integer value \\(n \in \mathbb{Z}\\) is a -/// perfect number. A number is perfect if it is equal to the sum of its proper +/// perfect number. A number is perfect if it is equal to the sum of its proper /// positive divisors. -/// +/// ///
/// Details /// @@ -314,7 +314,7 @@ fn do_sum(arr: List(Int)) -> Int { /// /// /// -/// A function that tests whether a given integer value \\(x \in \mathbb{Z}\\) is even. +/// A function that tests whether a given integer value \\(x \in \mathbb{Z}\\) is even. /// ///
/// Example: @@ -325,7 +325,7 @@ fn do_sum(arr: List(Int)) -> Int { /// pub fn example() { /// predicates.is_even(-3) /// |> should.equal(False) -/// +/// /// predicates.is_even(-4) /// |> should.equal(True) /// } @@ -347,7 +347,7 @@ pub fn is_even(x: Int) -> Bool { /// /// /// -/// A function that tests whether a given integer value \\(x \in \mathbb{Z}\\) is odd. +/// A function that tests whether a given integer value \\(x \in \mathbb{Z}\\) is odd. /// ///
/// Example: @@ -358,7 +358,7 @@ pub fn is_even(x: Int) -> Bool { /// pub fn example() { /// predicates.is_odd(-3) /// |> should.equal(True) -/// +/// /// predicates.is_odd(-4) /// |> should.equal(False) /// } @@ -380,24 +380,24 @@ pub fn is_odd(x: Int) -> Bool { /// /// /// -/// A function that tests whether a given integer value \\(x \in \mathbb{Z}\\) is a -/// prime number. A prime number is a natural number greater than 1 that has no +/// A function that tests whether a given integer value \\(x \in \mathbb{Z}\\) is a +/// prime number. A prime number is a natural number greater than 1 that has no /// positive divisors other than 1 and itself. -/// -/// The function uses the Miller-Rabin primality test to assess if \\(x\\) is prime. -/// It is a probabilistic test, so it can mistakenly identify a composite number +/// +/// The function uses the Miller-Rabin primality test to assess if \\(x\\) is prime. +/// It is a probabilistic test, so it can mistakenly identify a composite number /// as prime. However, the probability of such errors decreases with more testing -/// iterations (the function uses 64 iterations internally, which is typically +/// iterations (the function uses 64 iterations internally, which is typically /// more than sufficient). The Miller-Rabin test is particularly useful for large /// numbers. -/// +/// ///
/// Details /// /// Examples of prime numbers: /// - \\(2\\) is a prime number since it has only two divisors: \\(1\\) and \\(2\\). /// - \\(7\\) is a prime number since it has only two divisors: \\(1\\) and \\(7\\). -/// - \\(4\\) is not a prime number since it has divisors other than \\(1\\) and itself, such +/// - \\(4\\) is not a prime number since it has divisors other than \\(1\\) and itself, such /// as \\(2\\). /// ///
@@ -414,7 +414,7 @@ pub fn is_odd(x: Int) -> Bool { /// /// predicates.is_prime(4) /// |> should.equal(False) -/// +/// /// // Test the 2nd Carmichael number /// predicates.is_prime(1105) /// |> should.equal(False) @@ -446,7 +446,7 @@ fn miller_rabin_test(n: Int, k: Int) -> Bool { _, 0 -> True _, _ -> { // Generate a random int in the range [2, n] - let random_candidate: Int = 2 + int.random(n - 2) + let random_candidate = 2 + int.random(n - 2) case powmod_with_check(random_candidate, n - 1, n) == 1 { True -> miller_rabin_test(n, k - 1) False -> False @@ -459,7 +459,7 @@ fn powmod_with_check(base: Int, exponent: Int, modulus: Int) -> Int { case exponent, { exponent % 2 } == 0 { 0, _ -> 1 _, True -> { - let x: Int = powmod_with_check(base, exponent / 2, modulus) + let x = powmod_with_check(base, exponent / 2, modulus) case { x * x } % modulus, x != 1 && x != { modulus - 1 } { 1, True -> 0 _, _ -> { x * x } % modulus @@ -512,9 +512,9 @@ pub fn is_between(x: Float, lower: Float, upper: Float) -> Bool { /// /// /// -/// A function that tests whether a given integer \\(n \in \mathbb{Z}\\) is divisible by another +/// A function that tests whether a given integer \\(n \in \mathbb{Z}\\) is divisible by another /// integer \\(d \in \mathbb{Z}\\), such that \\(n \mod d = 0\\). -/// +/// ///
/// Details /// @@ -555,9 +555,9 @@ pub fn is_divisible(n: Int, d: Int) -> Bool { /// /// /// -/// A function that tests whether a given integer \\(m \in \mathbb{Z}\\) is a multiple of another +/// A function that tests whether a given integer \\(m \in \mathbb{Z}\\) is a multiple of another /// integer \\(k \in \mathbb{Z}\\), such that \\(m = k \times q\\), with \\(q \in \mathbb{Z}\\). -/// +/// ///
/// Details /// diff --git a/src/gleam_community/maths/sequences.gleam b/src/gleam_community/maths/sequences.gleam index 9ffe6ec..8385047 100644 --- a/src/gleam_community/maths/sequences.gleam +++ b/src/gleam_community/maths/sequences.gleam @@ -20,18 +20,18 @@ //// -//// +//// //// --- -//// -//// Sequences: A module containing functions for generating various types of +//// +//// Sequences: A module containing functions for generating various types of //// sequences, ranges and intervals. -//// +//// //// * **Ranges and intervals** //// * [`arange`](#arange) //// * [`linear_space`](#linear_space) //// * [`logarithmic_space`](#logarithmic_space) //// * [`geometric_space`](#geometric_space) -//// +//// import gleam/iterator import gleam_community/maths/conversion @@ -47,7 +47,7 @@ import gleam_community/maths/piecewise /// The function returns an iterator generating evenly spaced values within a given interval. /// based on a start value but excludes the stop value. The spacing between values is determined /// by the step size provided. The function supports both positive and negative step values. -/// +/// ///
/// Example: /// @@ -59,13 +59,13 @@ import gleam_community/maths/piecewise /// sequences.arange(1.0, 5.0, 1.0) /// |> iterator.to_list() /// |> should.equal([1.0, 2.0, 3.0, 4.0]) -/// +/// /// // No points returned since /// // start is smaller than stop and the step is positive /// sequences.arange(5.0, 1.0, 1.0) /// |> iterator.to_list() /// |> should.equal([]) -/// +/// /// // Points returned since /// // start smaller than stop but negative step /// sequences.arange(5.0, 1.0, -1.0) @@ -115,10 +115,10 @@ pub fn arange( /// /// /// -/// The function returns an iterator for generating linearly spaced points over a specified -/// interval. The endpoint of the interval can optionally be included/excluded. The number of +/// The function returns an iterator for generating linearly spaced points over a specified +/// interval. The endpoint of the interval can optionally be included/excluded. The number of /// points and whether the endpoint is included determine the spacing between values. -/// +/// ///
/// Example: /// @@ -138,7 +138,7 @@ pub fn arange( /// 0.0, /// tol, /// ) -/// +/// /// result /// |> list.all(fn(x) { x == True }) /// |> should.be_true() @@ -161,7 +161,7 @@ pub fn linear_space( num: Int, endpoint: Bool, ) -> Result(iterator.Iterator(Float), String) { - let direction: Float = case start <=. stop { + let direction = case start <=. stop { True -> 1.0 False -> -1.0 } @@ -196,10 +196,10 @@ pub fn linear_space( /// /// /// -/// The function returns an iterator of logarithmically spaced points over a specified interval. -/// The endpoint of the interval can optionally be included/excluded. The number of points, base, +/// The function returns an iterator of logarithmically spaced points over a specified interval. +/// The endpoint of the interval can optionally be included/excluded. The number of points, base, /// and whether the endpoint is included determine the spacing between values. -/// +/// ///
/// Example: /// @@ -264,9 +264,9 @@ pub fn logarithmic_space( /// /// /// -/// The function returns an iterator of numbers spaced evenly on a log scale (a geometric -/// progression). Each point in the list is a constant multiple of the previous. The function is -/// similar to the [`logarithmic_space`](#logarithmic_space) function, but with endpoints +/// The function returns an iterator of numbers spaced evenly on a log scale (a geometric +/// progression). Each point in the list is a constant multiple of the previous. The function is +/// similar to the [`logarithmic_space`](#logarithmic_space) function, but with endpoints /// specified directly. /// ///
@@ -295,7 +295,7 @@ pub fn logarithmic_space( /// // Input (start and stop can't be equal to 0.0) /// sequences.geometric_space(0.0, 1000.0, 3, False) /// |> should.be_error() -/// +/// /// sequences.geometric_space(-1000.0, 0.0, 3, False) /// |> should.be_error() /// diff --git a/src/gleam_community/maths/special.gleam b/src/gleam_community/maths/special.gleam index f6e3438..28b098c 100644 --- a/src/gleam_community/maths/special.gleam +++ b/src/gleam_community/maths/special.gleam @@ -20,17 +20,17 @@ //// -//// +//// //// --- -//// +//// //// Special: A module containing special mathematical functions. -//// +//// //// * **Special mathematical functions** //// * [`beta`](#beta) //// * [`erf`](#erf) //// * [`gamma`](#gamma) //// * [`incomplete_gamma`](#incomplete_gamma) -//// +//// import gleam/list import gleam_community/maths/conversion @@ -76,17 +76,17 @@ pub fn beta(x: Float, y: Float) -> Float { /// /// pub fn erf(x: Float) -> Float { - let assert [a1, a2, a3, a4, a5]: List(Float) = [ + let assert [a1, a2, a3, a4, a5] = [ 0.254829592, -0.284496736, 1.421413741, -1.453152027, 1.061405429, ] - let p: Float = 0.3275911 + let p = 0.3275911 - let sign: Float = piecewise.float_sign(x) - let x: Float = piecewise.float_absolute_value(x) + let sign = piecewise.float_sign(x) + let x = piecewise.float_absolute_value(x) // Formula 7.1.26 given in Abramowitz and Stegun. - let t: Float = 1.0 /. { 1.0 +. p *. x } - let y: Float = + let t = 1.0 /. { 1.0 +. p *. x } + let y = 1.0 -. { { { { a5 *. t +. a4 } *. t +. a3 } *. t +. a2 } *. t +. a1 } *. t @@ -100,7 +100,7 @@ pub fn erf(x: Float) -> Float { /// /// /// -/// The gamma function over the real numbers. The function is essentially equal to +/// The gamma function over the real numbers. The function is essentially equal to /// the factorial for any positive integer argument: \\(\Gamma(n) = (n - 1)!\\) /// /// The implemented gamma function is approximated through Lanczos approximation @@ -131,14 +131,14 @@ fn gamma_lanczos(x: Float) -> Float { /. { elementary.sin(elementary.pi() *. x) *. gamma_lanczos(1.0 -. x) } False -> { let z = x -. 1.0 - let x: Float = + let x = list.index_fold(lanczos_p, 0.0, fn(acc: Float, v: Float, index: Int) { case index > 0 { True -> acc +. v /. { z +. conversion.int_to_float(index) } False -> v } }) - let t: Float = z +. lanczos_g +. 0.5 + let t = z +. lanczos_g +. 0.5 let assert Ok(v1) = elementary.power(2.0 *. elementary.pi(), 0.5) let assert Ok(v2) = elementary.power(t, z +. 0.5) v1 *. v2 *. elementary.exponential(-1.0 *. t) *. x @@ -189,8 +189,8 @@ fn incomplete_gamma_sum( case t { 0.0 -> s _ -> { - let ns: Float = s +. t - let nt: Float = t *. { x /. { a +. n } } + let ns = s +. t + let nt = t *. { x /. { a +. n } } incomplete_gamma_sum(a, x, nt, ns, n +. 1.0) } } diff --git a/test/gleam_community/maths/metrics_test.gleam b/test/gleam_community/maths/metrics_test.gleam index dcf43eb..4debea5 100644 --- a/test/gleam_community/maths/metrics_test.gleam +++ b/test/gleam_community/maths/metrics_test.gleam @@ -317,7 +317,7 @@ pub fn median_test() { pub fn variance_test() { // Degrees of freedom - let ddof: Int = 1 + let ddof = 1 // An empty list returns an error [] @@ -332,7 +332,7 @@ pub fn variance_test() { pub fn standard_deviation_test() { // Degrees of freedom - let ddof: Int = 1 + let ddof = 1 // An empty list returns an error [] @@ -349,19 +349,18 @@ pub fn jaccard_index_test() { metrics.jaccard_index(set.from_list([]), set.from_list([])) |> should.equal(0.0) - let set_a: set.Set(Int) = set.from_list([0, 1, 2, 5, 6, 8, 9]) - let set_b: set.Set(Int) = set.from_list([0, 2, 3, 4, 5, 7, 9]) + let set_a = set.from_list([0, 1, 2, 5, 6, 8, 9]) + let set_b = set.from_list([0, 2, 3, 4, 5, 7, 9]) metrics.jaccard_index(set_a, set_b) |> should.equal(4.0 /. 10.0) - let set_c: set.Set(Int) = set.from_list([0, 1, 2, 3, 4, 5]) - let set_d: set.Set(Int) = set.from_list([6, 7, 8, 9, 10]) + let set_c = set.from_list([0, 1, 2, 3, 4, 5]) + let set_d = set.from_list([6, 7, 8, 9, 10]) metrics.jaccard_index(set_c, set_d) |> should.equal(0.0 /. 11.0) - let set_e: set.Set(String) = set.from_list(["cat", "dog", "hippo", "monkey"]) - let set_f: set.Set(String) = - set.from_list(["monkey", "rhino", "ostrich", "salmon"]) + let set_e = set.from_list(["cat", "dog", "hippo", "monkey"]) + let set_f = set.from_list(["monkey", "rhino", "ostrich", "salmon"]) metrics.jaccard_index(set_e, set_f) |> should.equal(1.0 /. 7.0) } @@ -370,19 +369,18 @@ pub fn sorensen_dice_coefficient_test() { metrics.sorensen_dice_coefficient(set.from_list([]), set.from_list([])) |> should.equal(0.0) - let set_a: set.Set(Int) = set.from_list([0, 1, 2, 5, 6, 8, 9]) - let set_b: set.Set(Int) = set.from_list([0, 2, 3, 4, 5, 7, 9]) + let set_a = set.from_list([0, 1, 2, 5, 6, 8, 9]) + let set_b = set.from_list([0, 2, 3, 4, 5, 7, 9]) metrics.sorensen_dice_coefficient(set_a, set_b) |> should.equal(2.0 *. 4.0 /. { 7.0 +. 7.0 }) - let set_c: set.Set(Int) = set.from_list([0, 1, 2, 3, 4, 5]) - let set_d: set.Set(Int) = set.from_list([6, 7, 8, 9, 10]) + let set_c = set.from_list([0, 1, 2, 3, 4, 5]) + let set_d = set.from_list([6, 7, 8, 9, 10]) metrics.sorensen_dice_coefficient(set_c, set_d) |> should.equal(2.0 *. 0.0 /. { 6.0 +. 5.0 }) - let set_e: set.Set(String) = set.from_list(["cat", "dog", "hippo", "monkey"]) - let set_f: set.Set(String) = - set.from_list(["monkey", "rhino", "ostrich", "salmon", "spider"]) + let set_e = set.from_list(["cat", "dog", "hippo", "monkey"]) + let set_f = set.from_list(["monkey", "rhino", "ostrich", "salmon", "spider"]) metrics.sorensen_dice_coefficient(set_e, set_f) |> should.equal(2.0 *. 1.0 /. { 4.0 +. 5.0 }) } @@ -391,20 +389,18 @@ pub fn overlap_coefficient_test() { metrics.overlap_coefficient(set.from_list([]), set.from_list([])) |> should.equal(0.0) - let set_a: set.Set(Int) = set.from_list([0, 1, 2, 5, 6, 8, 9]) - let set_b: set.Set(Int) = set.from_list([0, 2, 3, 4, 5, 7, 9]) + let set_a = set.from_list([0, 1, 2, 5, 6, 8, 9]) + let set_b = set.from_list([0, 2, 3, 4, 5, 7, 9]) metrics.overlap_coefficient(set_a, set_b) |> should.equal(4.0 /. 7.0) - let set_c: set.Set(Int) = set.from_list([0, 1, 2, 3, 4, 5]) - let set_d: set.Set(Int) = set.from_list([6, 7, 8, 9, 10]) + let set_c = set.from_list([0, 1, 2, 3, 4, 5]) + let set_d = set.from_list([6, 7, 8, 9, 10]) metrics.overlap_coefficient(set_c, set_d) |> should.equal(0.0 /. 5.0) - let set_e: set.Set(String) = - set.from_list(["horse", "dog", "hippo", "monkey", "bird"]) - let set_f: set.Set(String) = - set.from_list(["monkey", "bird", "ostrich", "salmon"]) + let set_e = set.from_list(["horse", "dog", "hippo", "monkey", "bird"]) + let set_f = set.from_list(["monkey", "bird", "ostrich", "salmon"]) metrics.overlap_coefficient(set_e, set_f) |> should.equal(2.0 /. 4.0) } @@ -440,7 +436,7 @@ pub fn cosine_similarity_test() { metrics.cosine_similarity([-1.0, -2.0, -3.0], [1.0, 2.0, 3.0], option.None) |> should.equal(Ok(-1.0)) - // Try with arbitrary valid input + // Try with arbitrary valid input let assert Ok(result) = metrics.cosine_similarity([1.0, 2.0, 3.0], [4.0, 5.0, 6.0], option.None) result diff --git a/test/gleam_community/maths/predicates_test.gleam b/test/gleam_community/maths/predicates_test.gleam index fcae19c..0248fcf 100644 --- a/test/gleam_community/maths/predicates_test.gleam +++ b/test/gleam_community/maths/predicates_test.gleam @@ -3,25 +3,25 @@ import gleam_community/maths/predicates import gleeunit/should pub fn float_is_close_test() { - let val: Float = 99.0 - let ref_val: Float = 100.0 + let val = 99.0 + let ref_val = 100.0 // We set 'atol' and 'rtol' such that the values are equivalent // if 'val' is within 1 percent of 'ref_val' +/- 0.1 - let rtol: Float = 0.01 - let atol: Float = 0.1 + let rtol = 0.01 + let atol = 0.1 predicates.is_close(val, ref_val, rtol, atol) |> should.be_true() } pub fn float_list_all_close_test() { - let val: Float = 99.0 - let ref_val: Float = 100.0 - let xarr: List(Float) = list.repeat(val, 42) - let yarr: List(Float) = list.repeat(ref_val, 42) + let val = 99.0 + let ref_val = 100.0 + let xarr = list.repeat(val, 42) + let yarr = list.repeat(ref_val, 42) // We set 'atol' and 'rtol' such that the values are equivalent // if 'val' is within 1 percent of 'ref_val' +/- 0.1 - let rtol: Float = 0.01 - let atol: Float = 0.1 + let rtol = 0.01 + let atol = 0.1 predicates.all_close(xarr, yarr, rtol, atol) |> fn(zarr: Result(List(Bool), String)) -> Result(Bool, Nil) { case zarr { From 00ad62800f31b30dd6fd0c2d1972b69ae01a9a5d Mon Sep 17 00:00:00 2001 From: Hayleigh Thompson Date: Sat, 17 Aug 2024 11:29:39 +0100 Subject: [PATCH 2/4] :recycle: Remove type annotations from lambdas. --- src/gleam_community/maths/arithmetics.gleam | 24 ++-- src/gleam_community/maths/combinatorics.gleam | 107 ++++++++---------- src/gleam_community/maths/metrics.gleam | 47 ++++---- src/gleam_community/maths/piecewise.gleam | 20 ++-- src/gleam_community/maths/predicates.gleam | 10 +- src/gleam_community/maths/sequences.gleam | 6 +- src/gleam_community/maths/special.gleam | 2 +- .../maths/predicates_test.gleam | 4 +- 8 files changed, 101 insertions(+), 119 deletions(-) diff --git a/src/gleam_community/maths/arithmetics.gleam b/src/gleam_community/maths/arithmetics.gleam index ab8eb12..540ba0d 100644 --- a/src/gleam_community/maths/arithmetics.gleam +++ b/src/gleam_community/maths/arithmetics.gleam @@ -244,7 +244,7 @@ fn find_divisors(n: Int) -> List(Int) { let assert Ok(sqrt_result) = elementary.square_root(nabs) let max = conversion.float_to_int(sqrt_result) + 1 list.range(2, max) - |> list.fold([1, n], fn(acc: List(Int), i: Int) -> List(Int) { + |> list.fold([1, n], fn(acc, i) { case n % i == 0 { True -> [i, n / i, ..acc] False -> acc @@ -340,10 +340,10 @@ pub fn float_sum(arr: List(Float), weights: option.Option(List(Float))) -> Float [], _ -> 0.0 _, option.None -> arr - |> list.fold(0.0, fn(acc: Float, a: Float) -> Float { a +. acc }) + |> list.fold(0.0, fn(acc, a) { a +. acc }) _, option.Some(warr) -> { list.zip(arr, warr) - |> list.fold(0.0, fn(acc: Float, a: #(Float, Float)) -> Float { + |> list.fold(0.0, fn(acc: Float, a) { pair.first(a) *. pair.second(a) +. acc }) } @@ -395,7 +395,7 @@ pub fn int_sum(arr: List(Int)) -> Int { [] -> 0 _ -> arr - |> list.fold(0, fn(acc: Int, a: Int) -> Int { a + acc }) + |> list.fold(0, fn(acc, a) { a + acc }) } } @@ -451,12 +451,12 @@ pub fn float_product( |> Ok _, option.None -> arr - |> list.fold(1.0, fn(acc: Float, a: Float) -> Float { a *. acc }) + |> list.fold(1.0, fn(acc, a) { a *. acc }) |> Ok _, option.Some(warr) -> { let results = list.zip(arr, warr) - |> list.map(fn(a: #(Float, Float)) -> Result(Float, String) { + |> list.map(fn(a) { pair.first(a) |> elementary.power(pair.second(a)) }) @@ -464,7 +464,7 @@ pub fn float_product( case results { Ok(prods) -> prods - |> list.fold(1.0, fn(acc: Float, a: Float) -> Float { a *. acc }) + |> list.fold(1.0, fn(acc, a) { a *. acc }) |> Ok Error(msg) -> msg @@ -519,7 +519,7 @@ pub fn int_product(arr: List(Int)) -> Int { [] -> 1 _ -> arr - |> list.fold(1, fn(acc: Int, a: Int) -> Int { a * acc }) + |> list.fold(1, fn(acc, a) { a * acc }) } } @@ -569,7 +569,7 @@ pub fn float_cumulative_sum(arr: List(Float)) -> List(Float) { [] -> [] _ -> arr - |> list.scan(0.0, fn(acc: Float, a: Float) -> Float { a +. acc }) + |> list.scan(0.0, fn(acc, a) { a +. acc }) } } @@ -619,7 +619,7 @@ pub fn int_cumulative_sum(arr: List(Int)) -> List(Int) { [] -> [] _ -> arr - |> list.scan(0, fn(acc: Int, a: Int) -> Int { a + acc }) + |> list.scan(0, fn(acc, a) { a + acc }) } } @@ -671,7 +671,7 @@ pub fn float_cumulative_product(arr: List(Float)) -> List(Float) { [] -> [] _ -> arr - |> list.scan(1.0, fn(acc: Float, a: Float) -> Float { a *. acc }) + |> list.scan(1.0, fn(acc, a) { a *. acc }) } } @@ -723,6 +723,6 @@ pub fn int_cumulative_product(arr: List(Int)) -> List(Int) { [] -> [] _ -> arr - |> list.scan(1, fn(acc: Int, a: Int) -> Int { a * acc }) + |> list.scan(1, fn(acc, a) { a * acc }) } } diff --git a/src/gleam_community/maths/combinatorics.gleam b/src/gleam_community/maths/combinatorics.gleam index b026c4d..b6a6606 100644 --- a/src/gleam_community/maths/combinatorics.gleam +++ b/src/gleam_community/maths/combinatorics.gleam @@ -20,12 +20,12 @@ //// -//// +//// //// --- -//// -//// Combinatorics: A module that offers mathematical functions related to counting, arrangements, -//// and permutations/combinations. -//// +//// +//// Combinatorics: A module that offers mathematical functions related to counting, arrangements, +//// and permutations/combinations. +//// //// * **Combinatorial functions** //// * [`combination`](#combination) //// * [`factorial`](#factorial) @@ -33,7 +33,7 @@ //// * [`list_combination`](#list_combination) //// * [`list_permutation`](#list_permutation) //// * [`cartesian_product`](#cartesian_product) -//// +//// import gleam/iterator import gleam/list @@ -70,26 +70,26 @@ pub type CombinatoricsMode { /// Also known as the "stars and bars" problem in combinatorics. /// /// The implementation uses an efficient iterative multiplicative formula for computing the result. -/// +/// ///
/// Details -/// -/// A \\(k\\)-combination is a sequence of \\(k\\) elements selected from \\(n\\) elements where -/// the order of selection does not matter. For example, consider selecting 2 elements from a list +/// +/// A \\(k\\)-combination is a sequence of \\(k\\) elements selected from \\(n\\) elements where +/// the order of selection does not matter. For example, consider selecting 2 elements from a list /// of 3 elements: `["A", "B", "C"]`: -/// -/// - For \\(k\\)-combinations (without repetitions), where order does not matter, the possible +/// +/// - For \\(k\\)-combinations (without repetitions), where order does not matter, the possible /// selections are: /// - `["A", "B"]` /// - `["A", "C"]` /// - `["B", "C"]` /// -/// - For \\(k\\)-combinations (with repetitions), where order does not matter but elements can +/// - For \\(k\\)-combinations (with repetitions), where order does not matter but elements can /// repeat, the possible selections are: /// - `["A", "A"], ["A", "B"], ["A", "C"]` /// - `["B", "B"], ["B", "C"], ["C", "C"]` /// -/// - On the contrary, for \\(k\\)-permutations (without repetitions), the order matters, so the +/// - On the contrary, for \\(k\\)-permutations (without repetitions), the order matters, so the /// possible selections are: /// - `["A", "B"], ["B", "A"]` /// - `["A", "C"], ["C", "A"]` @@ -106,15 +106,15 @@ pub type CombinatoricsMode { /// // Invalid input gives an error /// combinatorics.combination(-1, 1, option.None) /// |> should.be_error() -/// +/// /// // Valid input: n = 4 and k = 0 /// combinatorics.combination(4, 0, option.Some(combinatorics.WithoutRepetitions)) /// |> should.equal(Ok(1)) -/// +/// /// // Valid input: k = n (n = 4, k = 4) /// combinatorics.combination(4, 4, option.Some(combinatorics.WithoutRepetitions)) /// |> should.equal(Ok(1)) -/// +/// /// // Valid input: combinations with repetition (n = 2, k = 3) /// combinatorics.combination(2, 3, option.Some(combinatorics.WithRepetitions)) /// |> should.equal(Ok(4)) @@ -125,7 +125,7 @@ pub type CombinatoricsMode { /// Back to top ↑ /// /// -/// +/// pub fn combination( n: Int, k: Int, @@ -161,7 +161,7 @@ fn combination_without_repetitions(n: Int, k: Int) -> Result(Int, String) { False -> n - k } list.range(1, min) - |> list.fold(1, fn(acc: Int, x: Int) -> Int { acc * { n + 1 - x } / x }) + |> list.fold(1, fn(acc, x) { acc * { n + 1 - x } / x }) |> Ok } } @@ -215,7 +215,7 @@ pub fn factorial(n) -> Result(Int, String) { |> Ok _ -> list.range(1, n) - |> list.fold(1, fn(acc: Int, x: Int) -> Int { acc * x }) + |> list.fold(1, fn(acc, x) { acc * x }) |> Ok } } @@ -227,50 +227,50 @@ pub fn factorial(n) -> Result(Int, String) { /// /// /// A combinatorial function for computing the number of \\(k\\)-permutations. -/// +/// /// **Without** repetitions: /// /// \\[ /// P(n, k) = \binom{n}{k} \cdot k! = \frac{n!}{(n - k)!} /// \\] -/// +/// /// **With** repetitions: -/// +/// /// \\[ /// P^*(n, k) = n^k /// \\] -/// +/// /// The implementation uses an efficient iterative multiplicative formula for computing the result. -/// +/// ///
/// Details -/// +/// /// A \\(k\\)-permutation (without repetitions) is a sequence of \\(k\\) elements selected from \ -/// \\(n\\) elements where the order of selection matters. For example, consider selecting 2 +/// \\(n\\) elements where the order of selection matters. For example, consider selecting 2 /// elements from a list of 3 elements: `["A", "B", "C"]`: -/// -/// - For \\(k\\)-permutations (without repetitions), the order matters, so the possible selections +/// +/// - For \\(k\\)-permutations (without repetitions), the order matters, so the possible selections /// are: /// - `["A", "B"], ["B", "A"]` /// - `["A", "C"], ["C", "A"]` /// - `["B", "C"], ["C", "B"]` -/// -/// - For \\(k\\)-permutations (with repetitions), the order also matters, but we have repeated +/// +/// - For \\(k\\)-permutations (with repetitions), the order also matters, but we have repeated /// selections: /// - `["A", "A"], ["A", "B"], ["A", "C"]` /// - `["B", "A"], ["B", "B"], ["B", "C"]` /// - `["C", "A"], ["C", "B"], ["C", "C"]` /// -/// - On the contrary, for \\(k\\)-combinations (without repetitions), where order does not matter, +/// - On the contrary, for \\(k\\)-combinations (without repetitions), where order does not matter, /// the possible selections are: /// - `["A", "B"]` /// - `["A", "C"]` /// - `["B", "C"]` ///
-/// +/// ///
/// Example: -/// +/// /// import gleam/option /// import gleeunit/should /// import gleam_community/maths/combinatorics @@ -325,7 +325,7 @@ fn permutation_without_repetitions(n: Int, k: Int) -> Result(Int, String) { } _, _ -> list.range(0, k - 1) - |> list.fold(1, fn(acc: Int, x: Int) -> Int { acc * { n - x } }) + |> list.fold(1, fn(acc, x) { acc * { n - x } }) |> Ok } } @@ -346,11 +346,11 @@ fn permutation_with_repetitions(n: Int, k: Int) -> Result(Int, String) { /// /// /// -/// Generates all possible combinations of \\(k\\) elements selected from a given list of size +/// Generates all possible combinations of \\(k\\) elements selected from a given list of size /// \\(n\\). /// -/// The function can handle cases with and without repetitions -/// (see more details [here](#combination)). Also, note that repeated elements are treated as +/// The function can handle cases with and without repetitions +/// (see more details [here](#combination)). Also, note that repeated elements are treated as /// distinct. /// ///
@@ -370,7 +370,7 @@ fn permutation_with_repetitions(n: Int, k: Int) -> Result(Int, String) { /// 3, /// option.Some(combinatorics.WithoutRepetitions), /// ) -/// +/// /// result /// |> iterator.to_list() /// |> set.from_list() @@ -476,11 +476,11 @@ fn do_list_combination_with_repetitions( /// /// /// -/// Generates all possible permutations of \\(k\\) elements selected from a given list of size +/// Generates all possible permutations of \\(k\\) elements selected from a given list of size /// \\(n\\). /// -/// The function can handle cases with and without repetitions -/// (see more details [here](#permutation)). Also, note that repeated elements are treated as +/// The function can handle cases with and without repetitions +/// (see more details [here](#permutation)). Also, note that repeated elements are treated as /// distinct. /// ///
@@ -500,7 +500,7 @@ fn do_list_combination_with_repetitions( /// 3, /// option.Some(combinatorics.WithoutRepetitions), /// ) -/// +/// /// result /// |> iterator.to_list() /// |> set.from_list() @@ -523,7 +523,7 @@ fn do_list_combination_with_repetitions( /// /// /// -/// +/// pub fn list_permutation( arr: List(a), k: Int, @@ -636,7 +636,7 @@ fn do_list_permutation_with_repetitions( /// set.from_list([]) /// |> combinatorics.cartesian_product(set.from_list([])) /// |> should.equal(set.from_list([])) -/// +/// /// // Cartesian product of two sets with numeric values /// set.from_list([1.0, 10.0]) /// |> combinatorics.cartesian_product(set.from_list([1.0, 2.0])) @@ -654,16 +654,9 @@ fn do_list_permutation_with_repetitions( /// pub fn cartesian_product(xset: set.Set(a), yset: set.Set(a)) -> set.Set(#(a, a)) { xset - |> set.fold( - set.new(), - fn(accumulator0: set.Set(#(a, a)), member0: a) -> set.Set(#(a, a)) { - set.fold( - yset, - accumulator0, - fn(accumulator1: set.Set(#(a, a)), member1: a) -> set.Set(#(a, a)) { - set.insert(accumulator1, #(member0, member1)) - }, - ) - }, - ) + |> set.fold(set.new(), fn(accumulator0: set.Set(#(a, a)), member0: a) { + set.fold(yset, accumulator0, fn(accumulator1: set.Set(#(a, a)), member1: a) { + set.insert(accumulator1, #(member0, member1)) + }) + }) } diff --git a/src/gleam_community/maths/metrics.gleam b/src/gleam_community/maths/metrics.gleam index 7f550c3..dd4dd7a 100644 --- a/src/gleam_community/maths/metrics.gleam +++ b/src/gleam_community/maths/metrics.gleam @@ -182,7 +182,7 @@ pub fn norm( _, option.None -> { let aggregate = arr - |> list.fold(0.0, fn(accumulator: Float, element: Float) -> Float { + |> list.fold(0.0, fn(accumulator, element) { let assert Ok(result) = piecewise.float_absolute_value(element) |> elementary.power(p) @@ -202,19 +202,16 @@ pub fn norm( let tuples = list.zip(arr, warr) let aggregate = tuples - |> list.fold( - 0.0, - fn(accumulator: Float, tuple: #(Float, Float)) -> Float { - let first_element = pair.first(tuple) - let second_element = pair.second(tuple) - let assert Ok(result) = - elementary.power( - piecewise.float_absolute_value(first_element), - p, - ) - second_element *. result +. accumulator - }, - ) + |> list.fold(0.0, fn(accumulator, tuple) { + let first_element = pair.first(tuple) + let second_element = pair.second(tuple) + let assert Ok(result) = + elementary.power( + piecewise.float_absolute_value(first_element), + p, + ) + second_element *. result +. accumulator + }) let assert Ok(result) = elementary.power(aggregate, 1.0 /. p) result |> Ok @@ -370,9 +367,7 @@ pub fn minkowski_distance( False -> { let differences = list.zip(xarr, yarr) - |> list.map(fn(tuple: #(Float, Float)) -> Float { - pair.first(tuple) -. pair.second(tuple) - }) + |> list.map(fn(tuple) { pair.first(tuple) -. pair.second(tuple) }) let assert Ok(result) = norm(differences, p, weights) result @@ -496,7 +491,7 @@ pub fn chebyshev_distance( |> Error Ok(_) -> { list.zip(xarr, yarr) - |> list.map(fn(tuple: #(Float, Float)) -> Float { + |> list.map(fn(tuple) { { pair.first(tuple) -. pair.second(tuple) } |> piecewise.float_absolute_value() }) @@ -553,9 +548,7 @@ pub fn mean(arr: List(Float)) -> Result(Float, String) { _ -> arr |> arithmetics.float_sum(option.None) - |> fn(a: Float) -> Float { - a /. conversion.int_to_float(list.length(arr)) - } + |> fn(a) { a /. conversion.int_to_float(list.length(arr)) } |> Ok } } @@ -684,12 +677,12 @@ pub fn variance(arr: List(Float), ddof: Int) -> Result(Float, String) { False -> { let assert Ok(mean) = mean(arr) arr - |> list.map(fn(a: Float) -> Float { + |> list.map(fn(a) { let assert Ok(result) = elementary.power(a -. mean, 2.0) result }) |> arithmetics.float_sum(option.None) - |> fn(a: Float) -> Float { + |> fn(a) { a /. { conversion.int_to_float(list.length(arr)) @@ -1094,9 +1087,7 @@ pub fn cosine_similarity( let numerator_elements = zipped_arr - |> list.map(fn(tuple: #(Float, Float)) -> Float { - pair.first(tuple) *. pair.second(tuple) - }) + |> list.map(fn(tuple) { pair.first(tuple) *. pair.second(tuple) }) case weights { option.None -> { @@ -1284,14 +1275,14 @@ pub fn braycurtis_distance( let zipped_arr = list.zip(xarr, yarr) let numerator_elements = zipped_arr - |> list.map(fn(tuple: #(Float, Float)) -> Float { + |> list.map(fn(tuple) { piecewise.float_absolute_value({ pair.first(tuple) -. pair.second(tuple) }) }) let denominator_elements = zipped_arr - |> list.map(fn(tuple: #(Float, Float)) -> Float { + |> list.map(fn(tuple) { piecewise.float_absolute_value({ pair.first(tuple) +. pair.second(tuple) }) diff --git a/src/gleam_community/maths/piecewise.gleam b/src/gleam_community/maths/piecewise.gleam index d7e8a3c..fdfc4fb 100644 --- a/src/gleam_community/maths/piecewise.gleam +++ b/src/gleam_community/maths/piecewise.gleam @@ -823,7 +823,7 @@ pub fn int_flip_sign(x: Int) -> Int { /// /// /// -pub fn minimum(x: a, y: a, compare: fn(a, a) -> order.Order) -> a { +pub fn minimum(x: a, y: a, compare: fn(a, a) -> order.Order) { case compare(x, y) { order.Lt -> x order.Eq -> x @@ -869,7 +869,7 @@ pub fn minimum(x: a, y: a, compare: fn(a, a) -> order.Order) -> a { /// /// /// -pub fn maximum(x: a, y: a, compare: fn(a, a) -> order.Order) -> a { +pub fn maximum(x: a, y: a, compare: fn(a, a) -> order.Order) { case compare(x, y) { order.Lt -> y order.Eq -> y @@ -909,7 +909,7 @@ pub fn maximum(x: a, y: a, compare: fn(a, a) -> order.Order) -> a { /// /// /// -pub fn minmax(x: a, y: a, compare: fn(a, a) -> order.Order) -> #(a, a) { +pub fn minmax(x: a, y: a, compare: fn(a, a) -> order.Order) { #(minimum(x, y, compare), maximum(x, y, compare)) } @@ -956,7 +956,7 @@ pub fn list_minimum( |> Error [x, ..rest] -> Ok( - list.fold(rest, x, fn(acc: a, element: a) { + list.fold(rest, x, fn(acc, element) { case compare(element, acc) { order.Lt -> element _ -> acc @@ -1010,7 +1010,7 @@ pub fn list_maximum( |> Error [x, ..rest] -> Ok( - list.fold(rest, x, fn(acc: a, element: a) { + list.fold(rest, x, fn(acc, element) { case compare(acc, element) { order.Lt -> element _ -> acc @@ -1073,13 +1073,13 @@ pub fn arg_minimum( arr |> list_minimum(compare) arr - |> list.index_map(fn(element: a, index: Int) -> Int { + |> list.index_map(fn(element, index) { case compare(element, min) { order.Eq -> index _ -> -1 } }) - |> list.filter(fn(index: Int) -> Bool { + |> list.filter(fn(index) { case index { -1 -> False _ -> True @@ -1143,13 +1143,13 @@ pub fn arg_maximum( arr |> list_maximum(compare) arr - |> list.index_map(fn(element: a, index: Int) -> Int { + |> list.index_map(fn(element, index) { case compare(element, max) { order.Eq -> index _ -> -1 } }) - |> list.filter(fn(index: Int) -> Bool { + |> list.filter(fn(index) { case index { -1 -> False _ -> True @@ -1210,7 +1210,7 @@ pub fn extrema( |> Error [x, ..rest] -> Ok( - list.fold(rest, #(x, x), fn(acc: #(a, a), element: a) { + list.fold(rest, #(x, x), fn(acc, element) { let first = pair.first(acc) let second = pair.second(acc) case compare(element, first), compare(second, element) { diff --git a/src/gleam_community/maths/predicates.gleam b/src/gleam_community/maths/predicates.gleam index eca553e..4681e3b 100644 --- a/src/gleam_community/maths/predicates.gleam +++ b/src/gleam_community/maths/predicates.gleam @@ -135,11 +135,11 @@ fn float_absolute_difference(a: Float, b: Float) -> Float { /// let rtol = 0.01 /// let atol = 0.10 /// predicates.all_close(xarr, yarr, rtol, atol) -/// |> fn(zarr: Result(List(Bool), String)) -> Result(Bool, Nil) { +/// |> fn(zarr), String)) { /// case zarr { /// Ok(arr) -> /// arr -/// |> list.all(fn(a: Bool) -> Bool { a }) +/// |> list.all(fn(a) { a }) /// |> Ok /// _ -> Nil |> Error /// } @@ -168,9 +168,7 @@ pub fn all_close( |> Error True -> list.zip(xarr, yarr) - |> list.map(fn(z: #(Float, Float)) -> Bool { - is_close(pair.first(z), pair.second(z), rtol, atol) - }) + |> list.map(fn(z) { is_close(pair.first(z), pair.second(z), rtol, atol) }) |> Ok } } @@ -304,7 +302,7 @@ fn do_sum(arr: List(Int)) -> Int { [] -> 0 _ -> arr - |> list.fold(0, fn(acc: Int, a: Int) -> Int { a + acc }) + |> list.fold(0, fn(acc, a) { a + acc }) } } diff --git a/src/gleam_community/maths/sequences.gleam b/src/gleam_community/maths/sequences.gleam index 8385047..62c5301 100644 --- a/src/gleam_community/maths/sequences.gleam +++ b/src/gleam_community/maths/sequences.gleam @@ -102,7 +102,7 @@ pub fn arange( |> conversion.float_to_int() iterator.range(0, num - 1) - |> iterator.map(fn(i: Int) { + |> iterator.map(fn(i) { start +. conversion.int_to_float(i) *. step_abs *. direction }) } @@ -179,7 +179,7 @@ pub fn linear_space( case num > 0 { True -> { iterator.range(0, num - 1) - |> iterator.map(fn(i: Int) -> Float { + |> iterator.map(fn(i) { start +. conversion.int_to_float(i) *. increment *. direction }) |> Ok @@ -246,7 +246,7 @@ pub fn logarithmic_space( True -> { let assert Ok(linspace) = linear_space(start, stop, num, endpoint) linspace - |> iterator.map(fn(i: Float) -> Float { + |> iterator.map(fn(i) { let assert Ok(result) = elementary.power(base, i) result }) diff --git a/src/gleam_community/maths/special.gleam b/src/gleam_community/maths/special.gleam index 28b098c..a3f0136 100644 --- a/src/gleam_community/maths/special.gleam +++ b/src/gleam_community/maths/special.gleam @@ -132,7 +132,7 @@ fn gamma_lanczos(x: Float) -> Float { False -> { let z = x -. 1.0 let x = - list.index_fold(lanczos_p, 0.0, fn(acc: Float, v: Float, index: Int) { + list.index_fold(lanczos_p, 0.0, fn(acc, v, index) { case index > 0 { True -> acc +. v /. { z +. conversion.int_to_float(index) } False -> v diff --git a/test/gleam_community/maths/predicates_test.gleam b/test/gleam_community/maths/predicates_test.gleam index 0248fcf..c9e2c5f 100644 --- a/test/gleam_community/maths/predicates_test.gleam +++ b/test/gleam_community/maths/predicates_test.gleam @@ -23,11 +23,11 @@ pub fn float_list_all_close_test() { let rtol = 0.01 let atol = 0.1 predicates.all_close(xarr, yarr, rtol, atol) - |> fn(zarr: Result(List(Bool), String)) -> Result(Bool, Nil) { + |> fn(zarr) { case zarr { Ok(arr) -> arr - |> list.all(fn(a: Bool) -> Bool { a }) + |> list.all(fn(a) { a }) |> Ok _ -> Nil From d649063d33f86dadcff9708052cd04b0b50a999a Mon Sep 17 00:00:00 2001 From: Hayleigh Thompson Date: Sat, 17 Aug 2024 11:48:47 +0100 Subject: [PATCH 3/4] :recycle: Remove type annotations from lambdas. --- src/gleam_community/maths/arithmetics.gleam | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/gleam_community/maths/arithmetics.gleam b/src/gleam_community/maths/arithmetics.gleam index 540ba0d..ee27306 100644 --- a/src/gleam_community/maths/arithmetics.gleam +++ b/src/gleam_community/maths/arithmetics.gleam @@ -343,9 +343,7 @@ pub fn float_sum(arr: List(Float), weights: option.Option(List(Float))) -> Float |> list.fold(0.0, fn(acc, a) { a +. acc }) _, option.Some(warr) -> { list.zip(arr, warr) - |> list.fold(0.0, fn(acc: Float, a) { - pair.first(a) *. pair.second(a) +. acc - }) + |> list.fold(0.0, fn(acc, a) { pair.first(a) *. pair.second(a) +. acc }) } } } From b8af54a93535409d6dda2850dda29d87518fb192 Mon Sep 17 00:00:00 2001 From: versecafe <147033096+versecafe@users.noreply.github.com> Date: Wed, 11 Sep 2024 00:54:20 -0500 Subject: [PATCH 4/4] Allow cartesian product of (a, b) instead of (a, a) --- src/gleam_community/maths/combinatorics.gleam | 6 +++--- test/gleam_community/maths/combinatorics_test.gleam | 9 ++++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/gleam_community/maths/combinatorics.gleam b/src/gleam_community/maths/combinatorics.gleam index b6a6606..726ae52 100644 --- a/src/gleam_community/maths/combinatorics.gleam +++ b/src/gleam_community/maths/combinatorics.gleam @@ -652,10 +652,10 @@ fn do_list_permutation_with_repetitions( /// /// /// -pub fn cartesian_product(xset: set.Set(a), yset: set.Set(a)) -> set.Set(#(a, a)) { +pub fn cartesian_product(xset: set.Set(a), yset: set.Set(b)) -> set.Set(#(a, b)) { xset - |> set.fold(set.new(), fn(accumulator0: set.Set(#(a, a)), member0: a) { - set.fold(yset, accumulator0, fn(accumulator1: set.Set(#(a, a)), member1: a) { + |> set.fold(set.new(), fn(accumulator0: set.Set(#(a, b)), member0: a) { + set.fold(yset, accumulator0, fn(accumulator1: set.Set(#(a, b)), member1: b) { set.insert(accumulator1, #(member0, member1)) }) }) diff --git a/test/gleam_community/maths/combinatorics_test.gleam b/test/gleam_community/maths/combinatorics_test.gleam index 087122f..729f450 100644 --- a/test/gleam_community/maths/combinatorics_test.gleam +++ b/test/gleam_community/maths/combinatorics_test.gleam @@ -72,7 +72,7 @@ pub fn int_combination_test() { combinatorics.combination(7, 5, option.Some(combinatorics.WithRepetitions)) |> should.equal(Ok(462)) - // NOTE: Tests with the 'combination' function that produce values that exceed + // NOTE: Tests with the 'combination' function that produce values that exceed // precision of the JavaScript 'Number' primitive will result in errors } @@ -697,4 +697,11 @@ pub fn example_test() { |> should.equal( set.from_list([#(1.0, 1.0), #(1.0, 2.0), #(10.0, 1.0), #(10.0, 2.0)]), ) + + // Cartesian product of two sets with different types + set.from_list(["1", "10"]) + |> combinatorics.cartesian_product(set.from_list([1.0, 2.0])) + |> should.equal( + set.from_list([#("1", 1.0), #("1", 2.0), #("10", 1.0), #("10", 2.0)]), + ) }