diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 67e89ac..ef48f17 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -24,4 +24,6 @@ jobs:
- run: gleam format --check
- - run: gleam test
\ No newline at end of file
+ - run: gleam test --target=erlang
+
+ - run: gleam test --target=javscript
\ No newline at end of file
diff --git a/src/gleam_community/maths/float.gleam b/src/gleam_community/maths/float.gleam
index 83eeb6b..0df101c 100644
--- a/src/gleam_community/maths/float.gleam
+++ b/src/gleam_community/maths/float.gleam
@@ -1587,14 +1587,14 @@ pub fn nth_root(x: Float, n: Int) -> Result(Float, String) {
"Invalid input argument: x < 0. Valid input is x > 0"
|> Error
False ->
- case n >= 2 {
+ case n >= 1 {
True -> {
assert Ok(result) = power(x, 1.0 /. int.to_float(n))
result
|> Ok
}
False ->
- "Invalid input argyment: n < 2. Valid input is n >= 2."
+ "Invalid input argument: n < 1. Valid input is n >= 2."
|> Error
}
}
diff --git a/src/gleam_community/maths/float_list.gleam b/src/gleam_community/maths/float_list.gleam
index 4a76861..cf10672 100644
--- a/src/gleam_community/maths/float_list.gleam
+++ b/src/gleam_community/maths/float_list.gleam
@@ -27,11 +27,9 @@
//// * [`sum`](#sum)
//// * [`product`](#product)
//// * [`norm`](#norm)
-//// * [`minkowski`](#minkowski)
-//// * [`euclidean`](#euclidean)
-//// * [`manhatten`](#manhatten)
-//// * [`root_mean_squared_error`](#root_mean_squared_error)
-//// * [`mean_squared_error`](#mean_squared_error)
+//// * [`minkowski_distance`](#minkowski_distance)
+//// * [`euclidean_distance`](#euclidean_distance)
+//// * [`manhatten_distance`](#manhatten_distance)
//// * [`cumulative_sum`](#cumulative_sum)
//// * [`cumulative_product`](#cumulative_product)
//// * **Ranges and intervals**
@@ -53,6 +51,8 @@ import gleam/float
import gleam/pair
import gleam/option
import gleam_community/maths/float as floatx
+import gleam_community/maths/int as intx
+import gleam/io
///
/// Example:
///
@@ -77,8 +148,69 @@ import gleam_community/maths/float as floatx
///
///
///
-pub fn norm(xarr: List(Float), p: Int) -> Float {
- todo
+pub fn minkowski_distance(
+ xarr: List(Float),
+ yarr: List(Float),
+ p: Float,
+) -> Result(Float, String) {
+ let xlen: Int = list.length(xarr)
+ let ylen: Int = list.length(yarr)
+ case xlen == ylen {
+ False ->
+ "Invalid input argument: length(xarr) != length(yarr). Valid input is when length(xarr) == length(yarr)."
+ |> Error
+ True ->
+ case p <. 1.0 {
+ True ->
+ "Invalid input argument: p < 1. Valid input is p >= 1."
+ |> Error
+ False ->
+ list.zip(xarr, yarr)
+ |> list.map(fn(tuple: #(Float, Float)) -> Float {
+ pair.first(tuple) -. pair.second(tuple)
+ })
+ |> norm(p)
+ |> Ok
+ }
+ }
+}
+
+///
+///
+/// Calculcate the Euclidean distance between two lists (representing vectors):
+///
+/// \\[
+/// \left( \sum_{i=1}^n \left|x_i - x_j \right|^{p} \right)^{\frac{1}{p}}
+/// \\]
+///
+/// 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, j$$.
+///
+///
+/// Example:
+///
+/// import gleeunit/should
+/// import gleam_community/maths/float_list
+///
+/// pub fn example () {
+///
+/// }
+///
+///
+///
+///
+pub fn euclidean_distance(
+ xarr: List(Float),
+ yarr: List(Float),
+) -> Result(Float, String) {
+ minkowski_distance(xarr, yarr, 2.0)
}
///
@@ -104,116 +236,11 @@ pub fn norm(xarr: List(Float), p: Int) -> Float {
///
///
///
-pub fn minkowski(xarr: List(Float), yarr: List(Float), p: Int) -> Float {
- todo
-}
-
-///
-///
-///
-/// Example:
-///
-/// import gleeunit/should
-/// import gleam_community/maths/float_list
-///
-/// pub fn example () {
-///
-/// }
-///
-///
-///
-///
-pub fn euclidean(xarr: List(Float), yarr: List(Float)) -> Float {
- todo
-}
-
-///
-///
-///
-/// Example:
-///
-/// import gleeunit/should
-/// import gleam_community/maths/float_list
-///
-/// pub fn example () {
-///
-/// }
-///
-///
-///
-///
-pub fn manhatten(xarr: List(Float), yarr: List(Float)) -> Float {
- todo
-}
-
-///
-///
-///
-/// Example:
-///
-/// import gleeunit/should
-/// import gleam_community/maths/float_list
-///
-/// pub fn example () {
-///
-/// }
-///
-///
-///
-///
-pub fn mean_squared_error(xarr: List(Float), yarr: List(Float)) -> Float {
- todo
-}
-
-///
-///
-///
-/// Example:
-///
-/// import gleeunit/should
-/// import gleam_community/maths/float_list
-///
-/// pub fn example () {
-///
-/// }
-///
-///
-///
-///
-pub fn root_mean_squared_error(xarr: List(Float), yarr: List(Float)) -> Float {
- todo
+pub fn manhatten_distance(
+ xarr: List(Float),
+ yarr: List(Float),
+) -> Result(Float, String) {
+ minkowski_distance(xarr, yarr, 1.0)
}
///
@@ -659,7 +686,7 @@ pub fn arg_maximum(arr: List(Float)) -> Result(List(Int), String) {
arr
|> list.index_map(fn(index: Int, a: Float) -> Int {
case a -. max {
- 0. -> index
+ 0.0 -> index
_ -> -1
}
})
@@ -719,7 +746,7 @@ pub fn arg_minimum(arr: List(Float)) -> Result(List(Int), String) {
arr
|> list.index_map(fn(index: Int, a: Float) -> Int {
case a -. min {
- 0. -> index
+ 0.0 -> index
_ -> -1
}
})
diff --git a/test/gleam/gleam_community_maths_float_list_test.gleam b/test/gleam/gleam_community_maths_float_list_test.gleam
index aea7158..717f1c3 100644
--- a/test/gleam/gleam_community_maths_float_list_test.gleam
+++ b/test/gleam/gleam_community_maths_float_list_test.gleam
@@ -2,8 +2,10 @@ import gleam/int
import gleam/list
import gleam/pair
import gleam_community/maths/float_list
+import gleam_community/maths/float as floatx
import gleeunit
import gleeunit/should
+import gleam/io
pub fn main() {
gleeunit.main()
@@ -33,6 +35,98 @@ pub fn float_list_all_close_test() {
|> should.equal(Ok(True))
}
+pub fn float_list_norm_test() {
+ assert Ok(tol) = floatx.power(-10.0, -6.0)
+
+ // An empty lists returns 0.0
+ []
+ |> float_list.norm(1.0)
+ |> should.equal(0.0)
+
+ // Check that the function agrees, at some arbitrary input
+ // points, with known function values
+ [1.0, 1.0, 1.0]
+ |> float_list.norm(1.0)
+ |> floatx.is_close(3.0, 0.0, tol)
+ |> should.be_true()
+
+ [1.0, 1.0, 1.0]
+ |> float_list.norm(-1.0)
+ |> floatx.is_close(0.3333333333333333, 0.0, tol)
+ |> should.be_true()
+
+ [-1.0, -1.0, -1.0]
+ |> float_list.norm(-1.0)
+ |> floatx.is_close(0.3333333333333333, 0.0, tol)
+ |> should.be_true()
+
+ [-1.0, -1.0, -1.0]
+ |> float_list.norm(1.0)
+ |> floatx.is_close(3.0, 0.0, tol)
+ |> should.be_true()
+
+ [-1.0, -2.0, -3.0]
+ |> float_list.norm(-10.0)
+ |> floatx.is_close(0.9999007044905545, 0.0, tol)
+ |> should.be_true()
+
+ [-1.0, -2.0, -3.0]
+ |> float_list.norm(-100.0)
+ |> floatx.is_close(1.0, 0.0, tol)
+ |> should.be_true()
+
+ [-1.0, -2.0, -3.0]
+ |> float_list.norm(2.0)
+ |> floatx.is_close(3.7416573867739413, 0.0, tol)
+ |> should.be_true()
+}
+
+pub fn float_list_minkowski_test() {
+ assert Ok(tol) = floatx.power(-10.0, -6.0)
+
+ // Empty lists returns 0.0
+ float_list.minkowski_distance([], [], 1.0)
+ |> should.equal(Ok(0.0))
+
+ // Differing lenghths returns error
+ float_list.minkowski_distance([], [1.0], 1.0)
+ |> should.be_error()
+
+ // Test order < 1
+ float_list.minkowski_distance([0.0, 0.0], [0.0, 0.0], -1.0)
+ |> should.be_error()
+
+ // Check that the function agrees, at some arbitrary input
+ // points, with known function values
+ assert Ok(result) = float_list.minkowski_distance([1.0, 1.0], [1.0, 1.0], 1.0)
+ result
+ |> floatx.is_close(0.0, 0.0, tol)
+ |> should.be_true()
+
+ assert Ok(result) =
+ float_list.minkowski_distance([0.0, 0.0], [1.0, 1.0], 10.0)
+ result
+ |> floatx.is_close(1.0717734625362931, 0.0, tol)
+ |> should.be_true()
+
+ assert Ok(result) =
+ float_list.minkowski_distance([0.0, 0.0], [1.0, 1.0], 100.0)
+ result
+ |> floatx.is_close(1.0069555500567189, 0.0, tol)
+ |> should.be_true()
+
+ assert Ok(result) =
+ float_list.minkowski_distance([0.0, 0.0], [1.0, 1.0], 10.0)
+ result
+ |> floatx.is_close(1.0717734625362931, 0.0, tol)
+ |> should.be_true()
+
+ assert Ok(result) = float_list.minkowski_distance([0.0, 0.0], [1.0, 2.0], 2.0)
+ result
+ |> floatx.is_close(2.23606797749979, 0.0, tol)
+ |> should.be_true()
+}
+
pub fn float_list_maximum_test() {
// An empty lists returns an error
[]