mirror of
https://github.com/sigmasternchen/gleam-community-maths
synced 2025-03-15 07:59:01 +00:00
Allow passing weights in distance calculations
This commit is contained in:
parent
b7f7b29e48
commit
2313363a9e
11 changed files with 626 additions and 249 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, {
|
||||
|
@ -57,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>
|
||||
|
@ -67,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)
|
||||
|
@ -107,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|,
|
||||
|
@ -116,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>
|
||||
|
@ -164,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>
|
||||
|
@ -203,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>
|
||||
|
@ -254,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>
|
||||
|
@ -355,7 +362,8 @@ 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 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>
|
||||
|
@ -415,10 +423,10 @@ pub fn int_sum(arr: List(Int)) -> Int {
|
|||
/// import gleam_community/maths/arithmetics
|
||||
///
|
||||
/// pub fn example () {
|
||||
/// // An empty list returns 0.0
|
||||
/// // An empty list returns 1.0
|
||||
/// []
|
||||
/// |> arithmetics.float_product(option.None)
|
||||
/// |> should.equal(0.0)
|
||||
/// |> should.equal(1.0)
|
||||
///
|
||||
/// // Valid input returns a result
|
||||
/// [1.0, 2.0, 3.0]
|
||||
|
@ -478,7 +486,8 @@ 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 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>
|
||||
|
@ -487,10 +496,10 @@ pub fn float_product(
|
|||
/// 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]
|
||||
|
@ -526,9 +535,10 @@ pub fn int_product(arr: List(Int)) -> Int {
|
|||
/// 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>
|
||||
|
@ -575,9 +585,10 @@ pub fn float_cumulative_sum(arr: List(Float)) -> List(Float) {
|
|||
/// 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>
|
||||
|
@ -624,9 +635,11 @@ 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 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>
|
||||
|
@ -653,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 {
|
||||
[] -> []
|
||||
_ ->
|
||||
|
@ -674,9 +687,11 @@ pub fn float_cumumlative_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 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, {
|
||||
|
|
|
@ -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, {
|
||||
|
@ -61,9 +61,10 @@ import gleam/int
|
|||
import gleam/string
|
||||
import gleam/option
|
||||
|
||||
/// Utility function that checks all lists have the expected length
|
||||
/// Primarily used by all distance measures taking List(Float) as input
|
||||
fn check_lists(
|
||||
/// Utility function that checks all lists have the expected length and contents
|
||||
/// The function is primarily used by all distance measures taking 'List(Float)'
|
||||
/// as input
|
||||
fn validate_lists(
|
||||
xarr: List(Float),
|
||||
yarr: List(Float),
|
||||
weights: option.Option(List(Float)),
|
||||
|
@ -76,9 +77,9 @@ fn check_lists(
|
|||
"Invalid input argument: The list yarr is empty."
|
||||
|> Error
|
||||
_, _ -> {
|
||||
let xlen: Int = list.length(xarr)
|
||||
let ylen: Int = list.length(yarr)
|
||||
case xlen == ylen, weights {
|
||||
let xarr_length: Int = list.length(xarr)
|
||||
let yarr_length: Int = 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)."
|
||||
|> Error
|
||||
|
@ -87,11 +88,11 @@ fn check_lists(
|
|||
|> Ok
|
||||
}
|
||||
True, option.Some(warr) -> {
|
||||
let wlen: Int = list.length(warr)
|
||||
case xlen == wlen {
|
||||
True ->
|
||||
True
|
||||
|> Ok
|
||||
let warr_length: Int = list.length(warr)
|
||||
case xarr_length == warr_length {
|
||||
True -> {
|
||||
validate_weights(warr)
|
||||
}
|
||||
False ->
|
||||
"Invalid input argument: length(weights) != length(xarr) and length(weights) != length(yarr). Valid input is when length(weights) == length(xarr) == length(yarr)."
|
||||
|> Error
|
||||
|
@ -102,39 +103,58 @@ fn check_lists(
|
|||
}
|
||||
}
|
||||
|
||||
fn validate_weights(warr: List(Float)) -> Result(Bool, String) {
|
||||
// Check that all the given weights are positive
|
||||
let assert Ok(minimum) = piecewise.list_minimum(warr, float.compare)
|
||||
case minimum >=. 0.0 {
|
||||
False ->
|
||||
"Invalid input argument: One or more weights are negative. Valid input is when all weights are >= 0."
|
||||
|> Error
|
||||
True ->
|
||||
True
|
||||
|> Ok
|
||||
}
|
||||
}
|
||||
|
||||
/// <div style="text-align: right;">
|
||||
/// <a href="https://github.com/gleam-community/maths/issues">
|
||||
/// <small>Spot a typo? Open an issue!</small>
|
||||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Calculate the $$p$$-norm of a list (representing a vector):
|
||||
/// Calculate the (weighted) $$p$$-norm of a list (representing a vector):
|
||||
///
|
||||
/// \\[
|
||||
/// \left( \sum_{i=1}^n \left|x_i\right|^{p} \right)^{\frac{1}{p}}
|
||||
/// \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
|
||||
/// the input list indexed by $$i$$.
|
||||
/// 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).
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
///
|
||||
/// import gleeunit/should
|
||||
/// import gleam/option
|
||||
/// import gleam_community/maths/elementary
|
||||
/// import gleam_community/maths/metrics
|
||||
/// import gleam_community/maths/predicates
|
||||
///
|
||||
/// pub fn example () {
|
||||
/// 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)
|
||||
/// |> 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)
|
||||
/// |> metrics.norm(-1.0, option.None)
|
||||
/// result
|
||||
/// |> predicates.is_close(0.3333333333333333, 0.0, tol)
|
||||
/// |> should.be_true()
|
||||
/// }
|
||||
|
@ -146,19 +166,65 @@ fn check_lists(
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
pub fn norm(arr: List(Float), p: Float) -> Float {
|
||||
case arr {
|
||||
[] -> 0.0
|
||||
_ -> {
|
||||
let agg: Float =
|
||||
pub fn norm(
|
||||
arr: List(Float),
|
||||
p: Float,
|
||||
weights: option.Option(List(Float)),
|
||||
) -> Result(Float, String) {
|
||||
case arr, weights {
|
||||
[], _ ->
|
||||
0.0
|
||||
|> Ok
|
||||
_, option.None -> {
|
||||
let aggregate: Float =
|
||||
arr
|
||||
|> list.fold(0.0, fn(acc: Float, a: Float) -> Float {
|
||||
|> list.fold(0.0, fn(accumulator: Float, element: Float) -> Float {
|
||||
let assert Ok(result) =
|
||||
elementary.power(piecewise.float_absolute_value(a), p)
|
||||
result +. acc
|
||||
piecewise.float_absolute_value(element)
|
||||
|> elementary.power(p)
|
||||
result +. accumulator
|
||||
})
|
||||
let assert Ok(result) = elementary.power(agg, 1.0 /. p)
|
||||
let assert Ok(result) = elementary.power(aggregate, 1.0 /. p)
|
||||
result
|
||||
|> Ok
|
||||
}
|
||||
_, option.Some(warr) -> {
|
||||
let arr_length: Int = list.length(arr)
|
||||
let warr_length: Int = 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 =
|
||||
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 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
|
||||
}
|
||||
Error(msg) ->
|
||||
msg
|
||||
|> Error
|
||||
}
|
||||
}
|
||||
False -> {
|
||||
"Invalid input argument: length(weights) != length(arr). Valid input is when length(weights) == length(arr)."
|
||||
|> Error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -169,35 +235,40 @@ pub fn norm(arr: List(Float), p: Float) -> Float {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Calculate the Manhattan distance between two lists (representing vectors):
|
||||
/// Calculate the (weighted) Manhattan distance between two lists (representing
|
||||
/// vectors):
|
||||
///
|
||||
/// \\[
|
||||
/// \sum_{i=1}^n \left|x_i - y_i \right|
|
||||
/// \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$$.
|
||||
/// values in the respective input lists indexed by $$i$$, while
|
||||
/// $$w_i \in \mathbb{R}_{+}$$ is a corresponding positive weight
|
||||
/// ($$w_i = 1.0\;\forall i=1...n$$ by default).
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
///
|
||||
/// import gleeunit/should
|
||||
/// import gleam/option
|
||||
/// import gleam_community/maths/elementary
|
||||
/// import gleam_community/maths/metrics
|
||||
/// import gleam_community/maths/predicates
|
||||
///
|
||||
/// pub fn example () {
|
||||
/// pub fn example() {
|
||||
/// let assert Ok(tol) = elementary.power(-10.0, -6.0)
|
||||
///
|
||||
/// // Empty lists returns an error
|
||||
/// metrics.manhattan_distance([], [])
|
||||
/// metrics.manhattan_distance([], [], option.None)
|
||||
/// |> should.be_error()
|
||||
///
|
||||
/// // Differing lengths returns error
|
||||
/// metrics.manhattan_distance([], [1.0])
|
||||
/// 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])
|
||||
/// 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()
|
||||
|
@ -224,14 +295,17 @@ pub fn manhattan_distance(
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Calculate the Minkowski distance between two lists (representing vectors):
|
||||
/// Calculate the (weighted) Minkowski distance between two lists (representing
|
||||
/// vectors):
|
||||
///
|
||||
/// \\[
|
||||
/// \left( \sum_{i=1}^n \left|x_i - y_i \right|^{p} \right)^{\frac{1}{p}}
|
||||
/// \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
|
||||
/// and $$x_i, y_i$$ are the values in the respective input lists indexed by $$i$$.
|
||||
/// $$w_i \in \mathbb{R}_{+}$$ is a corresponding positive weight
|
||||
/// ($$w_i = 1.0\;\forall i=1...n$$ by default).
|
||||
///
|
||||
/// The Minkowski distance is a generalization of both the Euclidean distance
|
||||
/// ($$p=2$$) and the Manhattan distance ($$p = 1$$).
|
||||
|
@ -240,26 +314,28 @@ pub fn manhattan_distance(
|
|||
/// <summary>Example:</summary>
|
||||
///
|
||||
/// import gleeunit/should
|
||||
/// import gleam/option
|
||||
/// import gleam_community/maths/elementary
|
||||
/// import gleam_community/maths/metrics
|
||||
/// import gleam_community/maths/predicates
|
||||
///
|
||||
/// pub fn example () {
|
||||
/// pub fn example() {
|
||||
/// let assert Ok(tol) = elementary.power(-10.0, -6.0)
|
||||
///
|
||||
/// // Empty lists returns an error
|
||||
/// metrics.minkowski_distance([], [], 1.0)
|
||||
/// 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()
|
||||
///
|
||||
/// let assert Ok(result) = metrics.minkowski_distance([0.0, 0.0], [1.0, 2.0], 1.0)
|
||||
/// let assert Ok(result) =
|
||||
/// 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()
|
||||
|
@ -278,7 +354,7 @@ pub fn minkowski_distance(
|
|||
p: Float,
|
||||
weights: option.Option(List(Float)),
|
||||
) -> Result(Float, String) {
|
||||
case check_lists(xarr, yarr, weights) {
|
||||
case validate_lists(xarr, yarr, weights) {
|
||||
Error(msg) ->
|
||||
msg
|
||||
|> Error
|
||||
|
@ -287,16 +363,20 @@ pub fn minkowski_distance(
|
|||
True ->
|
||||
"Invalid input argument: p < 1. Valid input is p >= 1."
|
||||
|> Error
|
||||
False ->
|
||||
False -> {
|
||||
let differences: List(Float) =
|
||||
list.zip(xarr, yarr)
|
||||
|> list.map(fn(tuple: #(Float, Float)) -> Float {
|
||||
pair.first(tuple) -. pair.second(tuple)
|
||||
})
|
||||
|> norm(p)
|
||||
|
||||
let assert Ok(result) = norm(differences, p, weights)
|
||||
result
|
||||
|> Ok
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <div style="text-align: right;">
|
||||
|
@ -305,35 +385,40 @@ pub fn minkowski_distance(
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Calculate the Euclidean distance between two lists (representing vectors):
|
||||
/// Calculate the (weighted) Euclidean distance between two lists (representing
|
||||
/// vectors):
|
||||
///
|
||||
/// \\[
|
||||
/// \left( \sum_{i=1}^n \left|x_i - y_i \right|^{2} \right)^{\frac{1}{2}}
|
||||
/// \left( \sum_{i=1}^n w_{i} \left|x_i - y_i \right|^{2} \right)^{\frac{1}{2}}
|
||||
/// \\]
|
||||
///
|
||||
/// 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$$.
|
||||
/// values in the respective input lists indexed by $$i$$, while
|
||||
/// $$w_i \in \mathbb{R}_{+}$$ is a corresponding positive weight
|
||||
/// ($$w_i = 1.0\;\forall i=1...n$$ by default).
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
///
|
||||
/// import gleeunit/should
|
||||
/// import gleam/option
|
||||
/// import gleam_community/maths/elementary
|
||||
/// import gleam_community/maths/metrics
|
||||
/// import gleam_community/maths/predicates
|
||||
///
|
||||
/// pub fn example () {
|
||||
/// pub fn example() {
|
||||
/// let assert Ok(tol) = elementary.power(-10.0, -6.0)
|
||||
///
|
||||
/// // Empty lists returns an error
|
||||
/// metrics.euclidean_distance([], [])
|
||||
/// metrics.euclidean_distance([], [], option.None)
|
||||
/// |> should.be_error()
|
||||
///
|
||||
/// // Differing lengths returns an error
|
||||
/// metrics.euclidean_distance([], [1.0])
|
||||
/// 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])
|
||||
/// 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()
|
||||
|
@ -377,7 +462,7 @@ pub fn euclidean_distance(
|
|||
/// import gleam_community/maths/metrics
|
||||
/// import gleam_community/maths/predicates
|
||||
///
|
||||
/// pub fn example () {
|
||||
/// pub fn example() {
|
||||
/// // Empty lists returns an error
|
||||
/// metrics.chebyshev_distance([], [])
|
||||
/// |> should.be_error()
|
||||
|
@ -400,20 +485,17 @@ pub fn euclidean_distance(
|
|||
pub fn chebyshev_distance(
|
||||
xarr: List(Float),
|
||||
yarr: List(Float),
|
||||
weights: option.Option(List(Float)),
|
||||
) -> Result(Float, String) {
|
||||
case check_lists(xarr, yarr, weights) {
|
||||
case validate_lists(xarr, yarr, option.None) {
|
||||
Error(msg) ->
|
||||
msg
|
||||
|> Error
|
||||
Ok(_) -> {
|
||||
let differences =
|
||||
list.zip(xarr, yarr)
|
||||
|> list.map(fn(tuple: #(Float, Float)) -> Float {
|
||||
{ pair.first(tuple) -. pair.second(tuple) }
|
||||
|> piecewise.float_absolute_value()
|
||||
})
|
||||
differences
|
||||
|> piecewise.list_maximum(float.compare)
|
||||
}
|
||||
}
|
||||
|
@ -948,39 +1030,44 @@ pub fn overlap_coefficient(xset: set.Set(a), yset: set.Set(a)) -> Float {
|
|||
/// </a>
|
||||
/// </div>
|
||||
///
|
||||
/// Calculate the cosine similarity between two lists (representing vectors):
|
||||
/// Calculate the (weighted) cosine similarity between two lists (representing
|
||||
/// vectors):
|
||||
///
|
||||
/// \\[
|
||||
/// \frac{\sum_{i=1}^n x_i \cdot y_i}{\left(\sum_{i=1}^n x_i^2\right)^{\frac{1}{2}}
|
||||
/// \cdot \left(\sum_{i=1}^n y_i^2\right)^{\frac{1}{2}}}
|
||||
/// \frac{\sum_{i=1}^n w_i \cdot x_i \cdot y_i}
|
||||
/// {\left(\sum_{i=1}^n x_i^2\right)^{\frac{1}{2}}
|
||||
/// \cdot
|
||||
/// \left(\sum_{i=1}^n w_i 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$$. The numerator
|
||||
/// represents the dot product of the two vectors, while the denominator is the
|
||||
/// product of the magnitudes (Euclidean norms) of the two vectors. 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.
|
||||
/// the values in the respective input lists indexed by $$i$$, while
|
||||
/// $$w_i \in \mathbb{R}_{+}$$ is a corresponding positive weight
|
||||
/// ($$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.
|
||||
///
|
||||
/// <details>
|
||||
/// <summary>Example:</summary>
|
||||
///
|
||||
/// import gleeunit/should
|
||||
/// import gleam/option
|
||||
/// import gleam_community/maths/metrics
|
||||
///
|
||||
/// pub fn example () {
|
||||
/// pub fn example() {
|
||||
/// // Two orthogonal vectors
|
||||
/// metrics.cosine_similarity([-1.0, 1.0, 0.0], [1.0, 1.0, -1.0])
|
||||
/// 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])
|
||||
/// 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])
|
||||
/// metrics.cosine_similarity([-1.0, -2.0, -3.0], [1.0, 2.0, 3.0], option.None)
|
||||
/// |> should.equal(Ok(-1.0))
|
||||
/// }
|
||||
/// </details>
|
||||
|
@ -996,22 +1083,48 @@ pub fn cosine_similarity(
|
|||
yarr: List(Float),
|
||||
weights: option.Option(List(Float)),
|
||||
) -> Result(Float, String) {
|
||||
case check_lists(xarr, yarr, weights) {
|
||||
case validate_lists(xarr, yarr, weights) {
|
||||
Error(msg) ->
|
||||
msg
|
||||
|> Error
|
||||
Ok(_) -> {
|
||||
list.fold(
|
||||
list.zip(xarr, yarr),
|
||||
0.0,
|
||||
fn(acc: Float, a: #(Float, Float)) -> Float {
|
||||
let result: Float = pair.first(a) *. pair.second(a)
|
||||
result +. acc
|
||||
},
|
||||
)
|
||||
/. { norm(xarr, 2.0) *. norm(yarr, 2.0) }
|
||||
let zipped_arr: List(#(Float, Float)) = list.zip(xarr, yarr)
|
||||
|
||||
let numerator_elements: List(Float) =
|
||||
zipped_arr
|
||||
|> list.map(fn(tuple: #(Float, Float)) -> Float {
|
||||
pair.first(tuple) *. pair.second(tuple)
|
||||
})
|
||||
|
||||
case weights {
|
||||
option.None -> {
|
||||
let numerator: Float =
|
||||
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 = {
|
||||
xarr_norm *. yarr_norm
|
||||
}
|
||||
numerator /. denominator
|
||||
|> Ok
|
||||
}
|
||||
_ -> {
|
||||
let numerator: Float =
|
||||
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 = {
|
||||
xarr_norm *. yarr_norm
|
||||
}
|
||||
numerator /. denominator
|
||||
|> Ok
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1144,9 +1257,23 @@ fn distance_list_helper(
|
|||
/// <summary>Example:</summary>
|
||||
///
|
||||
/// import gleeunit/should
|
||||
/// import gleam/option
|
||||
/// import gleam_community/maths/metrics
|
||||
///
|
||||
/// pub fn example () {
|
||||
/// pub fn example() {
|
||||
/// // 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]))
|
||||
/// }
|
||||
/// </details>
|
||||
///
|
||||
|
@ -1162,7 +1289,7 @@ pub fn canberra_distance(
|
|||
yarr: List(Float),
|
||||
weights: option.Option(List(Float)),
|
||||
) -> Result(Float, String) {
|
||||
case check_lists(xarr, yarr, weights) {
|
||||
case validate_lists(xarr, yarr, weights) {
|
||||
Error(msg) ->
|
||||
msg
|
||||
|> Error
|
||||
|
@ -1170,6 +1297,7 @@ pub fn canberra_distance(
|
|||
let arr: List(Float) =
|
||||
list.zip(xarr, yarr)
|
||||
|> list.map(canberra_distance_helper)
|
||||
|
||||
case weights {
|
||||
option.None -> {
|
||||
arr
|
||||
|
@ -1206,9 +1334,24 @@ fn canberra_distance_helper(tuple: #(Float, Float)) -> Float {
|
|||
/// <summary>Example:</summary>
|
||||
///
|
||||
/// import gleeunit/should
|
||||
/// import gleam/option
|
||||
/// import gleam_community/maths/metrics
|
||||
///
|
||||
/// pub fn example () {
|
||||
/// pub fn example() {
|
||||
/// // 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))
|
||||
/// }
|
||||
/// </details>
|
||||
///
|
||||
|
@ -1224,7 +1367,7 @@ pub fn braycurtis_distance(
|
|||
yarr: List(Float),
|
||||
weights: option.Option(List(Float)),
|
||||
) -> Result(Float, String) {
|
||||
case check_lists(xarr, yarr, weights) {
|
||||
case validate_lists(xarr, yarr, weights) {
|
||||
Error(msg) ->
|
||||
msg
|
||||
|> Error
|
||||
|
|
|
@ -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, {
|
||||
|
|
|
@ -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)
|
||||
|
@ -50,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\|)
|
||||
|
@ -109,7 +111,8 @@ 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>
|
||||
|
@ -176,7 +179,8 @@ 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>
|
||||
|
@ -213,7 +217,8 @@ 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>
|
||||
|
@ -252,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>
|
||||
|
@ -369,13 +376,16 @@ pub fn is_odd(x: Int) -> Bool {
|
|||
/// </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.
|
||||
/// 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.
|
||||
/// 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>
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -197,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])
|
||||
}
|
||||
|
||||
|
|
|
@ -10,43 +10,57 @@ pub fn float_list_norm_test() {
|
|||
|
||||
// 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
|
||||
let assert Ok(result) =
|
||||
[1.0, 1.0, 1.0]
|
||||
|> metrics.norm(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)
|
||||
|> metrics.norm(-1.0, option.None)
|
||||
result
|
||||
|> predicates.is_close(0.3333333333333333, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
let assert Ok(result) =
|
||||
[-1.0, -1.0, -1.0]
|
||||
|> metrics.norm(-1.0)
|
||||
|> metrics.norm(-1.0, option.None)
|
||||
result
|
||||
|> predicates.is_close(0.3333333333333333, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
let assert Ok(result) =
|
||||
[-1.0, -1.0, -1.0]
|
||||
|> metrics.norm(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, -2.0, -3.0]
|
||||
|> metrics.norm(-10.0)
|
||||
|> metrics.norm(-10.0, option.None)
|
||||
result
|
||||
|> predicates.is_close(0.9999007044905545, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
let assert Ok(result) =
|
||||
[-1.0, -2.0, -3.0]
|
||||
|> metrics.norm(-100.0)
|
||||
|> metrics.norm(-100.0, option.None)
|
||||
result
|
||||
|> predicates.is_close(1.0, 0.0, tol)
|
||||
|> should.be_true()
|
||||
|
||||
let assert Ok(result) =
|
||||
[-1.0, -2.0, -3.0]
|
||||
|> metrics.norm(2.0)
|
||||
|> metrics.norm(2.0, option.None)
|
||||
result
|
||||
|> predicates.is_close(3.7416573867739413, 0.0, tol)
|
||||
|> should.be_true()
|
||||
}
|
||||
|
@ -62,12 +76,45 @@ pub fn float_list_manhattan_test() {
|
|||
metrics.manhattan_distance([], [1.0], option.None)
|
||||
|> should.be_error()
|
||||
|
||||
// manhattan distance (p = 1)
|
||||
// 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 float_list_minkowski_test() {
|
||||
|
@ -124,6 +171,58 @@ pub fn float_list_minkowski_test() {
|
|||
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() {
|
||||
|
@ -137,12 +236,55 @@ pub fn float_list_euclidean_test() {
|
|||
metrics.euclidean_distance([], [1.0], option.None)
|
||||
|> should.be_error()
|
||||
|
||||
// Euclidean distance (p = 2)
|
||||
// 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 mean_test() {
|
||||
|
@ -268,6 +410,8 @@ pub fn overlap_coefficient_test() {
|
|||
}
|
||||
|
||||
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()
|
||||
|
@ -295,43 +439,84 @@ pub fn cosine_similarity_test() {
|
|||
// 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([], [], option.None)
|
||||
metrics.chebyshev_distance([], [])
|
||||
|> should.be_error()
|
||||
|
||||
// One empty list returns an error
|
||||
metrics.chebyshev_distance([1.0, 2.0, 3.0], [], option.None)
|
||||
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], option.None)
|
||||
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], option.None)
|
||||
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], option.None)
|
||||
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], option.None)
|
||||
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], option.None)
|
||||
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],
|
||||
option.None,
|
||||
)
|
||||
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], option.None)
|
||||
metrics.chebyshev_distance([1.0, 2.0, 3.0], [1.0, 2.0, 3.0])
|
||||
|> should.equal(Ok(0.0))
|
||||
}
|
||||
|
||||
|
@ -421,6 +606,14 @@ pub fn canberra_distance_test() {
|
|||
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() {
|
||||
|
@ -469,4 +662,12 @@ pub fn braycurtis_distance_test() {
|
|||
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()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue