mirror of
https://github.com/sigmasternchen/gleam-community-maths
synced 2025-03-16 00:19:05 +00:00
♻️ Remove uses of list.at
This commit is contained in:
parent
6419c400b9
commit
ae959dcafe
2 changed files with 110 additions and 120 deletions
src/gleam_community/maths
|
@ -20,11 +20,11 @@
|
|||
////<style>
|
||||
//// .katex { font-size: 1.1em; }
|
||||
////</style>
|
||||
////
|
||||
////
|
||||
//// ---
|
||||
////
|
||||
////
|
||||
//// Metrics: A module offering functions for calculating distances and other types of metrics.
|
||||
////
|
||||
////
|
||||
//// * **Distances**
|
||||
//// * [`norm`](#norm)
|
||||
//// * [`manhatten_distance`](#float_manhatten_distance)
|
||||
|
@ -35,16 +35,15 @@
|
|||
//// * [`median`](#median)
|
||||
//// * [`variance`](#variance)
|
||||
//// * [`standard_deviation`](#standard_deviation)
|
||||
////
|
||||
////
|
||||
|
||||
import gleam_community/maths/elementary
|
||||
import gleam_community/maths/piecewise
|
||||
import gleam_community/maths/arithmetics
|
||||
import gleam_community/maths/predicates
|
||||
import gleam_community/maths/conversion
|
||||
import gleam/bool
|
||||
import gleam/list
|
||||
import gleam/pair
|
||||
import gleam/float
|
||||
import gleam_community/maths/arithmetics
|
||||
import gleam_community/maths/conversion
|
||||
import gleam_community/maths/elementary
|
||||
import gleam_community/maths/piecewise
|
||||
|
||||
/// <div style="text-align: right;">
|
||||
/// <a href="https://github.com/gleam-community/maths/issues">
|
||||
|
@ -130,15 +129,15 @@ pub fn norm(arr: List(Float), p: Float) -> Float {
|
|||
///
|
||||
/// pub fn example () {
|
||||
/// let assert Ok(tol) = elementary.power(-10.0, -6.0)
|
||||
///
|
||||
///
|
||||
/// // Empty lists returns 0.0
|
||||
/// metrics.float_manhatten_distance([], [])
|
||||
/// |> should.equal(Ok(0.0))
|
||||
///
|
||||
///
|
||||
/// // Differing lengths returns error
|
||||
/// metrics.manhatten_distance([], [1.0])
|
||||
/// |> should.be_error()
|
||||
///
|
||||
///
|
||||
/// let assert Ok(result) = metrics.manhatten_distance([0.0, 0.0], [1.0, 2.0])
|
||||
/// result
|
||||
/// |> predicates.is_close(3.0, 0.0, tol)
|
||||
|
@ -185,23 +184,23 @@ pub fn manhatten_distance(
|
|||
///
|
||||
/// pub fn example () {
|
||||
/// let assert Ok(tol) = elementary.power(-10.0, -6.0)
|
||||
///
|
||||
///
|
||||
/// // Empty lists returns 0.0
|
||||
/// metrics.minkowski_distance([], [], 1.0)
|
||||
/// |> should.equal(Ok(0.0))
|
||||
///
|
||||
///
|
||||
/// // Differing lengths returns error
|
||||
/// metrics.minkowski_distance([], [1.0], 1.0)
|
||||
/// |> should.be_error()
|
||||
///
|
||||
///
|
||||
/// // Test order < 1
|
||||
/// metrics.minkowski_distance([0.0, 0.0], [0.0, 0.0], -1.0)
|
||||
/// |> should.be_error()
|
||||
///
|
||||
///
|
||||
/// let assert Ok(result) = metrics.minkowski_distance([0.0, 0.0], [1.0, 2.0], 1.0)
|
||||
/// result
|
||||
/// |> predicates.is_close(3.0, 0.0, tol)
|
||||
/// |> should.be_true()
|
||||
/// |> should.be_true()
|
||||
/// }
|
||||
/// </details>
|
||||
///
|
||||
|
@ -262,15 +261,15 @@ pub fn minkowski_distance(
|
|||
///
|
||||
/// pub fn example () {
|
||||
/// let assert Ok(tol) = elementary.power(-10.0, -6.0)
|
||||
///
|
||||
///
|
||||
/// // Empty lists returns 0.0
|
||||
/// metrics.euclidean_distance([], [])
|
||||
/// |> should.equal(Ok(0.0))
|
||||
///
|
||||
///
|
||||
/// // Differing lengths returns error
|
||||
/// metrics.euclidean_distance([], [1.0])
|
||||
/// |> should.be_error()
|
||||
///
|
||||
///
|
||||
/// let assert Ok(result) = metrics.euclidean_distance([0.0, 0.0], [1.0, 2.0])
|
||||
/// result
|
||||
/// |> predicates.is_close(2.23606797749979, 0.0, tol)
|
||||
|
@ -303,7 +302,7 @@ pub fn euclidean_distance(
|
|||
/// \bar{x} = \frac{1}{n}\sum_{i=1}^n x_i
|
||||
/// \\]
|
||||
///
|
||||
/// In the formula, $$n$$ is the sample size (the length of the list) and
|
||||
/// 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$$.
|
||||
///
|
||||
/// <details>
|
||||
|
@ -370,7 +369,7 @@ pub fn mean(arr: List(Float)) -> Result(Float, String) {
|
|||
/// [1., 2., 3.]
|
||||
/// |> metrics.median()
|
||||
/// |> should.equal(Ok(2.))
|
||||
///
|
||||
///
|
||||
/// [1., 2., 3., 4.]
|
||||
/// |> metrics.median()
|
||||
/// |> should.equal(Ok(2.5))
|
||||
|
@ -383,33 +382,31 @@ pub fn mean(arr: List(Float)) -> Result(Float, String) {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
pub fn median(arr: List(Float)) -> Result(Float, String) {
|
||||
case arr {
|
||||
[] ->
|
||||
"Invalid input argument: The list is empty."
|
||||
|> Error
|
||||
_ -> {
|
||||
let count: Int = list.length(arr)
|
||||
let mid: Int = list.length(arr) / 2
|
||||
let sorted: List(Float) = list.sort(arr, float.compare)
|
||||
case predicates.is_odd(count) {
|
||||
// If there is an odd number of elements in the list, then the median
|
||||
// is just the middle value
|
||||
True -> {
|
||||
let assert Ok(val0) = list.at(sorted, mid)
|
||||
val0
|
||||
|> Ok
|
||||
}
|
||||
// If there is an even number of elements in the list, then the median
|
||||
// is the mean of the two middle values
|
||||
False -> {
|
||||
let assert Ok(val0) = list.at(sorted, mid - 1)
|
||||
let assert Ok(val1) = list.at(sorted, mid)
|
||||
[val0, val1]
|
||||
|> mean()
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn median(arr: List(Float)) -> Result(Float, Nil) {
|
||||
use <- bool.guard(list.is_empty(arr), Error(Nil))
|
||||
let length = list.length(arr)
|
||||
let mid = length / 2
|
||||
|
||||
case length % 2 == 0 {
|
||||
True -> do_median(arr, mid, True, 0)
|
||||
False -> do_median(arr, mid, False, 0)
|
||||
}
|
||||
}
|
||||
|
||||
fn do_median(
|
||||
xs: List(Float),
|
||||
mid: Int,
|
||||
mean: Bool,
|
||||
index: Int,
|
||||
) -> Result(Float, Nil) {
|
||||
use <- bool.guard(index > mid, Error(Nil))
|
||||
let mid_less_one = mid - 1
|
||||
|
||||
case xs {
|
||||
[x, ..] if !mean && index == mid -> Ok(x)
|
||||
[x, y, ..] if mean && index == mid_less_one -> Ok({ x +. y } /. 2.0)
|
||||
[_, ..rest] -> do_median(rest, mid, mean, index + 1)
|
||||
[] -> Error(Nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -424,9 +421,9 @@ pub fn median(arr: List(Float)) -> Result(Float, String) {
|
|||
/// 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.
|
||||
///
|
||||
|
@ -439,12 +436,12 @@ pub fn median(arr: List(Float)) -> Result(Float, String) {
|
|||
/// pub fn example () {
|
||||
/// // Degrees of freedom
|
||||
/// let ddof: Int = 1
|
||||
///
|
||||
///
|
||||
/// // An empty list returns an error
|
||||
/// []
|
||||
/// |> metrics.variance(ddof)
|
||||
/// |> should.be_error()
|
||||
///
|
||||
///
|
||||
/// // Valid input returns a result
|
||||
/// [1., 2., 3.]
|
||||
/// |> metrics.variance(ddof)
|
||||
|
@ -500,9 +497,9 @@ 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.
|
||||
///
|
||||
|
@ -515,12 +512,12 @@ pub fn variance(arr: List(Float), ddof: Int) -> Result(Float, String) {
|
|||
/// pub fn example () {
|
||||
/// // Degrees of freedom
|
||||
/// let ddof: Int = 1
|
||||
///
|
||||
///
|
||||
/// // An empty list returns an error
|
||||
/// []
|
||||
/// |> metrics.standard_deviationddof)
|
||||
/// |> should.be_error()
|
||||
///
|
||||
///
|
||||
/// // Valid input returns a result
|
||||
/// [1., 2., 3.]
|
||||
/// |> metrics.standard_deviation(ddof)
|
||||
|
@ -547,7 +544,7 @@ pub fn standard_deviation(arr: List(Float), ddof: Int) -> Result(Float, String)
|
|||
False -> {
|
||||
let assert Ok(variance) = variance(arr, ddof)
|
||||
// The computed variance will always be positive
|
||||
// So an error should never be returned
|
||||
// So an error should never be returned
|
||||
let assert Ok(stdev) = elementary.square_root(variance)
|
||||
stdev
|
||||
|> Ok
|
||||
|
|
|
@ -20,11 +20,11 @@
|
|||
////<style>
|
||||
//// .katex { font-size: 1.1em; }
|
||||
////</style>
|
||||
////
|
||||
////
|
||||
//// ---
|
||||
////
|
||||
////
|
||||
//// Piecewise: A module containing functions that have different definitions depending on conditions or intervals of their domain.
|
||||
////
|
||||
////
|
||||
//// * **Rounding functions**
|
||||
//// * [`ceiling`](#ceiling)
|
||||
//// * [`floor`](#floor)
|
||||
|
@ -52,11 +52,11 @@
|
|||
//// * [`arg_maximum`](#arg_maximum)
|
||||
////
|
||||
|
||||
import gleam/option
|
||||
import gleam/int
|
||||
import gleam/list
|
||||
import gleam/option
|
||||
import gleam/order
|
||||
import gleam/pair
|
||||
import gleam/int
|
||||
import gleam_community/maths/conversion
|
||||
import gleam_community/maths/elementary
|
||||
|
||||
|
@ -66,7 +66,7 @@ import gleam_community/maths/elementary
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// 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$$.
|
||||
/// 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) with rounding mode `RoundUp`.
|
||||
///
|
||||
|
@ -325,7 +325,7 @@ pub fn truncate(x: Float, digits: option.Option(Int)) -> Result(Float, String) {
|
|||
/// piecewise.round(12.0654, option.None, option.Some(piecewise.RoundNearest))
|
||||
/// |> should.equal(Ok(12.0))
|
||||
///
|
||||
/// // The default rounding mode is "RoundNearest" if None is provided
|
||||
/// // The default rounding mode is "RoundNearest" if None is provided
|
||||
/// piecewise.round(12.0654, option.None, option.None)
|
||||
/// |> should.equal(Ok(12.0))
|
||||
///
|
||||
|
@ -490,7 +490,7 @@ fn do_ceiling(a: Float) -> Float
|
|||
/// The absolute value:
|
||||
///
|
||||
/// \\[
|
||||
/// \forall x, y \in \mathbb{R}, \\; |x| \in \mathbb{R}_{+}.
|
||||
/// \forall x, y \in \mathbb{R}, \\; |x| \in \mathbb{R}_{+}.
|
||||
/// \\]
|
||||
///
|
||||
/// The function takes an input $$x$$ and returns a positive float value.
|
||||
|
@ -519,7 +519,7 @@ pub fn float_absolute_value(x: Float) -> Float {
|
|||
/// The absolute value:
|
||||
///
|
||||
/// \\[
|
||||
/// \forall x, y \in \mathbb{Z}, \\; |x| \in \mathbb{Z}_{+}.
|
||||
/// \forall x, y \in \mathbb{Z}, \\; |x| \in \mathbb{Z}_{+}.
|
||||
/// \\]
|
||||
///
|
||||
/// The function takes an input $$x$$ and returns a positive integer value.
|
||||
|
@ -548,7 +548,7 @@ pub fn int_absolute_value(x: Int) -> Int {
|
|||
/// The absolute difference:
|
||||
///
|
||||
/// \\[
|
||||
/// \forall x, y \in \mathbb{R}, \\; |x - y| \in \mathbb{R}_{+}.
|
||||
/// \forall x, y \in \mathbb{R}, \\; |x - y| \in \mathbb{R}_{+}.
|
||||
/// \\]
|
||||
///
|
||||
/// The function takes two inputs $$x$$ and $$y$$ and returns a positive float
|
||||
|
@ -589,7 +589,7 @@ pub fn float_absolute_difference(a: Float, b: Float) -> Float {
|
|||
/// The absolute difference:
|
||||
///
|
||||
/// \\[
|
||||
/// \forall x, y \in \mathbb{Z}, \\; |x - y| \in \mathbb{Z}_{+}.
|
||||
/// \forall x, y \in \mathbb{Z}, \\; |x - y| \in \mathbb{Z}_{+}.
|
||||
/// \\]
|
||||
///
|
||||
/// The function takes two inputs $$x$$ and $$y$$ and returns a positive integer value which is the the absolute difference of the inputs.
|
||||
|
@ -627,7 +627,7 @@ pub fn int_absolute_difference(a: Int, b: Int) -> Int {
|
|||
/// </div>
|
||||
///
|
||||
/// The function takes an input $$x \in \mathbb{R}$$ and returns the sign of
|
||||
/// the input, indicating whether it is positive (+1.0), negative (-1.0), or
|
||||
/// the input, indicating whether it is positive (+1.0), negative (-1.0), or
|
||||
/// zero (0.0).
|
||||
///
|
||||
/// <div style="text-align: right;">
|
||||
|
@ -871,7 +871,7 @@ pub fn maximum(x: a, y: a, compare: fn(a, a) -> order.Order) -> a {
|
|||
/// </div>
|
||||
///
|
||||
/// The minmax function takes two arguments $$x, y$$ along with a function
|
||||
/// for comparing $$x, y$$. The function returns a tuple with the smallest
|
||||
/// for comparing $$x, y$$. The function returns a tuple with the smallest
|
||||
/// value first and largest second.
|
||||
///
|
||||
/// <details>
|
||||
|
@ -906,7 +906,7 @@ pub fn minmax(x: a, y: a, compare: fn(a, a) -> order.Order) -> #(a, a) {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Returns the minimum value of a given list.
|
||||
/// Returns the minimum value of a given list.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
@ -920,7 +920,7 @@ pub fn minmax(x: a, y: a, compare: fn(a, a) -> order.Order) -> #(a, a) {
|
|||
/// []
|
||||
/// |> piecewise.list_minimum(int.compare)
|
||||
/// |> should.be_error()
|
||||
///
|
||||
///
|
||||
/// // Valid input returns a result
|
||||
/// [4, 4, 3, 2, 1]
|
||||
/// |> piecewise.list_minimum(int.compare)
|
||||
|
@ -941,17 +941,15 @@ pub fn list_minimum(
|
|||
[] ->
|
||||
"Invalid input argument: The list is empty."
|
||||
|> Error
|
||||
_ -> {
|
||||
let assert Ok(val0) = list.at(arr, 0)
|
||||
arr
|
||||
|> list.fold(val0, fn(acc: a, element: a) {
|
||||
case compare(element, acc) {
|
||||
order.Lt -> element
|
||||
_ -> acc
|
||||
}
|
||||
})
|
||||
|> Ok
|
||||
}
|
||||
[x, ..rest] ->
|
||||
Ok(
|
||||
list.fold(rest, x, fn(acc: a, element: a) {
|
||||
case compare(element, acc) {
|
||||
order.Lt -> element
|
||||
_ -> acc
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -961,7 +959,7 @@ pub fn list_minimum(
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Returns the maximum value of a given list.
|
||||
/// Returns the maximum value of a given list.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
@ -997,17 +995,15 @@ pub fn list_maximum(
|
|||
[] ->
|
||||
"Invalid input argument: The list is empty."
|
||||
|> Error
|
||||
_ -> {
|
||||
let assert Ok(val0) = list.at(arr, 0)
|
||||
arr
|
||||
|> list.fold(val0, fn(acc: a, element: a) {
|
||||
case compare(acc, element) {
|
||||
order.Lt -> element
|
||||
_ -> acc
|
||||
}
|
||||
})
|
||||
|> Ok
|
||||
}
|
||||
[x, ..rest] ->
|
||||
Ok(
|
||||
list.fold(rest, x, fn(acc: a, element: a) {
|
||||
case compare(acc, element) {
|
||||
order.Lt -> element
|
||||
_ -> acc
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1023,7 +1019,7 @@ pub fn list_maximum(
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Returns the indices of the minimum values in a given list.
|
||||
/// Returns the indices of the minimum values in a given list.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
@ -1037,7 +1033,7 @@ pub fn list_maximum(
|
|||
/// []
|
||||
/// |> piecewise.arg_minimum(float.compare)
|
||||
/// |> should.be_error()
|
||||
///
|
||||
///
|
||||
/// // Valid input returns a result
|
||||
/// [4.0, 4.0, 3.0, 2.0, 1.0]
|
||||
/// |> piecewise.arg_minimum(float.compare)
|
||||
|
@ -1107,7 +1103,7 @@ pub fn arg_minimum(
|
|||
/// []
|
||||
/// |> piecewise.arg_maximum(float.compare)
|
||||
/// |> should.be_error()
|
||||
///
|
||||
///
|
||||
/// // Valid input returns a result
|
||||
/// [4.0, 4.0, 3.0, 2.0, 1.0]
|
||||
/// |> piecewise.arg_maximum(float.compare)
|
||||
|
@ -1163,7 +1159,7 @@ pub fn arg_maximum(
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Returns a tuple consisting of the minimum and maximum values of a given list.
|
||||
/// Returns a tuple consisting of the minimum and maximum values of a given list.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
@ -1177,7 +1173,7 @@ pub fn arg_maximum(
|
|||
/// []
|
||||
/// |> piecewise.extrema(float.compare)
|
||||
/// |> should.be_error()
|
||||
///
|
||||
///
|
||||
/// // Valid input returns a result
|
||||
/// [4.0, 4.0, 3.0, 2.0, 1.0]
|
||||
/// |> piecewise.extrema(float.compare)
|
||||
|
@ -1199,21 +1195,18 @@ pub fn extrema(
|
|||
[] ->
|
||||
"Invalid input argument: The list is empty."
|
||||
|> Error
|
||||
_ -> {
|
||||
let assert Ok(val_max) = list.at(arr, 0)
|
||||
let assert Ok(val_min) = list.at(arr, 0)
|
||||
arr
|
||||
|> list.fold(#(val_min, val_max), fn(acc: #(a, a), element: a) {
|
||||
let first: a = pair.first(acc)
|
||||
let second: a = pair.second(acc)
|
||||
case compare(element, first), compare(second, element) {
|
||||
order.Lt, order.Lt -> #(element, element)
|
||||
order.Lt, _ -> #(element, second)
|
||||
_, order.Lt -> #(first, element)
|
||||
_, _ -> #(first, second)
|
||||
}
|
||||
})
|
||||
|> Ok
|
||||
}
|
||||
[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)
|
||||
case compare(element, first), compare(second, element) {
|
||||
order.Lt, order.Lt -> #(element, element)
|
||||
order.Lt, _ -> #(element, second)
|
||||
_, order.Lt -> #(first, element)
|
||||
_, _ -> #(first, second)
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue