diff --git a/src/gleam_community/maths.gleam b/src/gleam_community/maths.gleam index b5a76a4..1e95fbd 100644 --- a/src/gleam_community/maths.gleam +++ b/src/gleam_community/maths.gleam @@ -110,13 +110,13 @@ fn do_gcd(x: Int, y: Int) -> Int { /// import gleam_community/maths /// /// pub fn example() { -/// maths.int_euclidean_modulo(15, 4) +/// maths.euclidean_modulo(15, 4) /// |> should.equal(3) /// -/// maths.int_euclidean_modulo(-3, -2) +/// maths.euclidean_modulo(-3, -2) /// |> should.equal(1) /// -/// maths.int_euclidean_modulo(5, 0) +/// maths.euclidean_modulo(5, 0) /// |> should.equal(0) /// } /// @@ -127,7 +127,7 @@ fn do_gcd(x: Int, y: Int) -> Int { /// /// /// -pub fn int_euclidean_modulo(x: Int, y: Int) -> Int { +pub fn euclidean_modulo(x: Int, y: Int) -> Int { case x % y, x, y { _, 0, _ -> 0 _, _, 0 -> 0 @@ -302,15 +302,15 @@ pub fn proper_divisors(n: Int) -> List(Int) { /// /// pub fn example () { /// [] -/// |> maths.float_weighted_sum() +/// |> maths.weighted_sum() /// |> should.equal(Ok(0.0)) /// /// [#(1.0, 1.0), #(2.0, 1.0), #(3.0, 1.0)] -/// |> maths.float_weighted_sum() +/// |> maths.weighted_sum() /// |> should.equal(Ok(6.0)) /// /// [#(9.0, 0.5), #(10.0, 0.5), #(10.0, 0.5)] -/// |> maths.float_weighted_sum() +/// |> maths.weighted_sum() /// |> should.equal(Ok(14.5)) /// } /// @@ -321,12 +321,11 @@ pub fn proper_divisors(n: Int) -> List(Int) { /// /// /// -pub fn float_weighted_sum(arr: List(#(Float, Float))) -> Result(Float, Nil) { +pub fn weighted_sum(arr: List(#(Float, Float))) -> Result(Float, Nil) { case arr { [] -> Ok(0.0) _ -> { - let weight_is_negative = - list.any(arr, fn(tuple: #(Float, Float)) { tuple.1 <. 0.0 }) + let weight_is_negative = list.any(arr, fn(tuple) { tuple.1 <. 0.0 }) case weight_is_negative { True -> Error(Nil) False -> { @@ -364,17 +363,17 @@ pub fn float_weighted_sum(arr: List(#(Float, Float))) -> Result(Float, Nil) { /// /// pub fn example () { /// [] -/// |> maths.float_weighted_product() +/// |> maths.weighted_product() /// |> should.equal(Ok(1.0)) /// /// [#(1.0, 1.0), #(2.0, 1.0), #(3.0, 1.0)] -/// |> maths.float_weighted_product() +/// |> maths.weighted_product() /// |> should.equal(Ok(6.0)) /// /// let assert Ok(tolerance) = float.power(10.0, -6.0) /// let assert Ok(result) = /// [#(9.0, 0.5), #(10.0, 0.5), #(10.0, 0.5)] -/// |> maths.float_weighted_product() +/// |> maths.weighted_product() /// result /// |> maths.is_close(30.0, 0.0, tolerance) /// |> should.be_true() @@ -387,22 +386,18 @@ pub fn float_weighted_sum(arr: List(#(Float, Float))) -> Result(Float, Nil) { /// /// /// -pub fn float_weighted_product(arr: List(#(Float, Float))) -> Result(Float, Nil) { +pub fn weighted_product(arr: List(#(Float, Float))) -> Result(Float, Nil) { case arr { [] -> Ok(1.0) _ -> { - let weight_is_negative = - list.any(arr, fn(tuple: #(Float, Float)) { tuple.1 <. 0.0 }) + let weight_is_negative = list.any(arr, fn(tuple) { tuple.1 <. 0.0 }) case weight_is_negative { True -> Error(Nil) False -> { - list.map(arr, fn(a: #(Float, Float)) -> Result(Float, Nil) { - float.power(a.0, a.1) - }) - |> result.all - |> result.map(fn(prods) { - prods - |> list.fold(1.0, fn(acc: Float, a: Float) -> Float { a *. acc }) + list.map(arr, fn(tuple) { float.power(tuple.0, tuple.1) }) + |> result.all() + |> result.map(fn(products) { + list.fold(products, 1.0, fn(acc, element) { element *. acc }) }) } } @@ -435,11 +430,11 @@ pub fn float_weighted_product(arr: List(#(Float, Float))) -> Result(Float, Nil) /// /// pub fn example () { /// [] -/// |> maths.float_cumulative_sum() +/// |> maths.cumulative_sum() /// |> should.equal([]) /// /// [1.0, 2.0, 3.0] -/// |> maths.float_cumulative_sum() +/// |> maths.cumulative_sum() /// |> should.equal([1.0, 3.0, 6.0]) /// } /// @@ -450,10 +445,10 @@ pub fn float_weighted_product(arr: List(#(Float, Float))) -> Result(Float, Nil) /// /// /// -pub fn float_cumulative_sum(arr: List(Float)) -> List(Float) { +pub fn cumulative_sum(arr: List(Float)) -> List(Float) { case arr { [] -> [] - _ -> list.scan(arr, 0.0, fn(acc, a) { a +. acc }) + _ -> list.scan(arr, 0.0, fn(acc, element) { element +. acc }) } } @@ -500,7 +495,7 @@ pub fn float_cumulative_sum(arr: List(Float)) -> List(Float) { pub fn int_cumulative_sum(arr: List(Int)) -> List(Int) { case arr { [] -> [] - _ -> list.scan(arr, 0, fn(acc, a) { a + acc }) + _ -> list.scan(arr, 0, fn(acc, element) { element + acc }) } } @@ -530,11 +525,11 @@ pub fn int_cumulative_sum(arr: List(Int)) -> List(Int) { /// /// pub fn example () { /// [] -/// |> maths.float_cumulative_product() +/// |> maths.cumulative_product() /// |> should.equal([]) /// /// [1.0, 2.0, 3.0] -/// |> maths.float_cumulative_product() +/// |> maths.cumulative_product() /// |> should.equal([1.0, 2.0, 6.0]) /// } /// @@ -545,10 +540,10 @@ pub fn int_cumulative_sum(arr: List(Int)) -> List(Int) { /// /// /// -pub fn float_cumulative_product(arr: List(Float)) -> List(Float) { +pub fn cumulative_product(arr: List(Float)) -> List(Float) { case arr { [] -> [] - _ -> list.scan(arr, 1.0, fn(acc, a) { a *. acc }) + _ -> list.scan(arr, 1.0, fn(acc, element) { element *. acc }) } } @@ -596,7 +591,7 @@ pub fn float_cumulative_product(arr: List(Float)) -> List(Float) { pub fn int_cumulative_product(arr: List(Int)) -> List(Int) { case arr { [] -> [] - _ -> list.scan(arr, 1, fn(acc, a) { a * acc }) + _ -> list.scan(arr, 1, fn(acc, element) { element * acc }) } } @@ -1792,15 +1787,15 @@ pub fn round_to_nearest(x: Float, p: Int) -> Float { let xabs_truncated = truncate_float(xabs) let remainder = xabs -. xabs_truncated case remainder { - _ if remainder >. 0.5 -> float_sign(x) *. truncate_float(xabs +. 1.0) /. p + _ if remainder >. 0.5 -> sign(x) *. truncate_float(xabs +. 1.0) /. p _ if remainder == 0.5 -> { let assert Ok(is_even) = int.modulo(float.truncate(xabs), 2) case is_even == 0 { - True -> float_sign(x) *. xabs_truncated /. p - False -> float_sign(x) *. truncate_float(xabs +. 1.0) /. p + True -> sign(x) *. xabs_truncated /. p + False -> sign(x) *. truncate_float(xabs +. 1.0) /. p } } - _ -> float_sign(x) *. xabs_truncated /. p + _ -> sign(x) *. xabs_truncated /. p } } @@ -1855,8 +1850,8 @@ pub fn round_ties_away(x: Float, p: Int) -> Float { let xabs = float.absolute_value(x) *. p let remainder = xabs -. truncate_float(xabs) case remainder { - _ if remainder >=. 0.5 -> float_sign(x) *. truncate_float(xabs +. 1.0) /. p - _ -> float_sign(x) *. truncate_float(xabs) /. p + _ if remainder >=. 0.5 -> sign(x) *. truncate_float(xabs +. 1.0) /. p + _ -> sign(x) *. truncate_float(xabs) /. p } } @@ -1913,8 +1908,8 @@ pub fn round_ties_up(x: Float, p: Int) -> Float { let remainder = xabs -. xabs_truncated case remainder { _ if remainder >=. 0.5 && x >=. 0.0 -> - float_sign(x) *. truncate_float(xabs +. 1.0) /. p - _ -> float_sign(x) *. xabs_truncated /. p + sign(x) *. truncate_float(xabs +. 1.0) /. p + _ -> sign(x) *. xabs_truncated /. p } } @@ -2109,10 +2104,10 @@ fn do_ceiling(a: Float) -> Float /// import gleam_community/maths /// /// pub fn example() { -/// maths.float_absolute_difference(-10.0, 10.0) +/// maths.absolute_difference(-10.0, 10.0) /// |> should.equal(20.0) /// -/// maths.float_absolute_difference(0.0, -2.0) +/// maths.absolute_difference(0.0, -2.0) /// |> should.equal(2.0) /// } /// @@ -2123,9 +2118,8 @@ fn do_ceiling(a: Float) -> Float /// /// /// -pub fn float_absolute_difference(a: Float, b: Float) -> Float { - a -. b - |> float.absolute_value() +pub fn absolute_difference(a: Float, b: Float) -> Float { + float.absolute_value(a -. b) } ///
@@ -2165,8 +2159,7 @@ pub fn float_absolute_difference(a: Float, b: Float) -> Float { ///
/// pub fn int_absolute_difference(a: Int, b: Int) -> Int { - a - b - |> int.absolute_value() + int.absolute_value(a - b) } ///
@@ -2185,12 +2178,12 @@ pub fn int_absolute_difference(a: Int, b: Int) -> Int { /// ///
/// -pub fn float_sign(x: Float) -> Float { - do_float_sign(x) +pub fn sign(x: Float) -> Float { + do_sign(x) } -@target(erlang) -fn do_float_sign(x: Float) -> Float { +@external(javascript, "../maths.mjs", "sign") +fn do_sign(x: Float) -> Float { case x { _ if x <. 0.0 -> -1.0 _ if x >. 0.0 -> 1.0 @@ -2198,10 +2191,6 @@ fn do_float_sign(x: Float) -> Float { } } -@target(javascript) -@external(javascript, "../maths.mjs", "sign") -fn do_float_sign(a: Float) -> Float - ///
/// /// Spot a typo? Open an issue! @@ -2222,7 +2211,7 @@ pub fn int_sign(x: Int) -> Int { do_int_sign(x) } -@target(erlang) +@external(javascript, "../maths.mjs", "sign") fn do_int_sign(x: Int) -> Int { case x { _ if x < 0 -> -1 @@ -2231,10 +2220,6 @@ fn do_int_sign(x: Int) -> Int { } } -@target(javascript) -@external(javascript, "../maths.mjs", "sign") -fn do_int_sign(a: Int) -> Int - ///
/// /// Spot a typo? Open an issue! @@ -2250,14 +2235,14 @@ fn do_int_sign(a: Int) -> Int /// ///
/// -pub fn float_copy_sign(x: Float, y: Float) -> Float { - case float_sign(x) == float_sign(y) { +pub fn copy_sign(x: Float, y: Float) -> Float { + case sign(x) == sign(y) { // x and y have the same sign, just return x True -> x // x and y have different signs: // - x is positive and y is negative, then flip sign of x // - x is negative and y is positive, then flip sign of x - False -> float_flip_sign(x) + False -> flip_sign(x) } } @@ -2301,7 +2286,7 @@ pub fn int_copy_sign(x: Int, y: Int) -> Int { /// ///
/// -pub fn float_flip_sign(x: Float) -> Float { +pub fn flip_sign(x: Float) -> Float { -1.0 *. x } @@ -2772,7 +2757,9 @@ pub fn combination(n: Int, k: Int) -> Result(Int, Nil) { False -> n - k } Ok( - list.fold(list.range(1, min), 1, fn(acc, x) { acc * { n + 1 - x } / x }), + list.fold(list.range(1, min), 1, fn(acc, element) { + acc * { n + 1 - element } / element + }), ) } } @@ -3101,8 +3088,8 @@ fn remove_first_by_index( arr: Yielder(#(Int, a)), index_to_remove: Int, ) -> Yielder(#(Int, a)) { - yielder.flat_map(arr, fn(arg) { - let #(index, element) = arg + yielder.flat_map(arr, fn(tuple) { + let #(index, element) = tuple case index == index_to_remove { True -> yielder.empty() False -> yielder.single(#(index, element)) @@ -3149,7 +3136,8 @@ pub fn list_permutation(arr: List(a), k: Int) -> Result(Yielder(List(a)), Nil) { _, _ if k < 0 -> Error(Nil) _, arr_length if k > arr_length -> Error(Nil) _, _ -> { - let indexed_arr = list.index_map(arr, fn(x, i) { #(i, x) }) + let indexed_arr = + list.index_map(arr, fn(element, index) { #(index, element) }) Ok(do_list_permutation_without_repetitions( yielder.from_list(indexed_arr), k, @@ -3165,8 +3153,8 @@ fn do_list_permutation_without_repetitions( case k { 0 -> yielder.single([]) _ -> - yielder.flat_map(arr, fn(arg) { - let #(index, element) = arg + yielder.flat_map(arr, fn(tuple) { + let #(index, element) = tuple let remaining = remove_first_by_index(arr, index) let permutations = do_list_permutation_without_repetitions(remaining, k - 1) @@ -3217,21 +3205,22 @@ pub fn list_permutation_with_repetitions( case k { _ if k < 0 -> Error(Nil) _ -> { - let indexed_arr = list.index_map(arr, fn(x, i) { #(i, x) }) - Ok(do_list_permutation_with_repetitions(indexed_arr, k)) + let indexed_arr = + list.index_map(arr, fn(element, index) { #(index, element) }) + Ok(do_list_permutation_with_repetitions(yielder.from_list(indexed_arr), k)) } } } fn do_list_permutation_with_repetitions( - arr: List(#(Int, a)), + arr: Yielder(#(Int, a)), k: Int, ) -> Yielder(List(a)) { case k { 0 -> yielder.single([]) _ -> - yielder.flat_map(arr |> yielder.from_list, fn(arg) { - let #(_, element) = arg + yielder.flat_map(arr, fn(tuple) { + let #(_, element) = tuple // Allow the same element (by index) to be reused in future recursive calls let permutations = do_list_permutation_with_repetitions(arr, k - 1) // Prepend the current element to each generated permutation @@ -3275,9 +3264,9 @@ fn do_list_permutation_with_repetitions( /// /// pub fn cartesian_product(xset: set.Set(a), yset: set.Set(b)) -> set.Set(#(a, b)) { - set.fold(xset, set.new(), fn(accumulator0: set.Set(#(a, b)), member0: a) { - set.fold(yset, accumulator0, fn(accumulator1: set.Set(#(a, b)), member1: b) { - set.insert(accumulator1, #(member0, member1)) + set.fold(xset, set.new(), fn(acc0, element0) { + set.fold(yset, acc0, fn(acc1, element1) { + set.insert(acc1, #(element0, element1)) }) }) } @@ -3329,9 +3318,9 @@ pub fn norm(arr: List(Float), p: Float) -> Result(Float, Nil) { [] -> Ok(0.0) _ -> { let aggregate = - list.fold(arr, 0.0, fn(accumulator, element) { + list.fold(arr, 0.0, fn(acc, element) { let assert Ok(result) = float.power(float.absolute_value(element), p) - result +. accumulator + result +. acc }) float.power(aggregate, 1.0 /. p) } @@ -3388,15 +3377,14 @@ pub fn norm_with_weights( case arr { [] -> Ok(0.0) _ -> { - let weight_is_negative = - list.any(arr, fn(tuple: #(Float, Float)) { tuple.1 <. 0.0 }) + let weight_is_negative = list.any(arr, fn(tuple) { tuple.1 <. 0.0 }) case weight_is_negative { False -> { let aggregate = - list.fold(arr, 0.0, fn(accumulator, tuple) { + list.fold(arr, 0.0, fn(acc, tuple) { let assert Ok(result) = float.power(float.absolute_value(tuple.0), p) - tuple.1 *. result +. accumulator + tuple.1 *. result +. acc }) float.power(aggregate, 1.0 /. p) } @@ -3537,10 +3525,7 @@ pub fn minkowski_distance( case p <. 1.0 { True -> Error(Nil) False -> { - let differences = - list.map(arr, fn(tuple: #(Float, Float)) -> Float { - tuple.0 -. tuple.1 - }) + let differences = list.map(arr, fn(tuple) { tuple.0 -. tuple.1 }) norm(differences, p) } } @@ -3601,15 +3586,12 @@ pub fn minkowski_distance_with_weights( case arr { [] -> Error(Nil) _ -> { - let weight_is_negative = - list.any(arr, fn(tuple: #(Float, Float, Float)) { tuple.2 <. 0.0 }) + let weight_is_negative = list.any(arr, fn(tuple) { tuple.2 <. 0.0 }) case p <. 1.0, weight_is_negative { False, False -> { let differences = - list.map(arr, fn(tuple: #(Float, Float, Float)) -> #(Float, Float) { - #(tuple.0 -. tuple.1, tuple.2) - }) + list.map(arr, fn(tuple) { #(tuple.0 -. tuple.1, tuple.2) }) norm_with_weights(differences, p) } _, _ -> Error(Nil) @@ -3793,8 +3775,7 @@ pub fn chebyshev_distance_with_weights( case arr { [] -> Error(Nil) _ -> { - let weight_is_negative = - list.any(arr, fn(tuple: #(Float, Float, Float)) { tuple.2 <. 0.0 }) + let weight_is_negative = list.any(arr, fn(tuple) { tuple.2 <. 0.0 }) case weight_is_negative { True -> Error(Nil) @@ -3959,7 +3940,7 @@ fn do_median( /// Back to top ↑ /// /// -/// +/// pub fn variance(arr: List(Float), ddof: Int) -> Result(Float, Nil) { case arr, ddof { [], _ -> Error(Nil) @@ -3967,13 +3948,13 @@ pub fn variance(arr: List(Float), ddof: Int) -> Result(Float, Nil) { _, _ -> { let assert Ok(mean) = mean(arr) Ok( - list.map(arr, fn(a: Float) -> Float { - let assert Ok(result) = float.power(a -. mean, 2.0) + list.map(arr, fn(element) { + let assert Ok(result) = float.power(element -. mean, 2.0) result }) |> float.sum() - |> fn(a: Float) -> Float { - a /. { int.to_float(list.length(arr)) -. int.to_float(ddof) } + |> fn(element) { + element /. { int.to_float(list.length(arr)) -. int.to_float(ddof) } }, ) } @@ -4328,13 +4309,10 @@ pub fn overlap_coefficient(xset: set.Set(a), yset: set.Set(a)) -> Float { /// pub fn cosine_similarity(arr: List(#(Float, Float))) -> Result(Float, Nil) { let numerator = - arr - |> list.fold(0.0, fn(accumulator, tuple) { - accumulator +. tuple.0 *. tuple.1 - }) + list.fold(arr, 0.0, fn(acc, tuple) { acc +. tuple.0 *. tuple.1 }) - let xarr = arr |> list.map(fn(tuple: #(Float, Float)) { tuple.0 }) - let yarr = arr |> list.map(fn(tuple: #(Float, Float)) { tuple.1 }) + let xarr = list.map(arr, fn(tuple) { tuple.0 }) + let yarr = list.map(arr, fn(tuple) { tuple.1 }) let assert Ok(xarr_norm) = norm(xarr, 2.0) let assert Ok(yarr_norm) = norm(yarr, 2.0) @@ -4411,26 +4389,21 @@ pub fn cosine_similarity(arr: List(#(Float, Float))) -> Result(Float, Nil) { pub fn cosine_similarity_with_weights( arr: List(#(Float, Float, Float)), ) -> Result(Float, Nil) { - let weight_is_negative = - list.any(arr, fn(tuple: #(Float, Float, Float)) { tuple.2 <. 0.0 }) + let weight_is_negative = list.any(arr, fn(tuple) { tuple.2 <. 0.0 }) case weight_is_negative { False -> { let numerator = - arr - |> list.fold(0.0, fn(accumulator, tuple) { - accumulator +. tuple.0 *. tuple.1 *. tuple.2 + list.fold(arr, 0.0, fn(acc, tuple) { + acc +. tuple.0 *. tuple.1 *. tuple.2 }) - let xarr = - arr - |> list.map(fn(tuple: #(Float, Float, Float)) { #(tuple.0, tuple.2) }) - let yarr = - arr - |> list.map(fn(tuple: #(Float, Float, Float)) { #(tuple.1, tuple.2) }) + let xarr = list.map(arr, fn(tuple) { #(tuple.0, tuple.2) }) + let yarr = list.map(arr, fn(tuple) { #(tuple.1, tuple.2) }) let assert Ok(xarr_norm) = norm_with_weights(xarr, 2.0) let assert Ok(yarr_norm) = norm_with_weights(yarr, 2.0) + let denominator = { xarr_norm *. yarr_norm } @@ -4482,12 +4455,12 @@ pub fn canberra_distance(arr: List(#(Float, Float))) -> Result(Float, Nil) { [] -> Error(Nil) _ -> { Ok( - list.fold(arr, 0.0, fn(accumulator, tuple) { + list.fold(arr, 0.0, fn(acc, tuple) { let numerator = float.absolute_value({ tuple.0 -. tuple.1 }) let denominator = { float.absolute_value(tuple.0) +. float.absolute_value(tuple.1) } - accumulator +. numerator /. denominator + acc +. numerator /. denominator }), ) } @@ -4538,19 +4511,18 @@ pub fn canberra_distance_with_weights( case arr { [] -> Error(Nil) _ -> { - let weight_is_negative = - list.any(arr, fn(tuple: #(Float, Float, Float)) { tuple.2 <. 0.0 }) + let weight_is_negative = list.any(arr, fn(tuple) { tuple.2 <. 0.0 }) case weight_is_negative { True -> Error(Nil) False -> { Ok( - list.fold(arr, 0.0, fn(accumulator, tuple) { + list.fold(arr, 0.0, fn(acc, tuple) { let numerator = float.absolute_value({ tuple.0 -. tuple.1 }) let denominator = { float.absolute_value(tuple.0) +. float.absolute_value(tuple.1) } - accumulator +. tuple.2 *. numerator /. denominator + acc +. tuple.2 *. numerator /. denominator }), ) } @@ -4605,13 +4577,13 @@ pub fn braycurtis_distance(arr: List(#(Float, Float))) -> Result(Float, Nil) { [] -> Error(Nil) _ -> { let numerator = - list.fold(arr, 0.0, fn(accumulator, tuple) { - accumulator +. float.absolute_value({ tuple.0 -. tuple.1 }) + list.fold(arr, 0.0, fn(acc, tuple) { + acc +. float.absolute_value({ tuple.0 -. tuple.1 }) }) let denominator = - list.fold(arr, 0.0, fn(accumulator, tuple) { - accumulator +. float.absolute_value({ tuple.0 +. tuple.1 }) + list.fold(arr, 0.0, fn(acc, tuple) { + acc +. float.absolute_value({ tuple.0 +. tuple.1 }) }) Ok({ numerator /. denominator }) @@ -4666,24 +4638,19 @@ pub fn braycurtis_distance_with_weights( case arr { [] -> Error(Nil) _ -> { - let weight_is_negative = - list.any(arr, fn(tuple: #(Float, Float, Float)) { tuple.2 <. 0.0 }) + let weight_is_negative = list.any(arr, fn(tuple) { tuple.2 <. 0.0 }) case weight_is_negative { True -> Error(Nil) False -> { let numerator = - list.fold(arr, 0.0, fn(accumulator, tuple) { - accumulator - +. tuple.2 - *. float.absolute_value({ tuple.0 -. tuple.1 }) + list.fold(arr, 0.0, fn(acc, tuple) { + acc +. tuple.2 *. float.absolute_value({ tuple.0 -. tuple.1 }) }) let denominator = - list.fold(arr, 0.0, fn(accumulator, tuple) { - accumulator - +. tuple.2 - *. float.absolute_value({ tuple.0 +. tuple.1 }) + list.fold(arr, 0.0, fn(acc, tuple) { + acc +. tuple.2 *. float.absolute_value({ tuple.0 +. tuple.1 }) }) Ok({ numerator /. denominator }) @@ -4734,12 +4701,9 @@ pub fn braycurtis_distance_with_weights( /// /// pub fn is_close(x: Float, y: Float, rtol: Float, atol: Float) -> Bool { - let x = float_absolute_difference(x, y) + let x = absolute_difference(x, y) let y = atol +. rtol *. float.absolute_value(y) - case x <=. y { - True -> True - False -> False - } + x <=. y } ///
@@ -5196,7 +5160,7 @@ pub fn erf(x: Float) -> Float { ] let p = 0.3275911 - let sign = float_sign(x) + let sign = sign(x) let x = float.absolute_value(x) // Formula 7.1.26 given in Abramowitz and Stegun. @@ -5368,8 +5332,8 @@ pub fn arange(start: Float, stop: Float, increment: Float) -> Yielder(Float) { let distance = float.absolute_value(start -. stop) let num = float.round(distance /. increment_abs) - yielder.map(yielder.range(0, num - 1), fn(i) { - start +. int.to_float(i) *. increment_abs *. direction + yielder.map(yielder.range(0, num - 1), fn(index) { + start +. int.to_float(index) *. increment_abs *. direction }) } } @@ -5436,8 +5400,8 @@ pub fn linear_space( case steps > 0 { True -> { Ok( - yielder.map(yielder.range(0, steps - 1), fn(i) { - start +. int.to_float(i) *. increment *. direction + yielder.map(yielder.range(0, steps - 1), fn(index) { + start +. int.to_float(index) *. increment *. direction }), ) } @@ -5455,6 +5419,11 @@ pub fn linear_space( /// interval. The endpoint of the interval can optionally be included/excluded. The number of /// points, base, and whether the endpoint is included determine the spacing between values. /// +/// The values in the sequence are computed as powers of the given base, where the exponents are +/// evenly spaced between `start` and `stop`. The `base` parameter must be positive, as negative +/// bases lead to undefined behavior when computing fractional exponents. Similarly, the number of +/// points (`steps`) must be positive; specifying zero or a negative value will result in an error. +/// ///
/// Example: /// @@ -5482,7 +5451,7 @@ pub fn linear_space( /// Back to top ↑ /// ///
-/// +/// pub fn logarithmic_space( start: Float, stop: Float, @@ -5490,13 +5459,13 @@ pub fn logarithmic_space( endpoint: Bool, base: Float, ) -> Result(Yielder(Float), Nil) { - case steps > 0 { + case steps > 0 && base >=. 0.0 { True -> { let assert Ok(linspace) = linear_space(start, stop, steps, endpoint) Ok( - yielder.map(linspace, fn(i) { - let assert Ok(result) = float.power(base, i) + yielder.map(linspace, fn(value) { + let assert Ok(result) = float.power(base, value) result }), ) @@ -5511,11 +5480,20 @@ pub fn logarithmic_space( /// /// /// -/// The function returns an iterator of numbers spaced evenly on a log scale (a geometric -/// progression). Each point in the list is a constant multiple of the previous. The function is -/// similar to the [`logarithmic_space`](#logarithmic_space) function, but with endpoints -/// specified directly. +/// The function returns an iterator for generating a geometric progression between two specified +/// values, where each value is a constant multiple of the previous one. Unlike +/// [`logarithmic_space`](#logarithmic_space), this function allows specifying the starting +/// and ending values (`start` and `stop`) directly, without requiring them to be transformed +/// into exponents. /// +/// Internally, the function computes the logarithms of `start` and `stop` and generates evenly +/// spaced points in the logarithmic domain (using base 10). These points are then transformed back +/// into their original scale to create a sequence of values that grow multiplicatively. +/// +/// The `start` and `stop` values must be positive, as logarithms are undefined for non-positive +/// values. The number of points (`steps`) must also be positive; specifying zero or a negative +/// value will result in an error. +/// ///
/// Example: /// @@ -5532,7 +5510,7 @@ pub fn logarithmic_space( /// |> list.all(fn(x) { x == True }) /// |> should.be_true() /// -/// // Input (start and stop can't be equal to 0.0) +/// // Input (start and stop can't be less than or equal to 0.0) /// maths.geometric_space(0.0, 1000.0, 3, False) /// |> should.be_error() /// @@ -5557,75 +5535,13 @@ pub fn geometric_space( steps: Int, endpoint: Bool, ) -> Result(Yielder(Float), Nil) { - case start == 0.0 || stop == 0.0 { + case start <=. 0.0 || stop <=. 0.0 || steps < 0 { True -> Error(Nil) - False -> - case steps > 0 { - True -> { - let assert Ok(log_start) = logarithm_10(start) - let assert Ok(log_stop) = logarithm_10(stop) - logarithmic_space(log_start, log_stop, steps, endpoint, 10.0) - } - False -> Error(Nil) - } - } -} - -///
-/// -/// Spot a typo? Open an issue! -/// -///
-/// -/// The function returns an iterator of exponentially spaced points over a specified interval. The -/// endpoint of the interval can optionally be included/excluded. The number of points and whether -/// the endpoint is included determine the spacing between values. The sequence is generated by -/// computing intermediate values in a logarithmic domain and transforming them into the exponential -/// domain. -/// -///
-/// Example: -/// -/// import gleam/yielder -/// import gleeunit/should -/// import gleam_community/maths -/// -/// pub fn example() { -/// let assert Ok(tolerance) = float.power(10.0, -6.0) -/// let assert Ok(exp_space) = maths.exponential_space(1.0, 1000.0, 4, True) -/// let expected = [1.0, 10.0, 100.0, 1000.0] -/// let pairs = exp_space |> yielder.to_list() |> list.zip(expected) -/// let assert Ok(result) = maths.all_close(pairs, 0.0, tolerance) -/// result |> list.all(fn(x) { x == True }) |> should.be_true() -/// } -///
-/// -///
-/// -/// Back to top ↑ -/// -///
-/// -pub fn exponential_space( - start: Float, - stop: Float, - steps: Int, - endpoint: Bool, -) -> Result(Yielder(Float), Nil) { - case steps > 0 { - True -> { + False -> { let assert Ok(log_start) = logarithm_10(start) let assert Ok(log_stop) = logarithm_10(stop) - let assert Ok(log_space) = - linear_space(log_start, log_stop, steps, endpoint) - Ok( - yielder.map(log_space, fn(log_value) { - let assert Ok(exp_value) = float.power(10.0, log_value) - exp_value - }), - ) + logarithmic_space(log_start, log_stop, steps, endpoint, 10.0) } - False -> Error(Nil) } } @@ -5635,8 +5551,8 @@ pub fn exponential_space( /// /// /// -/// Generates evenly spaced points around a center value. The total span is determined by -/// the radius argument of the function. +/// Generates evenly spaced points around a center value. The total span (around the center value) +/// is determined by the `radius` argument of the function. /// ///
/// Example: @@ -5650,6 +5566,12 @@ pub fn exponential_space( /// sym_space /// |> yielder.to_list() /// |> should.equal([-5.0, -2.5, 0.0, 2.5, 5.0]) +/// +/// // A negative radius reverses the order of the values +/// let assert Ok(sym_space) = maths.symmetric_space(0.0, -5.0, 5) +/// sym_space +/// |> yielder.to_list() +/// |> should.equal([5.0, 2.5, 0.0, -2.5, -5.0]) /// } ///
/// diff --git a/test/gleam_community/arithmetics_test.gleam b/test/gleam_community/arithmetics_test.gleam index 6cbc9ec..626682f 100644 --- a/test/gleam_community/arithmetics_test.gleam +++ b/test/gleam_community/arithmetics_test.gleam @@ -22,35 +22,35 @@ pub fn int_gcd_test() { |> should.equal(6) } -pub fn int_euclidean_modulo_test() { +pub fn euclidean_modulo_test() { // Base Case: Positive x, Positive y // Note that the truncated, floored, and euclidean // definitions should agree for this base case - maths.int_euclidean_modulo(15, 4) + maths.euclidean_modulo(15, 4) |> should.equal(3) // Case: Positive x, Negative y - maths.int_euclidean_modulo(15, -4) + maths.euclidean_modulo(15, -4) |> should.equal(3) // Case: Negative x, Positive y - maths.int_euclidean_modulo(-15, 4) + maths.euclidean_modulo(-15, 4) |> should.equal(1) // Case: Negative x, Negative y - maths.int_euclidean_modulo(-15, -4) + maths.euclidean_modulo(-15, -4) |> should.equal(1) // Case: Positive x, Zero y - maths.int_euclidean_modulo(5, 0) + maths.euclidean_modulo(5, 0) |> should.equal(0) // Case: Zero x, Negative y - maths.int_euclidean_modulo(0, 5) + maths.euclidean_modulo(0, 5) |> should.equal(0) } -pub fn int_lcm_test() { +pub fn lcm_test() { maths.lcm(1, 1) |> should.equal(1) @@ -70,7 +70,7 @@ pub fn int_lcm_test() { |> should.equal(210) } -pub fn int_proper_divisors_test() { +pub fn proper_divisors_test() { maths.proper_divisors(2) |> should.equal([1]) @@ -84,7 +84,7 @@ pub fn int_proper_divisors_test() { |> should.equal([1, 2, 3, 6, 9]) } -pub fn int_divisors_test() { +pub fn divisors_test() { maths.divisors(2) |> should.equal([1, 2]) @@ -98,19 +98,19 @@ pub fn int_divisors_test() { |> should.equal([1, 2, 3, 6, 9, 18]) } -pub fn float_list_cumulative_sum_test() { +pub fn list_cumulative_sum_test() { // An empty lists returns an empty list [] - |> maths.float_cumulative_sum() + |> maths.cumulative_sum() |> should.equal([]) // Valid input returns a result [1.0, 2.0, 3.0] - |> maths.float_cumulative_sum() + |> maths.cumulative_sum() |> should.equal([1.0, 3.0, 6.0]) [-2.0, 4.0, 6.0] - |> maths.float_cumulative_sum() + |> maths.cumulative_sum() |> should.equal([-2.0, 2.0, 8.0]) } @@ -130,19 +130,19 @@ pub fn int_list_cumulative_sum_test() { |> should.equal([-2, 2, 8]) } -pub fn float_list_cumulative_product_test() { +pub fn list_cumulative_product_test() { // An empty lists returns an empty list [] - |> maths.float_cumulative_product() + |> maths.cumulative_product() |> should.equal([]) // Valid input returns a result [1.0, 2.0, 3.0] - |> maths.float_cumulative_product() + |> maths.cumulative_product() |> should.equal([1.0, 2.0, 6.0]) [-2.0, 4.0, 6.0] - |> maths.float_cumulative_product() + |> maths.cumulative_product() |> should.equal([-2.0, -8.0, -48.0]) } @@ -162,42 +162,42 @@ pub fn int_list_cumulative_product_test() { |> should.equal([-2, -8, -48]) } -pub fn float_weighted_product_test() { +pub fn weighted_product_test() { [] - |> maths.float_weighted_product() + |> maths.weighted_product() |> should.equal(Ok(1.0)) [#(1.0, 0.0), #(2.0, 0.0), #(3.0, 0.0)] - |> maths.float_weighted_product() + |> maths.weighted_product() |> should.equal(Ok(1.0)) [#(1.0, 1.0), #(2.0, 1.0), #(3.0, 1.0)] - |> maths.float_weighted_product() + |> maths.weighted_product() |> should.equal(Ok(6.0)) let assert Ok(tolerance) = float.power(10.0, -6.0) let assert Ok(result) = [#(9.0, 0.5), #(10.0, 0.5), #(10.0, 0.5)] - |> maths.float_weighted_product() + |> maths.weighted_product() result |> maths.is_close(30.0, 0.0, tolerance) |> should.be_true() } -pub fn float_weighted_sum_test() { +pub fn weighted_sum_test() { [] - |> maths.float_weighted_sum() + |> maths.weighted_sum() |> should.equal(Ok(0.0)) [#(1.0, 0.0), #(2.0, 0.0), #(3.0, 0.0)] - |> maths.float_weighted_sum() + |> maths.weighted_sum() |> should.equal(Ok(0.0)) [#(1.0, 1.0), #(2.0, 1.0), #(3.0, 1.0)] - |> maths.float_weighted_sum() + |> maths.weighted_sum() |> should.equal(Ok(6.0)) [#(9.0, 0.5), #(10.0, 0.5), #(10.0, 0.5)] - |> maths.float_weighted_sum() + |> maths.weighted_sum() |> should.equal(Ok(14.5)) } diff --git a/test/gleam_community/conversion_test.gleam b/test/gleam_community/conversion_test.gleam index 081089c..9b03f13 100644 --- a/test/gleam_community/conversion_test.gleam +++ b/test/gleam_community/conversion_test.gleam @@ -2,7 +2,7 @@ import gleam/float import gleam_community/maths import gleeunit/should -pub fn float_to_degree_test() { +pub fn to_degree_test() { let assert Ok(tol) = float.power(10.0, -6.0) maths.radians_to_degrees(0.0) |> maths.is_close(0.0, 0.0, tol) @@ -13,7 +13,7 @@ pub fn float_to_degree_test() { |> should.be_true() } -pub fn float_to_radian_test() { +pub fn to_radian_test() { let assert Ok(tol) = float.power(10.0, -6.0) maths.degrees_to_radians(0.0) |> maths.is_close(0.0, 0.0, tol) @@ -24,7 +24,7 @@ pub fn float_to_radian_test() { |> should.be_true() } -pub fn float_cartesian_to_polar_test() { +pub fn cartesian_to_polar_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Test: Cartesian (1, 0) -> Polar (1, 0) @@ -68,7 +68,7 @@ pub fn float_cartesian_to_polar_test() { |> should.be_true() } -pub fn float_polar_to_cartesian_test() { +pub fn polar_to_cartesian_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Test: Polar (1, 0) -> Cartesian (1, 0) diff --git a/test/gleam_community/elementary_test.gleam b/test/gleam_community/elementary_test.gleam index ed833f2..9f49106 100644 --- a/test/gleam_community/elementary_test.gleam +++ b/test/gleam_community/elementary_test.gleam @@ -2,7 +2,7 @@ import gleam/float import gleam_community/maths import gleeunit/should -pub fn float_acos_test() { +pub fn acos_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values @@ -25,7 +25,7 @@ pub fn float_acos_test() { |> should.be_error() } -pub fn float_acosh_test() { +pub fn acosh_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values @@ -40,7 +40,7 @@ pub fn float_acosh_test() { |> should.be_error() } -pub fn float_asin_test() { +pub fn asin_test() { // Check that the function agrees, at some arbitrary input // points, with known function values maths.asin(0.0) @@ -61,7 +61,7 @@ pub fn float_asin_test() { |> should.be_error() } -pub fn float_asinh_test() { +pub fn asinh_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values @@ -74,7 +74,7 @@ pub fn float_asinh_test() { |> should.be_true() } -pub fn float_atan_test() { +pub fn atan_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values @@ -135,7 +135,7 @@ pub fn math_atan2_test() { |> should.be_true() } -pub fn float_atanh_test() { +pub fn atanh_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values @@ -164,7 +164,7 @@ pub fn float_atanh_test() { |> should.be_error() } -pub fn float_cos_test() { +pub fn cos_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values @@ -181,7 +181,7 @@ pub fn float_cos_test() { |> should.be_true() } -pub fn float_cosh_test() { +pub fn cosh_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values @@ -198,7 +198,7 @@ pub fn float_cosh_test() { // runtime. } -pub fn float_sin_test() { +pub fn sin_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values @@ -215,7 +215,7 @@ pub fn float_sin_test() { |> should.be_true() } -pub fn float_sinh_test() { +pub fn sinh_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values @@ -266,7 +266,7 @@ pub fn math_tanh_test() { |> should.be_true() } -pub fn float_exponential_test() { +pub fn exponential_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values @@ -283,7 +283,7 @@ pub fn float_exponential_test() { // runtime. } -pub fn float_natural_logarithm_test() { +pub fn natural_logarithm_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values @@ -301,7 +301,7 @@ pub fn float_natural_logarithm_test() { |> should.be_error() } -pub fn float_logarithm_test() { +pub fn logarithm_test() { // Check that the function agrees, at some arbitrary input // points, with known function values maths.logarithm(10.0, 10.0) @@ -334,7 +334,7 @@ pub fn float_logarithm_test() { |> should.be_error() } -pub fn float_logarithm_2_test() { +pub fn logarithm_2_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values @@ -355,7 +355,7 @@ pub fn float_logarithm_2_test() { |> should.be_error() } -pub fn float_logarithm_10_test() { +pub fn logarithm_10_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values @@ -380,7 +380,7 @@ pub fn float_logarithm_10_test() { |> should.be_error() } -pub fn float_nth_root_test() { +pub fn nth_root_test() { maths.nth_root(9.0, 2) |> should.equal(Ok(3.0)) @@ -399,7 +399,7 @@ pub fn float_nth_root_test() { |> should.be_error() } -pub fn float_constants_test() { +pub fn constants_test() { let assert Ok(tolerance) = float.power(10.0, -12.0) // Test that the constant is approximately equal to 2.7128... diff --git a/test/gleam_community/metrics_test.gleam b/test/gleam_community/metrics_test.gleam index f799692..996d261 100644 --- a/test/gleam_community/metrics_test.gleam +++ b/test/gleam_community/metrics_test.gleam @@ -3,7 +3,7 @@ import gleam/set import gleam_community/maths import gleeunit/should -pub fn float_list_norm_test() { +pub fn list_norm_test() { let assert Ok(tol) = float.power(10.0, -6.0) // An empty lists returns 0.0 @@ -63,7 +63,7 @@ pub fn float_list_norm_test() { |> should.be_true() } -pub fn float_list_norm_with_weights_test() { +pub fn list_norm_with_weights_test() { let assert Ok(tol) = float.power(10.0, -6.0) // An empty lists returns 0.0 @@ -95,7 +95,7 @@ pub fn float_list_norm_with_weights_test() { |> should.be_true() } -pub fn float_list_manhattan_test() { +pub fn list_manhattan_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Try with valid input (same as Minkowski distance with p = 1) @@ -135,7 +135,7 @@ pub fn float_list_manhattan_test() { |> should.be_error() } -pub fn float_list_minkowski_test() { +pub fn list_minkowski_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Test order < 1 @@ -209,7 +209,7 @@ pub fn float_list_minkowski_test() { |> should.be_error() } -pub fn float_list_euclidean_test() { +pub fn list_euclidean_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Empty lists returns an error @@ -268,6 +268,10 @@ pub fn mean_test() { [1.0, 2.0, 3.0] |> maths.mean() |> should.equal(Ok(2.0)) + + [-1.0, -2.0, -3.0] + |> maths.mean() + |> should.equal(Ok(-2.0)) } pub fn median_test() { diff --git a/test/gleam_community/piecewise_test.gleam b/test/gleam_community/piecewise_test.gleam index f74a84f..9a6907f 100644 --- a/test/gleam_community/piecewise_test.gleam +++ b/test/gleam_community/piecewise_test.gleam @@ -3,7 +3,7 @@ import gleam/int import gleam_community/maths import gleeunit/should -pub fn float_ceiling_test() { +pub fn ceiling_test() { // Round 3. digit AFTER decimal point maths.round_up(12.0654, 3) |> should.equal(12.066) @@ -33,7 +33,7 @@ pub fn float_ceiling_test() { |> should.equal(1000.0) } -pub fn float_floor_test() { +pub fn floor_test() { // Round 3. digit AFTER decimal point maths.round_down(12.0654, 3) |> should.equal(12.065) @@ -63,7 +63,7 @@ pub fn float_floor_test() { |> should.equal(0.0) } -pub fn float_truncate_test() { +pub fn truncate_test() { // Round 3. digit AFTER decimal point maths.round_to_zero(12.0654, 3) |> should.equal(12.065) @@ -373,41 +373,41 @@ pub fn math_round_ties_up_test() { |> should.equal(0.0) } -pub fn float_absolute_difference_test() { - maths.float_absolute_difference(20.0, 15.0) +pub fn absolute_difference_test() { + maths.absolute_difference(20.0, 15.0) |> should.equal(5.0) - maths.float_absolute_difference(-20.0, -15.0) + maths.absolute_difference(-20.0, -15.0) |> should.equal(5.0) - maths.float_absolute_difference(20.0, -15.0) + maths.absolute_difference(20.0, -15.0) |> should.equal(35.0) - maths.float_absolute_difference(-20.0, 15.0) + maths.absolute_difference(-20.0, 15.0) |> should.equal(35.0) - maths.float_absolute_difference(0.0, 0.0) + maths.absolute_difference(0.0, 0.0) |> should.equal(0.0) - maths.float_absolute_difference(1.0, 2.0) + maths.absolute_difference(1.0, 2.0) |> should.equal(1.0) - maths.float_absolute_difference(2.0, 1.0) + maths.absolute_difference(2.0, 1.0) |> should.equal(1.0) - maths.float_absolute_difference(-1.0, 0.0) + maths.absolute_difference(-1.0, 0.0) |> should.equal(1.0) - maths.float_absolute_difference(0.0, -1.0) + maths.absolute_difference(0.0, -1.0) |> should.equal(1.0) - maths.float_absolute_difference(10.0, 20.0) + maths.absolute_difference(10.0, 20.0) |> should.equal(10.0) - maths.float_absolute_difference(-10.0, -20.0) + maths.absolute_difference(-10.0, -20.0) |> should.equal(10.0) - maths.float_absolute_difference(-10.5, 10.5) + maths.absolute_difference(-10.5, 10.5) |> should.equal(21.0) } @@ -425,39 +425,39 @@ pub fn int_absolute_difference_test() { |> should.equal(35) } -pub fn float_sign_test() { - maths.float_sign(100.0) +pub fn sign_test() { + maths.sign(100.0) |> should.equal(1.0) - maths.float_sign(0.0) + maths.sign(0.0) |> should.equal(0.0) - maths.float_sign(-100.0) + maths.sign(-100.0) |> should.equal(-1.0) } -pub fn float_flip_sign_test() { - maths.float_flip_sign(100.0) +pub fn flip_sign_test() { + maths.flip_sign(100.0) |> should.equal(-100.0) - maths.float_flip_sign(0.0) + maths.flip_sign(0.0) |> should.equal(-0.0) - maths.float_flip_sign(-100.0) + maths.flip_sign(-100.0) |> should.equal(100.0) } -pub fn float_copy_sign_test() { - maths.float_copy_sign(100.0, 10.0) +pub fn copy_sign_test() { + maths.copy_sign(100.0, 10.0) |> should.equal(100.0) - maths.float_copy_sign(-100.0, 10.0) + maths.copy_sign(-100.0, 10.0) |> should.equal(100.0) - maths.float_copy_sign(100.0, -10.0) + maths.copy_sign(100.0, -10.0) |> should.equal(-100.0) - maths.float_copy_sign(-100.0, -10.0) + maths.copy_sign(-100.0, -10.0) |> should.equal(-100.0) } @@ -497,7 +497,7 @@ pub fn int_copy_sign_test() { |> should.equal(-100) } -pub fn float_minmax_test() { +pub fn minmax_test() { maths.minmax(0.75, 0.5, float.compare) |> should.equal(#(0.5, 0.75)) @@ -525,7 +525,7 @@ pub fn int_minmax_test() { |> should.equal(#(-75, 50)) } -pub fn float_list_minimum_test() { +pub fn list_minimum_test() { // An empty lists returns an error [] |> maths.list_minimum(float.compare) @@ -549,7 +549,7 @@ pub fn int_list_minimum_test() { |> should.equal(Ok(1)) } -pub fn float_list_maximum_test() { +pub fn list_maximum_test() { // An empty lists returns an error [] |> maths.list_maximum(float.compare) @@ -573,7 +573,7 @@ pub fn int_list_maximum_test() { |> should.equal(Ok(4)) } -pub fn float_list_arg_maximum_test() { +pub fn list_arg_maximum_test() { // An empty lists returns an error [] |> maths.arg_maximum(float.compare) @@ -597,7 +597,7 @@ pub fn int_list_arg_maximum_test() { |> should.equal(Ok([0, 1])) } -pub fn float_list_arg_minimum_test() { +pub fn list_arg_minimum_test() { // An empty lists returns an error [] |> maths.arg_minimum(float.compare) @@ -621,7 +621,7 @@ pub fn int_list_arg_minimum_test() { |> should.equal(Ok([4])) } -pub fn float_list_extrema_test() { +pub fn list_extrema_test() { // An empty lists returns an error [] |> maths.extrema(float.compare) diff --git a/test/gleam_community/sequences_test.gleam b/test/gleam_community/sequences_test.gleam index ef8b68f..2e4ff20 100644 --- a/test/gleam_community/sequences_test.gleam +++ b/test/gleam_community/sequences_test.gleam @@ -4,7 +4,7 @@ import gleam/yielder import gleam_community/maths import gleeunit/should -pub fn float_list_linear_space_test() { +pub fn list_linear_space_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Check that the function agrees, at some arbitrary input @@ -28,7 +28,6 @@ pub fn float_list_linear_space_test() { 0.0, tol, ) - result |> list.all(fn(x) { x == True }) |> should.be_true() @@ -42,7 +41,6 @@ pub fn float_list_linear_space_test() { 0.0, tol, ) - result |> list.all(fn(x) { x == True }) |> should.be_true() @@ -54,7 +52,6 @@ pub fn float_list_linear_space_test() { 0.0, tol, ) - result |> list.all(fn(x) { x == True }) |> should.be_true() @@ -69,7 +66,6 @@ pub fn float_list_linear_space_test() { 0.0, tol, ) - result |> list.all(fn(x) { x == True }) |> should.be_true() @@ -83,7 +79,6 @@ pub fn float_list_linear_space_test() { 0.0, tol, ) - result |> list.all(fn(x) { x == True }) |> should.be_true() @@ -96,7 +91,6 @@ pub fn float_list_linear_space_test() { 0.0, tol, ) - result |> list.all(fn(x) { x == True }) |> should.be_true() @@ -108,7 +102,31 @@ pub fn float_list_linear_space_test() { 0.0, tol, ) + result + |> list.all(fn(x) { x == True }) + |> should.be_true() + // Check that when start == stop and steps > 0, then + // the value (start/stop) is just repeated, since the + // step increment will be 0 + let assert Ok(linspace) = maths.linear_space(10.0, 10.0, 5, True) + let assert Ok(result) = + maths.all_close( + linspace |> yielder.to_list() |> list.zip([10.0, 10.0, 10.0, 10.0, 10.0]), + 0.0, + tol, + ) + result + |> list.all(fn(x) { x == True }) + |> should.be_true() + + let assert Ok(linspace) = maths.linear_space(10.0, 10.0, 5, False) + let assert Ok(result) = + maths.all_close( + linspace |> yielder.to_list() |> list.zip([10.0, 10.0, 10.0, 10.0, 10.0]), + 0.0, + tol, + ) result |> list.all(fn(x) { x == True }) |> should.be_true() @@ -118,12 +136,12 @@ pub fn float_list_linear_space_test() { |> should.be_error() } -pub fn float_list_logarithmic_space_test() { +pub fn list_logarithmic_space_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values // ---> With endpoint included - // - Positive start, stop, base + // - Positive start, stop let assert Ok(logspace) = maths.logarithmic_space(1.0, 3.0, 3, True, 10.0) let assert Ok(result) = maths.all_close( @@ -135,31 +153,7 @@ pub fn float_list_logarithmic_space_test() { |> list.all(fn(x) { x == True }) |> should.be_true() - // - Positive start, stop, negative base - let assert Ok(logspace) = maths.logarithmic_space(1.0, 3.0, 3, True, -10.0) - let assert Ok(result) = - maths.all_close( - logspace |> yielder.to_list() |> list.zip([-10.0, 100.0, -1000.0]), - 0.0, - tol, - ) - result - |> list.all(fn(x) { x == True }) - |> should.be_true() - - // - Positive start, negative stop, base - let assert Ok(logspace) = maths.logarithmic_space(1.0, -3.0, 3, True, -10.0) - let assert Ok(result) = - maths.all_close( - logspace |> yielder.to_list() |> list.zip([-10.0, -0.1, -0.001]), - 0.0, - tol, - ) - result - |> list.all(fn(x) { x == True }) - |> should.be_true() - - // - Positive start, base, negative stop + // - Positive start, negative stop let assert Ok(logspace) = maths.logarithmic_space(1.0, -3.0, 3, True, 10.0) let assert Ok(result) = maths.all_close( @@ -171,7 +165,7 @@ pub fn float_list_logarithmic_space_test() { |> list.all(fn(x) { x == True }) |> should.be_true() - // - Positive stop, base, negative start + // - Positive stop, negative start let assert Ok(logspace) = maths.logarithmic_space(-1.0, 3.0, 3, True, 10.0) let assert Ok(result) = maths.all_close( @@ -184,7 +178,7 @@ pub fn float_list_logarithmic_space_test() { |> should.be_true() // ----> Without endpoint included - // - Positive start, stop, base + // - Positive start, stop let assert Ok(logspace) = maths.logarithmic_space(1.0, 3.0, 3, False, 10.0) let assert Ok(result) = maths.all_close( @@ -198,12 +192,44 @@ pub fn float_list_logarithmic_space_test() { |> list.all(fn(x) { x == True }) |> should.be_true() + // Check that when start == stop and steps > 0, then + // the value (start/stop) is just repeated, since the + // step increment will be 0 + let assert Ok(logspace) = maths.logarithmic_space(5.0, 5.0, 5, True, 5.0) + let assert Ok(result) = + maths.all_close( + logspace + |> yielder.to_list() + |> list.zip([3125.0, 3125.0, 3125.0, 3125.0, 3125.0]), + 0.0, + tol, + ) + result + |> list.all(fn(x) { x == True }) + |> should.be_true() + let assert Ok(logspace) = maths.logarithmic_space(5.0, 5.0, 5, False, 5.0) + let assert Ok(result) = + maths.all_close( + logspace + |> yielder.to_list() + |> list.zip([3125.0, 3125.0, 3125.0, 3125.0, 3125.0]), + 0.0, + tol, + ) + result + |> list.all(fn(x) { x == True }) + |> should.be_true() + // A negative number of points does not work (-3) maths.logarithmic_space(1.0, 3.0, -3, True, 10.0) |> should.be_error() + + // A negative base does not work (-10) + maths.logarithmic_space(1.0, 3.0, 3, True, -10.0) + |> should.be_error() } -pub fn float_list_geometric_space_test() { +pub fn list_geometric_space_test() { let assert Ok(tol) = float.power(10.0, -6.0) // Check that the function agrees, at some arbitrary input // points, with known function values @@ -259,7 +285,36 @@ pub fn float_list_geometric_space_test() { |> list.all(fn(x) { x == True }) |> should.be_true() - // Test invalid input (start and stop can't be equal to 0.0) + // Check that when start == stop and steps > 0, then + // the value (start/stop) is just repeated, since the + // step increment will be 0 + let assert Ok(logspace) = maths.geometric_space(5.0, 5.0, 5, True) + let assert Ok(result) = + maths.all_close( + logspace + |> yielder.to_list() + |> list.zip([5.0, 5.0, 5.0, 5.0, 5.0]), + 0.0, + tol, + ) + result + |> list.all(fn(x) { x == True }) + |> should.be_true() + + let assert Ok(logspace) = maths.geometric_space(5.0, 5.0, 5, False) + let assert Ok(result) = + maths.all_close( + logspace + |> yielder.to_list() + |> list.zip([5.0, 5.0, 5.0, 5.0, 5.0]), + 0.0, + tol, + ) + result + |> list.all(fn(x) { x == True }) + |> should.be_true() + + // Test invalid input (start and stop can't be less than or equal to 0.0) maths.geometric_space(0.0, 1000.0, 3, False) |> should.be_error() @@ -271,7 +326,7 @@ pub fn float_list_geometric_space_test() { |> should.be_error() } -pub fn float_list_arange_test() { +pub fn list_arange_test() { // Positive start, stop, step maths.arange(1.0, 5.0, 1.0) |> yielder.to_list() @@ -311,45 +366,7 @@ pub fn float_list_arange_test() { |> should.equal([-5.0, -4.0, -3.0, -2.0]) } -pub fn float_list_exponential_space_test() { - let assert Ok(tolerance) = float.power(10.0, -6.0) - - // Check that the function agrees, at some arbitrary input - // points, with known function values - // ---> With endpoint included - let assert Ok(exp_space) = maths.exponential_space(1.0, 1000.0, 4, True) - let assert Ok(result) = - maths.all_close( - exp_space |> yielder.to_list() |> list.zip([1.0, 10.0, 100.0, 1000.0]), - 0.0, - tolerance, - ) - result - |> list.all(fn(x) { x == True }) - |> should.be_true() - - // ---> Without endpoint included - let assert Ok(exp_space) = maths.exponential_space(1.0, 1000.0, 4, False) - let assert Ok(result) = - maths.all_close( - exp_space - |> yielder.to_list() - |> list.zip([ - 1.0, 5.623413251903491, 31.622776601683793, 177.82794100389228, - ]), - 0.0, - tolerance, - ) - result - |> list.all(fn(x) { x == True }) - |> should.be_true() - - // A negative number of points does not work (-3) - maths.exponential_space(1.0, 1000.0, -3, True) - |> should.be_error() -} - -pub fn float_list_symmetric_space_test() { +pub fn list_symmetric_space_test() { let assert Ok(tolerance) = float.power(10.0, -6.0) // Check that the function agrees, at some arbitrary input @@ -370,6 +387,12 @@ pub fn float_list_symmetric_space_test() { |> yielder.to_list() |> should.equal([-15.0, -12.5, -10.0, -7.5, -5.0]) + // Negative Radius (simply reverses the order of the values) + let assert Ok(sym_space) = maths.symmetric_space(0.0, -5.0, 5) + sym_space + |> yielder.to_list() + |> should.equal([5.0, 2.5, 0.0, -2.5, -5.0]) + // Uneven number of points let assert Ok(sym_space) = maths.symmetric_space(0.0, 2.0, 4) let assert Ok(result) = @@ -384,6 +407,14 @@ pub fn float_list_symmetric_space_test() { |> list.all(fn(x) { x == True }) |> should.be_true() + // Check that when radius == 0 and steps > 0, then + // the value center value is just repeated, since the + // step increment will be 0 + let assert Ok(sym_space) = maths.symmetric_space(10.0, 0.0, 4) + sym_space + |> yielder.to_list() + |> should.equal([10.0, 10.0, 10.0, 10.0]) + // A negative number of points does not work (-5) maths.symmetric_space(0.0, 5.0, -5) |> should.be_error()