mirror of
https://github.com/sigmasternchen/gleam-community-maths
synced 2025-03-15 07:59:01 +00:00
Merge branch 'main' into list-at-hotfix
This commit is contained in:
commit
725f437135
12 changed files with 1843 additions and 292 deletions
|
@ -1,6 +1,6 @@
|
|||
////<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.css" integrity="sha384-GvrOXuhMATgEsSwCs4smul74iXGOixntILdUW9XmUC6+HX0sLNAK3q71HotJqlAn" crossorigin="anonymous">
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.js" integrity="sha384-cpW21h6RZv/phavutF+AuVYrr+dA8xD9zs6FwLpaCct6O9ctzYFfFr4dgmgccOTx" crossorigin="anonymous"></script>
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"></script>
|
||||
////<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.css" integrity="sha384-wcIxkf4k558AjM3Yz3BBFQUbk/zgIYC2R0QpeeYb+TwlBVMrlgLqwRjRtGZiK7ww" crossorigin="anonymous">
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.js" integrity="sha384-hIoBPJpTUs74ddyc4bFZSM1TVlQDA60VBbJS0oA934VSz82sBx1X7kSx2ATBDIyd" crossorigin="anonymous"></script>
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/contrib/auto-render.min.js" integrity="sha384-43gviWU0YVjaDtb/GhzOouOXtZMP/7XUzwPTstBeZFe/+rCMvRwr4yROQP43s0Xk" crossorigin="anonymous"></script>
|
||||
////<script>
|
||||
//// document.addEventListener("DOMContentLoaded", function() {
|
||||
//// renderMathInElement(document.body, {
|
||||
|
@ -44,6 +44,9 @@
|
|||
|
||||
import gleam/int
|
||||
import gleam/list
|
||||
import gleam/option
|
||||
import gleam/pair
|
||||
import gleam/result
|
||||
import gleam_community/maths/conversion
|
||||
import gleam_community/maths/elementary
|
||||
import gleam_community/maths/piecewise
|
||||
|
@ -54,8 +57,9 @@ import gleam_community/maths/piecewise
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// The function calculates the greatest common multiple of two integers $$x, y \in \mathbb{Z}$$.
|
||||
/// The greatest common multiple is the largest positive integer that is divisible by both $$x$$ and $$y$$.
|
||||
/// 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$$.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
@ -64,10 +68,10 @@ import gleam_community/maths/piecewise
|
|||
/// import gleam_community/maths/arithmetics
|
||||
///
|
||||
/// pub fn example() {
|
||||
/// arithmetics.lcm(1, 1)
|
||||
/// arithmetics.gcd(1, 1)
|
||||
/// |> should.equal(1)
|
||||
///
|
||||
/// arithmetics.lcm(100, 10)
|
||||
/// arithmetics.gcd(100, 10)
|
||||
/// |> should.equal(10)
|
||||
///
|
||||
/// arithmetics.gcd(-36, -17)
|
||||
|
@ -104,8 +108,9 @@ fn do_gcd(x: Int, y: Int) -> Int {
|
|||
/// </div>
|
||||
///
|
||||
///
|
||||
/// 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 division of $$x$$ by $$y$$, such that:
|
||||
/// 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
|
||||
/// division of $$x$$ by $$y$$, such that:
|
||||
///
|
||||
/// \\[
|
||||
/// x = q \cdot y + r \quad \text{and} \quad 0 \leq r < |y|,
|
||||
|
@ -113,13 +118,15 @@ fn do_gcd(x: Int, y: Int) -> Int {
|
|||
///
|
||||
/// 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 positive outcome, ensuring consistency with mathematical conventions.
|
||||
/// 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`.
|
||||
/// Note that like the Gleam division operator `/` this will return `0` if one of
|
||||
/// the arguments is `0`.
|
||||
///
|
||||
///
|
||||
/// <details>
|
||||
|
@ -161,8 +168,9 @@ pub fn int_euclidean_modulo(x: Int, y: Int) -> Int {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// 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.
|
||||
/// 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.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
@ -200,7 +208,8 @@ pub fn lcm(x: Int, y: Int) -> Int {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// The function returns all the positive divisors of an integer, including the number iteself.
|
||||
/// The function returns all the positive divisors of an integer, including the
|
||||
/// number itself.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
@ -251,7 +260,8 @@ fn find_divisors(n: Int) -> List(Int) {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// The function returns all the positive divisors of an integer, excluding the number iteself.
|
||||
/// The function returns all the positive divisors of an integer, excluding the
|
||||
/// number iteself.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
@ -289,29 +299,32 @@ pub fn proper_divisors(n: Int) -> List(Int) {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Calculcate the sum of the elements in a list:
|
||||
/// Calculate the (weighted) sum of the elements in a list:
|
||||
///
|
||||
/// \\[
|
||||
/// \sum_{i=1}^n x_i
|
||||
/// \sum_{i=1}^n w_i x_i
|
||||
/// \\]
|
||||
///
|
||||
/// 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$$.
|
||||
/// 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).
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
///
|
||||
/// import gleeunit/should
|
||||
/// import gleam/option
|
||||
/// import gleam_community/maths/arithmetics
|
||||
///
|
||||
/// pub fn example () {
|
||||
/// // An empty list returns an error
|
||||
/// []
|
||||
/// |> arithmetics.float_sum()
|
||||
/// |> arithmetics.float_sum(option.None)
|
||||
/// |> should.equal(0.0)
|
||||
///
|
||||
/// // Valid input returns a result
|
||||
/// [1.0, 2.0, 3.0]
|
||||
/// |> arithmetics.float_sum()
|
||||
/// |> arithmetics.float_sum(option.None)
|
||||
/// |> should.equal(6.0)
|
||||
/// }
|
||||
/// </details>
|
||||
|
@ -322,12 +335,18 @@ pub fn proper_divisors(n: Int) -> List(Int) {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
pub fn float_sum(arr: List(Float)) -> Float {
|
||||
case arr {
|
||||
[] -> 0.0
|
||||
_ ->
|
||||
pub fn float_sum(arr: List(Float), weights: option.Option(List(Float))) -> Float {
|
||||
case arr, weights {
|
||||
[], _ -> 0.0
|
||||
_, option.None ->
|
||||
arr
|
||||
|> list.fold(0.0, fn(acc: Float, a: Float) -> Float { a +. acc })
|
||||
_, option.Some(warr) -> {
|
||||
list.zip(arr, warr)
|
||||
|> list.fold(0.0, fn(acc: Float, a: #(Float, Float)) -> Float {
|
||||
pair.first(a) *. pair.second(a) +. acc
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -337,13 +356,14 @@ pub fn float_sum(arr: List(Float)) -> Float {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Calculcate the sum of the elements in a list:
|
||||
/// Calculate the sum of the elements in a list:
|
||||
///
|
||||
/// \\[
|
||||
/// \sum_{i=1}^n x_i
|
||||
/// \\]
|
||||
///
|
||||
/// 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$$.
|
||||
/// 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$$.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
@ -385,29 +405,32 @@ pub fn int_sum(arr: List(Int)) -> Int {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Calculcate the product of the elements in a list:
|
||||
/// Calculate the (weighted) product of the elements in a list:
|
||||
///
|
||||
/// \\[
|
||||
/// \prod_{i=1}^n x_i
|
||||
/// \prod_{i=1}^n x_i^{w_i}
|
||||
/// \\]
|
||||
///
|
||||
/// 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$$.
|
||||
/// 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).
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
///
|
||||
/// import gleeunit/should
|
||||
/// import gleam/option
|
||||
/// import gleam_community/maths/arithmetics
|
||||
///
|
||||
/// pub fn example () {
|
||||
/// // An empty list returns 0.0
|
||||
/// // An empty list returns 1.0
|
||||
/// []
|
||||
/// |> arithmetics.float_product()
|
||||
/// |> should.equal(0.0)
|
||||
/// |> arithmetics.float_product(option.None)
|
||||
/// |> should.equal(1.0)
|
||||
///
|
||||
/// // Valid input returns a result
|
||||
/// [1.0, 2.0, 3.0]
|
||||
/// |> arithmetics.float_product()
|
||||
/// |> arithmetics.float_product(option.None)
|
||||
/// |> should.equal(6.0)
|
||||
/// }
|
||||
/// </details>
|
||||
|
@ -418,12 +441,36 @@ pub fn int_sum(arr: List(Int)) -> Int {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
pub fn float_product(arr: List(Float)) -> Float {
|
||||
case arr {
|
||||
[] -> 1.0
|
||||
_ ->
|
||||
pub fn float_product(
|
||||
arr: List(Float),
|
||||
weights: option.Option(List(Float)),
|
||||
) -> Result(Float, String) {
|
||||
case arr, weights {
|
||||
[], _ ->
|
||||
1.0
|
||||
|> Ok
|
||||
_, option.None ->
|
||||
arr
|
||||
|> list.fold(1.0, fn(acc: Float, a: Float) -> Float { a *. acc })
|
||||
|> Ok
|
||||
_, option.Some(warr) -> {
|
||||
let results =
|
||||
list.zip(arr, warr)
|
||||
|> list.map(fn(a: #(Float, Float)) -> Result(Float, String) {
|
||||
pair.first(a)
|
||||
|> elementary.power(pair.second(a))
|
||||
})
|
||||
|> result.all
|
||||
case results {
|
||||
Ok(prods) ->
|
||||
prods
|
||||
|> list.fold(1.0, fn(acc: Float, a: Float) -> Float { a *. acc })
|
||||
|> Ok
|
||||
Error(msg) ->
|
||||
msg
|
||||
|> Error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -433,13 +480,14 @@ pub fn float_product(arr: List(Float)) -> Float {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Calculcate the product of the elements in a list:
|
||||
/// Calculate the product of the elements in a list:
|
||||
///
|
||||
/// \\[
|
||||
/// \prod_{i=1}^n x_i
|
||||
/// \\]
|
||||
///
|
||||
/// 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$$.
|
||||
/// 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$$.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
@ -448,10 +496,10 @@ pub fn float_product(arr: List(Float)) -> Float {
|
|||
/// import gleam_community/maths/arithmetics
|
||||
///
|
||||
/// pub fn example () {
|
||||
/// // An empty list returns 0
|
||||
/// // An empty list returns 1
|
||||
/// []
|
||||
/// |> arithmetics.int_product()
|
||||
/// |> should.equal(0)
|
||||
/// |> should.equal(1)
|
||||
///
|
||||
/// // Valid input returns a result
|
||||
/// [1, 2, 3]
|
||||
|
@ -481,15 +529,16 @@ pub fn int_product(arr: List(Int)) -> Int {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Calculcate the cumulative sum of the elements in a list:
|
||||
/// Calculate the cumulative sum of the elements in a list:
|
||||
///
|
||||
/// \\[
|
||||
/// v_j = \sum_{i=1}^j x_i \\;\\; \forall j = 1,\dots, n
|
||||
/// \\]
|
||||
///
|
||||
/// 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}$$ 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.
|
||||
/// 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}$$
|
||||
/// 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.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
@ -530,15 +579,16 @@ pub fn float_cumulative_sum(arr: List(Float)) -> List(Float) {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Calculcate the cumulative sum of the elements in a list:
|
||||
/// Calculate the cumulative sum of the elements in a list:
|
||||
///
|
||||
/// \\[
|
||||
/// v_j = \sum_{i=1}^j x_i \\;\\; \forall j = 1,\dots, n
|
||||
/// \\]
|
||||
///
|
||||
/// 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}$$ 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.
|
||||
/// 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}$$
|
||||
/// 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.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
@ -579,15 +629,17 @@ pub fn int_cumulative_sum(arr: List(Int)) -> List(Int) {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Calculcate the cumulative product of the elements in a list:
|
||||
/// Calculate the cumulative product of the elements in a list:
|
||||
///
|
||||
/// \\[
|
||||
/// 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 given list.
|
||||
/// 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.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
@ -614,7 +666,7 @@ pub fn int_cumulative_sum(arr: List(Int)) -> List(Int) {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
pub fn float_cumumlative_product(arr: List(Float)) -> List(Float) {
|
||||
pub fn float_cumulative_product(arr: List(Float)) -> List(Float) {
|
||||
case arr {
|
||||
[] -> []
|
||||
_ ->
|
||||
|
@ -629,15 +681,17 @@ pub fn float_cumumlative_product(arr: List(Float)) -> List(Float) {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Calculcate the cumulative product of the elements in a list:
|
||||
/// Calculate the cumulative product of the elements in a list:
|
||||
///
|
||||
/// \\[
|
||||
/// 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 value $$v_j$$ is thus the product of the $$1$$ to $$j$$ first elements in the given list.
|
||||
/// 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.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
////<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.css" integrity="sha384-GvrOXuhMATgEsSwCs4smul74iXGOixntILdUW9XmUC6+HX0sLNAK3q71HotJqlAn" crossorigin="anonymous">
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.js" integrity="sha384-cpW21h6RZv/phavutF+AuVYrr+dA8xD9zs6FwLpaCct6O9ctzYFfFr4dgmgccOTx" crossorigin="anonymous"></script>
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"></script>
|
||||
////<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.css" integrity="sha384-wcIxkf4k558AjM3Yz3BBFQUbk/zgIYC2R0QpeeYb+TwlBVMrlgLqwRjRtGZiK7ww" crossorigin="anonymous">
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.js" integrity="sha384-hIoBPJpTUs74ddyc4bFZSM1TVlQDA60VBbJS0oA934VSz82sBx1X7kSx2ATBDIyd" crossorigin="anonymous"></script>
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/contrib/auto-render.min.js" integrity="sha384-43gviWU0YVjaDtb/GhzOouOXtZMP/7XUzwPTstBeZFe/+rCMvRwr4yROQP43s0Xk" crossorigin="anonymous"></script>
|
||||
////<script>
|
||||
//// document.addEventListener("DOMContentLoaded", function() {
|
||||
//// renderMathInElement(document.body, {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
////<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.css" integrity="sha384-GvrOXuhMATgEsSwCs4smul74iXGOixntILdUW9XmUC6+HX0sLNAK3q71HotJqlAn" crossorigin="anonymous">
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.js" integrity="sha384-cpW21h6RZv/phavutF+AuVYrr+dA8xD9zs6FwLpaCct6O9ctzYFfFr4dgmgccOTx" crossorigin="anonymous"></script>
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"></script>
|
||||
////<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.css" integrity="sha384-wcIxkf4k558AjM3Yz3BBFQUbk/zgIYC2R0QpeeYb+TwlBVMrlgLqwRjRtGZiK7ww" crossorigin="anonymous">
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.js" integrity="sha384-hIoBPJpTUs74ddyc4bFZSM1TVlQDA60VBbJS0oA934VSz82sBx1X7kSx2ATBDIyd" crossorigin="anonymous"></script>
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/contrib/auto-render.min.js" integrity="sha384-43gviWU0YVjaDtb/GhzOouOXtZMP/7XUzwPTstBeZFe/+rCMvRwr4yROQP43s0Xk" crossorigin="anonymous"></script>
|
||||
////<script>
|
||||
//// document.addEventListener("DOMContentLoaded", function() {
|
||||
//// renderMathInElement(document.body, {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
////<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.css" integrity="sha384-GvrOXuhMATgEsSwCs4smul74iXGOixntILdUW9XmUC6+HX0sLNAK3q71HotJqlAn" crossorigin="anonymous">
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.js" integrity="sha384-cpW21h6RZv/phavutF+AuVYrr+dA8xD9zs6FwLpaCct6O9ctzYFfFr4dgmgccOTx" crossorigin="anonymous"></script>
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"></script>
|
||||
////<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.css" integrity="sha384-wcIxkf4k558AjM3Yz3BBFQUbk/zgIYC2R0QpeeYb+TwlBVMrlgLqwRjRtGZiK7ww" crossorigin="anonymous">
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.js" integrity="sha384-hIoBPJpTUs74ddyc4bFZSM1TVlQDA60VBbJS0oA934VSz82sBx1X7kSx2ATBDIyd" crossorigin="anonymous"></script>
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/contrib/auto-render.min.js" integrity="sha384-43gviWU0YVjaDtb/GhzOouOXtZMP/7XUzwPTstBeZFe/+rCMvRwr4yROQP43s0Xk" crossorigin="anonymous"></script>
|
||||
////<script>
|
||||
//// document.addEventListener("DOMContentLoaded", function() {
|
||||
//// renderMathInElement(document.body, {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
////<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.css" integrity="sha384-GvrOXuhMATgEsSwCs4smul74iXGOixntILdUW9XmUC6+HX0sLNAK3q71HotJqlAn" crossorigin="anonymous">
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.js" integrity="sha384-cpW21h6RZv/phavutF+AuVYrr+dA8xD9zs6FwLpaCct6O9ctzYFfFr4dgmgccOTx" crossorigin="anonymous"></script>
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"></script>
|
||||
////<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.css" integrity="sha384-wcIxkf4k558AjM3Yz3BBFQUbk/zgIYC2R0QpeeYb+TwlBVMrlgLqwRjRtGZiK7ww" crossorigin="anonymous">
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.js" integrity="sha384-hIoBPJpTUs74ddyc4bFZSM1TVlQDA60VBbJS0oA934VSz82sBx1X7kSx2ATBDIyd" crossorigin="anonymous"></script>
|
||||
////<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/contrib/auto-render.min.js" integrity="sha384-43gviWU0YVjaDtb/GhzOouOXtZMP/7XUzwPTstBeZFe/+rCMvRwr4yROQP43s0Xk" crossorigin="anonymous"></script>
|
||||
////<script>
|
||||
//// document.addEventListener("DOMContentLoaded", function() {
|
||||
//// renderMathInElement(document.body, {
|
||||
|
@ -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 \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 \in \mathbb{Z}, \\; |x| \in \mathbb{Z}_{+}.
|
||||
/// \\]
|
||||
///
|
||||
/// The function takes an input $$x$$ and returns a positive integer value.
|
||||
|
@ -592,7 +592,8 @@ pub fn float_absolute_difference(a: Float, b: Float) -> Float {
|
|||
/// \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.
|
||||
/// The function takes two inputs $$x$$ and $$y$$ and returns a positive integer
|
||||
/// value which is the the absolute difference of the inputs.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
@ -698,7 +699,8 @@ fn do_int_sign(a: Int) -> Int
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// The function takes two arguments $$x, y \in \mathbb{R}$$ and returns $$x$$ such that it has the same sign as $$y$$.
|
||||
/// The function takes two arguments $$x, y \in \mathbb{R}$$ and returns $$x$$
|
||||
/// such that it has the same sign as $$y$$.
|
||||
///
|
||||
/// <div style="text-align: right;">
|
||||
/// <a href="#">
|
||||
|
@ -723,7 +725,8 @@ pub fn float_copy_sign(x: Float, y: Float) -> Float {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// The function takes two arguments $$x, y \in \mathbb{Z}$$ and returns $$x$$ such that it has the same sign as $$y$$.
|
||||
/// The function takes two arguments $$x, y \in \mathbb{Z}$$ and returns $$x$$
|
||||
/// such that it has the same sign as $$y$$.
|
||||
///
|
||||
/// <div style="text-align: right;">
|
||||
/// <a href="#">
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
////
|
||||
//// ---
|
||||
////
|
||||
//// Predicates: A module containing functions for testing various mathematical properties of numbers.
|
||||
//// Predicates: A module containing functions for testing various mathematical
|
||||
//// properties of numbers.
|
||||
////
|
||||
//// * **Tests**
|
||||
//// * [`is_close`](#is_close)
|
||||
|
@ -33,6 +34,7 @@
|
|||
//// * [`is_perfect`](#is_perfect)
|
||||
//// * [`is_even`](#is_even)
|
||||
//// * [`is_odd`](#is_odd)
|
||||
//// * [`is_prime`](#is_prime)
|
||||
|
||||
import gleam/pair
|
||||
import gleam/int
|
||||
|
@ -49,8 +51,9 @@ import gleam_community/maths/arithmetics
|
|||
/// </div>
|
||||
///
|
||||
/// 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 the equation:
|
||||
/// $$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
|
||||
/// the equation:
|
||||
///
|
||||
/// \\[
|
||||
/// \|a - b\| \leq (a_{tol} + r_{tol} \cdot \|b\|)
|
||||
|
@ -61,7 +64,7 @@ import gleam_community/maths/arithmetics
|
|||
/// <summary>Example</summary>
|
||||
///
|
||||
/// import gleeunit/should
|
||||
/// import gleam_community/maths/tests
|
||||
/// import gleam_community/maths/predicates
|
||||
///
|
||||
/// pub fn example () {
|
||||
/// let val: Float = 99.
|
||||
|
@ -108,14 +111,15 @@ fn float_absolute_difference(a: Float, b: Float) -> Float {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Determine if a list of values are close to or equivalent to a another list of reference values.
|
||||
/// Determine if a list of values are close to or equivalent to a another list of
|
||||
/// reference values.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
///
|
||||
/// import gleeunit/should
|
||||
/// import gleam/list
|
||||
/// import gleam_community/maths/tests
|
||||
/// import gleam_community/maths/predicates
|
||||
///
|
||||
/// pub fn example () {
|
||||
/// let val: Float = 99.
|
||||
|
@ -126,7 +130,7 @@ fn float_absolute_difference(a: Float, b: Float) -> Float {
|
|||
/// // if 'val' is within 1 percent of 'ref_val' +/- 0.1
|
||||
/// let rtol: Float = 0.01
|
||||
/// let atol: Float = 0.10
|
||||
/// tests.all_close(xarr, yarr, rtol, atol)
|
||||
/// predicates.all_close(xarr, yarr, rtol, atol)
|
||||
/// |> fn(zarr: Result(List(Bool), String)) -> Result(Bool, Nil) {
|
||||
/// case zarr {
|
||||
/// Ok(arr) ->
|
||||
|
@ -175,19 +179,20 @@ 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.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example</summary>
|
||||
///
|
||||
/// import gleeunit/should
|
||||
/// import gleam_community/maths/tests
|
||||
/// import gleam_community/maths/predicates
|
||||
///
|
||||
/// pub fn example () {
|
||||
/// tests.is_fractional(0.3333)
|
||||
/// predicates.is_fractional(0.3333)
|
||||
/// |> should.equal(True)
|
||||
///
|
||||
/// tests.is_fractional(1.0)
|
||||
/// predicates.is_fractional(1.0)
|
||||
/// |> should.equal(False)
|
||||
/// }
|
||||
/// </details>
|
||||
|
@ -212,21 +217,22 @@ fn do_ceiling(a: Float) -> Float
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// A function that tests whether a given integer value $$x \in \mathbb{Z}$$ is a power of another integer value $$y \in \mathbb{Z}$$.
|
||||
/// A function that tests whether a given integer value $$x \in \mathbb{Z}$$ is a
|
||||
/// power of another integer value $$y \in \mathbb{Z}$$.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
///
|
||||
/// import gleeunit/should
|
||||
/// import gleam_community/maths/tests
|
||||
/// import gleam_community/maths/predicates
|
||||
///
|
||||
/// pub fn example() {
|
||||
/// // Check if 4 is a power of 2 (it is)
|
||||
/// tests.is_power(4, 2)
|
||||
/// predicates.is_power(4, 2)
|
||||
/// |> should.equal(True)
|
||||
///
|
||||
/// // Check if 5 is a power of 2 (it is not)
|
||||
/// tests.is_power(5, 2)
|
||||
/// predicates.is_power(5, 2)
|
||||
/// |> should.equal(False)
|
||||
/// }
|
||||
/// </details>
|
||||
|
@ -251,7 +257,9 @@ pub fn is_power(x: Int, y: Int) -> Bool {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// 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 positive divisors.
|
||||
/// 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
|
||||
/// positive divisors.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Details</summary>
|
||||
|
@ -266,13 +274,13 @@ pub fn is_power(x: Int, y: Int) -> Bool {
|
|||
/// <summary>Example:</summary>
|
||||
///
|
||||
/// import gleeunit/should
|
||||
/// import gleam_community/maths/tests
|
||||
/// import gleam_community/maths/predicates
|
||||
///
|
||||
/// pub fn example() {
|
||||
/// tests.is_perfect(6)
|
||||
/// predicates.is_perfect(6)
|
||||
/// |> should.equal(True)
|
||||
///
|
||||
/// tests.is_perfect(28)
|
||||
/// predicates.is_perfect(28)
|
||||
/// |> should.equal(True)
|
||||
/// }
|
||||
/// </details>
|
||||
|
@ -308,13 +316,13 @@ fn do_sum(arr: List(Int)) -> Int {
|
|||
/// <summary>Example:</summary>
|
||||
///
|
||||
/// import gleeunit/should
|
||||
/// import gleam_community/maths/tests
|
||||
/// import gleam_community/maths/predicates
|
||||
///
|
||||
/// pub fn example() {
|
||||
/// tests.is_even(-3)
|
||||
/// predicates.is_even(-3)
|
||||
/// |> should.equal(False)
|
||||
///
|
||||
/// tests.is_even(-4)
|
||||
/// predicates.is_even(-4)
|
||||
/// |> should.equal(True)
|
||||
/// }
|
||||
/// </details>
|
||||
|
@ -341,13 +349,13 @@ pub fn is_even(x: Int) -> Bool {
|
|||
/// <summary>Example:</summary>
|
||||
///
|
||||
/// import gleeunit/should
|
||||
/// import gleam_community/maths/tests
|
||||
/// import gleam_community/maths/predicates
|
||||
///
|
||||
/// pub fn example() {
|
||||
/// tests.is_odd(-3)
|
||||
/// predicates.is_odd(-3)
|
||||
/// |> should.equal(True)
|
||||
///
|
||||
/// tests.is_odd(-4)
|
||||
/// predicates.is_odd(-4)
|
||||
/// |> should.equal(False)
|
||||
/// }
|
||||
/// </details>
|
||||
|
@ -361,3 +369,97 @@ pub fn is_even(x: Int) -> Bool {
|
|||
pub fn is_odd(x: Int) -> Bool {
|
||||
x % 2 != 0
|
||||
}
|
||||
|
||||
/// <div style="text-align: right;">
|
||||
/// <a href="https://github.com/gleam-community/maths/issues">
|
||||
/// <small>Spot a typo? Open an issue!</small>
|
||||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// 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
|
||||
/// as prime. However, the probability of such errors decreases with more testing
|
||||
/// iterations (the function uses 64 iterations internally, which is typically
|
||||
/// more than sufficient). The Miller-Rabin test is particularly useful for large
|
||||
/// numbers.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Details</summary>
|
||||
///
|
||||
/// 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 as $$2$$.
|
||||
///
|
||||
/// </details>
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
///
|
||||
/// import gleeunit/should
|
||||
/// import gleam_community/maths/predicates
|
||||
///
|
||||
/// pub fn example() {
|
||||
/// predicates.is_prime(2)
|
||||
/// |> should.equal(True)
|
||||
///
|
||||
/// predicates.is_prime(4)
|
||||
/// |> should.equal(False)
|
||||
///
|
||||
/// // Test the 2nd Carmichael number
|
||||
/// predicates.is_prime(1105)
|
||||
/// |> should.equal(False)
|
||||
/// }
|
||||
/// </details>
|
||||
///
|
||||
/// <div style="text-align: right;">
|
||||
/// <a href="#">
|
||||
/// <small>Back to top ↑</small>
|
||||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
pub fn is_prime(x: Int) -> Bool {
|
||||
case x {
|
||||
x if x < 2 -> {
|
||||
False
|
||||
}
|
||||
x if x == 2 -> {
|
||||
True
|
||||
}
|
||||
_ -> {
|
||||
miller_rabin_test(x, 64)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn miller_rabin_test(n: Int, k: Int) -> Bool {
|
||||
case n, k {
|
||||
_, 0 -> True
|
||||
_, _ -> {
|
||||
// Generate a random int in the range [2, n]
|
||||
let random_candidate: Int = 2 + int.random(n - 2)
|
||||
case powmod_with_check(random_candidate, n - 1, n) == 1 {
|
||||
True -> miller_rabin_test(n, k - 1)
|
||||
False -> False
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
case { x * x } % modulus, x != 1 && x != { modulus - 1 } {
|
||||
1, True -> 0
|
||||
_, _ -> { x * x } % modulus
|
||||
}
|
||||
}
|
||||
_, _ -> { base * powmod_with_check(base, exponent - 1, modulus) } % modulus
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
////
|
||||
//// ---
|
||||
////
|
||||
//// Sequences: A module containing functions for generating various types of sequences, ranges and intervals.
|
||||
//// Sequences: A module containing functions for generating various types of
|
||||
//// sequences, ranges and intervals.
|
||||
////
|
||||
//// * **Ranges and intervals**
|
||||
//// * [`arange`](#arange)
|
||||
|
@ -42,8 +43,10 @@ import gleam/list
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// The function returns a list with evenly spaced values within a given interval based on a start, stop value and a given increment (step-length) between consecutive values.
|
||||
/// The list returned includes the given start value but excludes the stop value.
|
||||
/// The function returns a list with evenly spaced values within a given interval
|
||||
/// based on a start, stop value and a given increment (step-length) between
|
||||
/// consecutive values. The list returned includes the given start value but
|
||||
/// excludes the stop value.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
@ -98,7 +101,8 @@ pub fn arange(start: Float, stop: Float, step: Float) -> List(Float) {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Generate a linearly spaced list of points over a specified interval. The endpoint of the interval can optionally be included/excluded.
|
||||
/// Generate a linearly spaced list of points over a specified interval. The
|
||||
/// endpoint of the interval can optionally be included/excluded.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
@ -176,7 +180,8 @@ pub fn linear_space(
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Generate a logarithmically spaced list of points over a specified interval. The endpoint of the interval can optionally be included/excluded.
|
||||
/// Generate a logarithmically spaced list of points over a specified interval. The
|
||||
/// endpoint of the interval can optionally be included/excluded.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
@ -236,8 +241,11 @@ pub fn logarithmic_space(
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// The function returns a list 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.
|
||||
/// The function returns a list 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.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
|
@ -283,7 +291,7 @@ pub fn geometric_space(
|
|||
) -> Result(List(Float), String) {
|
||||
case start == 0.0 || stop == 0.0 {
|
||||
True ->
|
||||
""
|
||||
"Invalid input: Neither 'start' nor 'stop' can be zero, as they must be non-zero for logarithmic calculations."
|
||||
|> Error
|
||||
False ->
|
||||
case num > 0 {
|
||||
|
|
|
@ -100,8 +100,8 @@ pub fn erf(x: Float) -> Float {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// 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 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
|
||||
/// using the same coefficients used by the GNU Scientific Library.
|
||||
|
@ -174,7 +174,7 @@ pub fn incomplete_gamma(a: Float, x: Float) -> Result(Float, String) {
|
|||
}
|
||||
|
||||
False ->
|
||||
"Invlaid input argument: a <= 0 or x < 0. Valid input is a > 0 and x >= 0."
|
||||
"Invalid input argument: a <= 0 or x < 0. Valid input is a > 0 and x >= 0."
|
||||
|> Error
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import gleam_community/maths/arithmetics
|
||||
import gleeunit/should
|
||||
import gleam/option
|
||||
|
||||
pub fn int_gcd_test() {
|
||||
arithmetics.gcd(1, 1)
|
||||
|
@ -100,16 +101,16 @@ pub fn int_divisors_test() {
|
|||
pub fn float_list_sum_test() {
|
||||
// An empty list returns 0
|
||||
[]
|
||||
|> arithmetics.float_sum()
|
||||
|> arithmetics.float_sum(option.None)
|
||||
|> should.equal(0.0)
|
||||
|
||||
// Valid input returns a result
|
||||
[1.0, 2.0, 3.0]
|
||||
|> arithmetics.float_sum()
|
||||
|> arithmetics.float_sum(option.None)
|
||||
|> should.equal(6.0)
|
||||
|
||||
[-2.0, 4.0, 6.0]
|
||||
|> arithmetics.float_sum()
|
||||
|> arithmetics.float_sum(option.None)
|
||||
|> should.equal(8.0)
|
||||
}
|
||||
|
||||
|
@ -132,17 +133,17 @@ pub fn int_list_sum_test() {
|
|||
pub fn float_list_product_test() {
|
||||
// An empty list returns 0
|
||||
[]
|
||||
|> arithmetics.float_product()
|
||||
|> should.equal(1.0)
|
||||
|> arithmetics.float_product(option.None)
|
||||
|> should.equal(Ok(1.0))
|
||||
|
||||
// Valid input returns a result
|
||||
[1.0, 2.0, 3.0]
|
||||
|> arithmetics.float_product()
|
||||
|> should.equal(6.0)
|
||||
|> arithmetics.float_product(option.None)
|
||||
|> should.equal(Ok(6.0))
|
||||
|
||||
[-2.0, 4.0, 6.0]
|
||||
|> arithmetics.float_product()
|
||||
|> should.equal(-48.0)
|
||||
|> arithmetics.float_product(option.None)
|
||||
|> should.equal(Ok(-48.0))
|
||||
}
|
||||
|
||||
pub fn int_list_product_test() {
|
||||
|
@ -196,16 +197,16 @@ pub fn int_list_cumulative_sum_test() {
|
|||
pub fn float_list_cumulative_product_test() {
|
||||
// An empty lists returns an empty list
|
||||
[]
|
||||
|> arithmetics.float_cumumlative_product()
|
||||
|> arithmetics.float_cumulative_product()
|
||||
|> should.equal([])
|
||||
|
||||
// Valid input returns a result
|
||||
[1.0, 2.0, 3.0]
|
||||
|> arithmetics.float_cumumlative_product()
|
||||
|> arithmetics.float_cumulative_product()
|
||||
|> should.equal([1.0, 2.0, 6.0])
|
||||
|
||||
[-2.0, 4.0, 6.0]
|
||||
|> arithmetics.float_cumumlative_product()
|
||||
|> arithmetics.float_cumulative_product()
|
||||
|> should.equal([-2.0, -8.0, -48.0])
|
||||
}
|
||||
|
||||
|
|
|
@ -2,160 +2,292 @@ import gleam_community/maths/elementary
|
|||
import gleam_community/maths/metrics
|
||||
import gleam_community/maths/predicates
|
||||
import gleeunit/should
|
||||
import gleam/set
|
||||
import gleam/option
|
||||
|
||||
pub fn float_list_norm_test() {
|
||||
let assert Ok(tol) = elementary.power(-10.0, -6.0)
|
||||
|
||||
// An empty lists returns 0.0
|
||||
[]
|
||||
|> metrics.norm(1.0)
|
||||
|> should.equal(0.0)
|
||||
|> metrics.norm(1.0, option.None)
|
||||
|> should.equal(Ok(0.0))
|
||||
|
||||
// Check that the function agrees, at some arbitrary input
|
||||
// points, with known function values
|
||||
[1.0, 1.0, 1.0]
|
||||
|> metrics.norm(1.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()
|
||||
|
||||
[1.0, 1.0, 1.0]
|
||||
|> metrics.norm(-1.0)
|
||||
let assert Ok(result) =
|
||||
[1.0, 1.0, 1.0]
|
||||
|> metrics.norm(-1.0, option.None)
|
||||
result
|
||||
|> predicates.is_close(0.3333333333333333, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
[-1.0, -1.0, -1.0]
|
||||
|> metrics.norm(-1.0)
|
||||
let assert Ok(result) =
|
||||
[-1.0, -1.0, -1.0]
|
||||
|> metrics.norm(-1.0, option.None)
|
||||
result
|
||||
|> predicates.is_close(0.3333333333333333, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
[-1.0, -1.0, -1.0]
|
||||
|> metrics.norm(1.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()
|
||||
|
||||
[-1.0, -2.0, -3.0]
|
||||
|> metrics.norm(-10.0)
|
||||
let assert Ok(result) =
|
||||
[-1.0, -2.0, -3.0]
|
||||
|> metrics.norm(-10.0, option.None)
|
||||
result
|
||||
|> predicates.is_close(0.9999007044905545, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
[-1.0, -2.0, -3.0]
|
||||
|> metrics.norm(-100.0)
|
||||
let assert Ok(result) =
|
||||
[-1.0, -2.0, -3.0]
|
||||
|> metrics.norm(-100.0, option.None)
|
||||
result
|
||||
|> predicates.is_close(1.0, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
[-1.0, -2.0, -3.0]
|
||||
|> metrics.norm(2.0)
|
||||
let assert Ok(result) =
|
||||
[-1.0, -2.0, -3.0]
|
||||
|> metrics.norm(2.0, option.None)
|
||||
result
|
||||
|> predicates.is_close(3.7416573867739413, 0.0, tol)
|
||||
|> should.be_true()
|
||||
}
|
||||
|
||||
pub fn float_list_manhatten_test() {
|
||||
pub fn float_list_manhattan_test() {
|
||||
let assert Ok(tol) = elementary.power(-10.0, -6.0)
|
||||
|
||||
// Empty lists returns 0.0
|
||||
metrics.manhatten_distance([], [])
|
||||
|> should.equal(Ok(0.0))
|
||||
|
||||
// Differing lengths returns error
|
||||
metrics.manhatten_distance([], [1.0])
|
||||
// Empty lists returns an error
|
||||
metrics.manhattan_distance([], [], option.None)
|
||||
|> should.be_error()
|
||||
|
||||
// Manhatten distance (p = 1)
|
||||
let assert Ok(result) = metrics.manhatten_distance([0.0, 0.0], [1.0, 2.0])
|
||||
// Differing lengths returns error
|
||||
metrics.manhattan_distance([], [1.0], option.None)
|
||||
|> should.be_error()
|
||||
|
||||
// Try with valid input (same as Minkowski distance with p = 1)
|
||||
let assert Ok(result) =
|
||||
metrics.manhattan_distance([0.0, 0.0], [1.0, 2.0], option.None)
|
||||
result
|
||||
|> predicates.is_close(3.0, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
metrics.manhattan_distance([1.0, 2.0, 3.0], [4.0, 5.0, 6.0], option.None)
|
||||
|> should.equal(Ok(9.0))
|
||||
|
||||
metrics.manhattan_distance(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
option.Some([1.0, 1.0, 1.0]),
|
||||
)
|
||||
|> should.equal(Ok(9.0))
|
||||
|
||||
metrics.manhattan_distance(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
option.Some([1.0, 2.0, 3.0]),
|
||||
)
|
||||
|> should.equal(Ok(18.0))
|
||||
|
||||
// Try invalid input with weights (different sized lists returns an error)
|
||||
metrics.manhattan_distance(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
option.Some([7.0, 8.0]),
|
||||
)
|
||||
|> should.be_error()
|
||||
|
||||
// Try invalid input with weights that are negative
|
||||
metrics.manhattan_distance(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
option.Some([-7.0, -8.0, -9.0]),
|
||||
)
|
||||
|> should.be_error()
|
||||
}
|
||||
|
||||
// pub fn int_list_manhatten_test() {
|
||||
// // Empty lists returns 0
|
||||
// metrics.int_manhatten_distance([], [])
|
||||
// |> should.equal(Ok(0))
|
||||
|
||||
// // Differing lengths returns error
|
||||
// metrics.int_manhatten_distance([], [1])
|
||||
// |> should.be_error()
|
||||
|
||||
// let assert Ok(result) = metrics.int_manhatten_distance([0, 0], [1, 2])
|
||||
// result
|
||||
// |> should.equal(3)
|
||||
// }
|
||||
|
||||
pub fn float_list_minkowski_test() {
|
||||
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))
|
||||
// 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)
|
||||
metrics.minkowski_distance([], [1.0], 1.0, option.None)
|
||||
|> should.be_error()
|
||||
|
||||
// Test order < 1
|
||||
metrics.minkowski_distance([0.0, 0.0], [0.0, 0.0], -1.0)
|
||||
metrics.minkowski_distance([0.0, 0.0], [0.0, 0.0], -1.0, option.None)
|
||||
|> should.be_error()
|
||||
|
||||
// Check that the function agrees, at some arbitrary input
|
||||
// points, with known function values
|
||||
let assert Ok(result) =
|
||||
metrics.minkowski_distance([1.0, 1.0], [1.0, 1.0], 1.0)
|
||||
metrics.minkowski_distance([1.0, 1.0], [1.0, 1.0], 1.0, option.None)
|
||||
result
|
||||
|> predicates.is_close(0.0, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
let assert Ok(result) =
|
||||
metrics.minkowski_distance([0.0, 0.0], [1.0, 1.0], 10.0)
|
||||
metrics.minkowski_distance([0.0, 0.0], [1.0, 1.0], 10.0, option.None)
|
||||
result
|
||||
|> predicates.is_close(1.0717734625362931, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
let assert Ok(result) =
|
||||
metrics.minkowski_distance([0.0, 0.0], [1.0, 1.0], 100.0)
|
||||
metrics.minkowski_distance([0.0, 0.0], [1.0, 1.0], 100.0, option.None)
|
||||
result
|
||||
|> predicates.is_close(1.0069555500567189, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
let assert Ok(result) =
|
||||
metrics.minkowski_distance([0.0, 0.0], [1.0, 1.0], 10.0)
|
||||
metrics.minkowski_distance([0.0, 0.0], [1.0, 1.0], 10.0, option.None)
|
||||
result
|
||||
|> predicates.is_close(1.0717734625362931, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
// Euclidean distance (p = 2)
|
||||
let assert Ok(result) =
|
||||
metrics.minkowski_distance([0.0, 0.0], [1.0, 2.0], 2.0)
|
||||
metrics.minkowski_distance([0.0, 0.0], [1.0, 2.0], 2.0, option.None)
|
||||
result
|
||||
|> predicates.is_close(2.23606797749979, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
// Manhatten distance (p = 1)
|
||||
// Manhattan distance (p = 1)
|
||||
let assert Ok(result) =
|
||||
metrics.minkowski_distance([0.0, 0.0], [1.0, 2.0], 1.0)
|
||||
metrics.minkowski_distance([0.0, 0.0], [1.0, 2.0], 1.0, option.None)
|
||||
result
|
||||
|> predicates.is_close(3.0, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
// Try different valid input
|
||||
let assert Ok(result) =
|
||||
metrics.minkowski_distance(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
4.0,
|
||||
option.None,
|
||||
)
|
||||
result
|
||||
|> predicates.is_close(3.9482220388574776, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
let assert Ok(result) =
|
||||
metrics.minkowski_distance(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
4.0,
|
||||
option.Some([1.0, 1.0, 1.0]),
|
||||
)
|
||||
result
|
||||
|> predicates.is_close(3.9482220388574776, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
let assert Ok(result) =
|
||||
metrics.minkowski_distance(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
4.0,
|
||||
option.Some([1.0, 2.0, 3.0]),
|
||||
)
|
||||
result
|
||||
|> predicates.is_close(4.6952537402198615, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
// Try invalid input with weights (different sized lists returns an error)
|
||||
metrics.minkowski_distance(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
2.0,
|
||||
option.Some([7.0, 8.0]),
|
||||
)
|
||||
|> should.be_error()
|
||||
|
||||
// Try invalid input with weights that are negative
|
||||
metrics.minkowski_distance(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
2.0,
|
||||
option.Some([-7.0, -8.0, -9.0]),
|
||||
)
|
||||
|> should.be_error()
|
||||
}
|
||||
|
||||
pub fn float_list_euclidean_test() {
|
||||
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])
|
||||
// Empty lists returns an error
|
||||
metrics.euclidean_distance([], [], option.None)
|
||||
|> should.be_error()
|
||||
|
||||
// Euclidean distance (p = 2)
|
||||
let assert Ok(result) = metrics.euclidean_distance([0.0, 0.0], [1.0, 2.0])
|
||||
// Differing lengths returns error
|
||||
metrics.euclidean_distance([], [1.0], option.None)
|
||||
|> should.be_error()
|
||||
|
||||
// Try with valid input (same as Minkowski distance with p = 2)
|
||||
let assert Ok(result) =
|
||||
metrics.euclidean_distance([0.0, 0.0], [1.0, 2.0], option.None)
|
||||
result
|
||||
|> predicates.is_close(2.23606797749979, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
// Try different valid input
|
||||
let assert Ok(result) =
|
||||
metrics.euclidean_distance([1.0, 2.0, 3.0], [4.0, 5.0, 6.0], option.None)
|
||||
result
|
||||
|> predicates.is_close(5.196152422706632, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
let assert Ok(result) =
|
||||
metrics.euclidean_distance(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
option.Some([1.0, 1.0, 1.0]),
|
||||
)
|
||||
result
|
||||
|> predicates.is_close(5.196152422706632, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
let assert Ok(result) =
|
||||
metrics.euclidean_distance(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
option.Some([1.0, 2.0, 3.0]),
|
||||
)
|
||||
result
|
||||
|> predicates.is_close(7.3484692283495345, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
// Try invalid input with weights (different sized lists returns an error)
|
||||
metrics.euclidean_distance(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
option.Some([7.0, 8.0]),
|
||||
)
|
||||
|> should.be_error()
|
||||
|
||||
// Try invalid input with weights that are negative
|
||||
metrics.euclidean_distance(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
option.Some([-7.0, -8.0, -9.0]),
|
||||
)
|
||||
|> should.be_error()
|
||||
}
|
||||
|
||||
pub fn example_mean_test() {
|
||||
pub fn mean_test() {
|
||||
// An empty list returns an error
|
||||
[]
|
||||
|> metrics.mean()
|
||||
|
@ -167,7 +299,7 @@ pub fn example_mean_test() {
|
|||
|> should.equal(Ok(2.0))
|
||||
}
|
||||
|
||||
pub fn example_median_test() {
|
||||
pub fn median_test() {
|
||||
// An empty list returns an error
|
||||
[]
|
||||
|> metrics.median()
|
||||
|
@ -183,7 +315,7 @@ pub fn example_median_test() {
|
|||
|> should.equal(Ok(2.5))
|
||||
}
|
||||
|
||||
pub fn example_variance_test() {
|
||||
pub fn variance_test() {
|
||||
// Degrees of freedom
|
||||
let ddof: Int = 1
|
||||
|
||||
|
@ -198,7 +330,7 @@ pub fn example_variance_test() {
|
|||
|> should.equal(Ok(1.0))
|
||||
}
|
||||
|
||||
pub fn example_standard_deviation_test() {
|
||||
pub fn standard_deviation_test() {
|
||||
// Degrees of freedom
|
||||
let ddof: Int = 1
|
||||
|
||||
|
@ -212,3 +344,330 @@ pub fn example_standard_deviation_test() {
|
|||
|> metrics.standard_deviation(ddof)
|
||||
|> should.equal(Ok(1.0))
|
||||
}
|
||||
|
||||
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])
|
||||
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])
|
||||
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"])
|
||||
metrics.jaccard_index(set_e, set_f)
|
||||
|> should.equal(1.0 /. 7.0)
|
||||
}
|
||||
|
||||
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])
|
||||
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])
|
||||
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"])
|
||||
metrics.sorensen_dice_coefficient(set_e, set_f)
|
||||
|> should.equal(2.0 *. 1.0 /. { 4.0 +. 5.0 })
|
||||
}
|
||||
|
||||
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])
|
||||
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])
|
||||
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"])
|
||||
metrics.overlap_coefficient(set_e, set_f)
|
||||
|> should.equal(2.0 /. 4.0)
|
||||
}
|
||||
|
||||
pub fn cosine_similarity_test() {
|
||||
let assert Ok(tol) = elementary.power(-10.0, -6.0)
|
||||
|
||||
// Empty lists returns an error
|
||||
metrics.cosine_similarity([], [], option.None)
|
||||
|> should.be_error()
|
||||
|
||||
// One empty list returns an error
|
||||
metrics.cosine_similarity([1.0, 2.0, 3.0], [], option.None)
|
||||
|> should.be_error()
|
||||
|
||||
// One empty list returns an error
|
||||
metrics.cosine_similarity([], [1.0, 2.0, 3.0], option.None)
|
||||
|> should.be_error()
|
||||
|
||||
// Different sized lists returns an error
|
||||
metrics.cosine_similarity([1.0, 2.0], [1.0, 2.0, 3.0, 4.0], option.None)
|
||||
|> should.be_error()
|
||||
|
||||
// Two orthogonal vectors (represented by lists)
|
||||
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 (represented by lists)
|
||||
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 (represented by lists)
|
||||
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
|
||||
let assert Ok(result) =
|
||||
metrics.cosine_similarity([1.0, 2.0, 3.0], [4.0, 5.0, 6.0], option.None)
|
||||
result
|
||||
|> predicates.is_close(0.9746318461970762, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
// Try valid input with weights
|
||||
let assert Ok(result) =
|
||||
metrics.cosine_similarity(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
option.Some([1.0, 1.0, 1.0]),
|
||||
)
|
||||
result
|
||||
|> predicates.is_close(0.9746318461970762, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
// Try with different weights
|
||||
let assert Ok(result) =
|
||||
metrics.cosine_similarity(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
option.Some([1.0, 2.0, 3.0]),
|
||||
)
|
||||
result
|
||||
|> predicates.is_close(0.9855274566525745, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
// Try invalid input with weights (different sized lists returns an error)
|
||||
metrics.cosine_similarity(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
option.Some([7.0, 8.0]),
|
||||
)
|
||||
|> should.be_error()
|
||||
|
||||
// Try invalid input with weights that are negative
|
||||
metrics.cosine_similarity(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
option.Some([-7.0, -8.0, -9.0]),
|
||||
)
|
||||
|> should.be_error()
|
||||
}
|
||||
|
||||
pub fn chebyshev_distance_test() {
|
||||
// Empty lists returns an error
|
||||
metrics.chebyshev_distance([], [])
|
||||
|> should.be_error()
|
||||
|
||||
// One empty list returns an error
|
||||
metrics.chebyshev_distance([1.0, 2.0, 3.0], [])
|
||||
|> should.be_error()
|
||||
|
||||
// One empty list returns an error
|
||||
metrics.chebyshev_distance([], [1.0, 2.0, 3.0])
|
||||
|> should.be_error()
|
||||
|
||||
// Different sized lists returns an error
|
||||
metrics.chebyshev_distance([1.0, 2.0], [1.0, 2.0, 3.0, 4.0])
|
||||
|> should.be_error()
|
||||
|
||||
// Try different types of valid input
|
||||
metrics.chebyshev_distance([1.0, 0.0], [0.0, 2.0])
|
||||
|> should.equal(Ok(2.0))
|
||||
|
||||
metrics.chebyshev_distance([1.0, 0.0], [2.0, 0.0])
|
||||
|> should.equal(Ok(1.0))
|
||||
|
||||
metrics.chebyshev_distance([1.0, 0.0], [-2.0, 0.0])
|
||||
|> should.equal(Ok(3.0))
|
||||
|
||||
metrics.chebyshev_distance([-5.0, -10.0, -3.0], [-1.0, -12.0, -3.0])
|
||||
|> should.equal(Ok(4.0))
|
||||
|
||||
metrics.chebyshev_distance([1.0, 2.0, 3.0], [1.0, 2.0, 3.0])
|
||||
|> should.equal(Ok(0.0))
|
||||
}
|
||||
|
||||
pub fn levenshtein_distance_test() {
|
||||
// Try different types of valid input...
|
||||
|
||||
// Requires 5 insertions to transform the empty string into "hello"
|
||||
metrics.levenshtein_distance("", "hello")
|
||||
|> should.equal(5)
|
||||
// Requires 5 deletions to remove all characters from "hello" to match the empty string
|
||||
metrics.levenshtein_distance("hello", "")
|
||||
|> should.equal(5)
|
||||
|
||||
// Requires 2 deletions to remove two 'b's and 1 substitution to change 'b' to 'a'
|
||||
metrics.levenshtein_distance("bbb", "a")
|
||||
|> should.equal(3)
|
||||
// Requires 2 insertions to add two 'b's and 1 substitution to change 'a' to 'b'
|
||||
metrics.levenshtein_distance("a", "bbb")
|
||||
|> should.equal(3)
|
||||
|
||||
// No changes needed, since the strings are identical
|
||||
metrics.levenshtein_distance("hello", "hello")
|
||||
|> should.equal(0)
|
||||
|
||||
// Requires 1 substitution to change 'a' to 'u'
|
||||
metrics.levenshtein_distance("cat", "cut")
|
||||
|> should.equal(1)
|
||||
|
||||
// Requires 2 substitutions (k -> s, e -> i) and 1 insertion (g at the end)
|
||||
metrics.levenshtein_distance("kitten", "sitting")
|
||||
|> should.equal(3)
|
||||
|
||||
// Some more complex cases, involving multiple insertions, deletions, and substitutions
|
||||
metrics.levenshtein_distance("gggtatccat", "cctaggtccct")
|
||||
|> should.equal(6)
|
||||
|
||||
metrics.levenshtein_distance(
|
||||
"This is a longer string",
|
||||
"This is also a much longer string",
|
||||
)
|
||||
|> should.equal(10)
|
||||
}
|
||||
|
||||
pub fn canberra_distance_test() {
|
||||
// Empty lists returns an error
|
||||
metrics.canberra_distance([], [], option.None)
|
||||
|> should.be_error()
|
||||
|
||||
// One empty list returns an error
|
||||
metrics.canberra_distance([1.0, 2.0, 3.0], [], option.None)
|
||||
|> should.be_error()
|
||||
|
||||
// One empty list returns an error
|
||||
metrics.canberra_distance([], [1.0, 2.0, 3.0], 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()
|
||||
|
||||
// Try different types of valid input
|
||||
metrics.canberra_distance([0.0, 0.0], [0.0, 0.0], option.None)
|
||||
|> should.equal(Ok(0.0))
|
||||
|
||||
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.None)
|
||||
|> should.equal(Ok(2.0))
|
||||
|
||||
metrics.canberra_distance([1.0, 0.0], [2.0, 0.0], option.None)
|
||||
|> should.equal(Ok(1.0 /. 3.0))
|
||||
|
||||
metrics.canberra_distance([1.0, 0.0], [0.0, 2.0], option.Some([1.0, 1.0]))
|
||||
|> should.equal(Ok(2.0))
|
||||
|
||||
metrics.canberra_distance([1.0, 0.0], [0.0, 2.0], option.Some([1.0, 0.5]))
|
||||
|> should.equal(Ok(1.5))
|
||||
|
||||
metrics.canberra_distance([1.0, 0.0], [0.0, 2.0], option.Some([0.5, 0.5]))
|
||||
|> should.equal(Ok(1.0))
|
||||
|
||||
// Different sized lists (weights) returns an error
|
||||
metrics.canberra_distance(
|
||||
[1.0, 2.0, 3.0],
|
||||
[1.0, 2.0, 3.0],
|
||||
option.Some([1.0]),
|
||||
)
|
||||
|> should.be_error()
|
||||
|
||||
// Try invalid input with weights that are negative
|
||||
metrics.canberra_distance(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
option.Some([-7.0, -8.0, -9.0]),
|
||||
)
|
||||
|> should.be_error()
|
||||
}
|
||||
|
||||
pub fn braycurtis_distance_test() {
|
||||
// Empty lists returns an error
|
||||
metrics.braycurtis_distance([], [], option.None)
|
||||
|> should.be_error()
|
||||
|
||||
// One empty list returns an error
|
||||
metrics.braycurtis_distance([1.0, 2.0, 3.0], [], option.None)
|
||||
|> should.be_error()
|
||||
|
||||
// One empty list returns an error
|
||||
metrics.braycurtis_distance([], [1.0, 2.0, 3.0], 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()
|
||||
|
||||
// Try different types of valid input
|
||||
metrics.braycurtis_distance([0.0, 0.0], [0.0, 0.0], option.None)
|
||||
|> should.equal(Ok(0.0))
|
||||
|
||||
metrics.braycurtis_distance([1.0, 2.0], [-2.0, -1.0], option.None)
|
||||
|> should.equal(Ok(3.0))
|
||||
|
||||
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.None)
|
||||
|> should.equal(Ok(0.4))
|
||||
|
||||
metrics.braycurtis_distance([1.0, 2.0], [3.0, 4.0], option.Some([1.0, 1.0]))
|
||||
|> should.equal(Ok(0.4))
|
||||
|
||||
metrics.braycurtis_distance([1.0, 2.0], [3.0, 4.0], option.Some([0.5, 1.0]))
|
||||
|> should.equal(Ok(0.375))
|
||||
|
||||
metrics.braycurtis_distance([1.0, 2.0], [3.0, 4.0], option.Some([0.25, 0.25]))
|
||||
|> should.equal(Ok(0.4))
|
||||
|
||||
// Different sized lists (weights) returns an error
|
||||
metrics.braycurtis_distance(
|
||||
[1.0, 2.0, 3.0],
|
||||
[1.0, 2.0, 3.0],
|
||||
option.Some([1.0]),
|
||||
)
|
||||
|> should.be_error()
|
||||
|
||||
// Try invalid input with weights that are negative
|
||||
metrics.braycurtis_distance(
|
||||
[1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0],
|
||||
option.Some([-7.0, -8.0, -9.0]),
|
||||
)
|
||||
|> should.be_error()
|
||||
}
|
||||
|
|
|
@ -136,3 +136,41 @@ pub fn int_is_perfect_test() {
|
|||
predicates.is_perfect(13)
|
||||
|> should.equal(False)
|
||||
}
|
||||
|
||||
pub fn int_is_prime_test() {
|
||||
// Test a negative integer, i.e., not a natural number
|
||||
predicates.is_prime(-7)
|
||||
|> should.equal(False)
|
||||
|
||||
predicates.is_prime(1)
|
||||
|> should.equal(False)
|
||||
|
||||
predicates.is_prime(2)
|
||||
|> should.equal(True)
|
||||
|
||||
predicates.is_prime(3)
|
||||
|> should.equal(True)
|
||||
|
||||
predicates.is_prime(5)
|
||||
|> should.equal(True)
|
||||
|
||||
predicates.is_prime(7)
|
||||
|> should.equal(True)
|
||||
|
||||
predicates.is_prime(11)
|
||||
|> should.equal(True)
|
||||
|
||||
predicates.is_prime(42)
|
||||
|> should.equal(False)
|
||||
|
||||
predicates.is_prime(7919)
|
||||
|> should.equal(True)
|
||||
|
||||
// Test 1st Carmichael number
|
||||
predicates.is_prime(561)
|
||||
|> should.equal(False)
|
||||
|
||||
// Test 2nd Carmichael number
|
||||
predicates.is_prime(1105)
|
||||
|> should.equal(False)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue