Work on int module

This commit is contained in:
NicklasXYZ 2023-01-29 18:04:11 +01:00
parent 061c13bd5c
commit 861c067f12
6 changed files with 405 additions and 39 deletions

View file

@ -26,14 +26,14 @@
//// * **Distances, sums, and products**
//// * [`sum`](#sum)
//// * [`product`](#product)
//// * [`cumulative_sum`](#cumulative_sum)
//// * [`cumulative_product`](#cumulative_product)
//// * [`norm`](#norm)
//// * [`minkowski_distance`](#minkowski_distance)
//// * [`euclidean_distance`](#euclidean_distance)
//// * [`manhatten_distance`](#manhatten_distance)
//// * [`cumulative_sum`](#cumulative_sum)
//// * [`cumulative_product`](#cumulative_product)
//// * **Ranges and intervals**
//// * [`arrange`](#arrange)
//// * [`arange`](#arange)
//// * [`linear_space`](#linear_space)
//// * [`logarithmic_space`](#logarithmic_space)
//// * [`geometric_space`](#geometric_space)
@ -252,7 +252,7 @@ pub fn euclidean_distance(
/// </a>
/// </div>
///
/// Calculcate the Euclidean distance between two lists (representing vectors):
/// Calculcate the Manhatten distance between two lists (representing vectors):
///
/// \\[
/// \sum_{i=1}^n \left|x_i - x_j \right|
@ -271,11 +271,11 @@ pub fn euclidean_distance(
/// assert Ok(tol) = floatx.power(-10.0, -6.0)
///
/// // Empty lists returns 0.0
/// float_list.manhatten_distance([], [], 1.0)
/// float_list.manhatten_distance([], [])
/// |> should.equal(Ok(0.0))
///
/// // Differing lengths returns error
/// float_list.manhatten_distance([], [1.0], 1.0)
/// float_list.manhatten_distance([], [1.0])
/// |> should.be_error()
///
/// assert Ok(result) = float_list.manhatten_distance([0.0, 0.0], [1.0, 2.0])
@ -516,17 +516,17 @@ pub fn geometric_space(
/// import gleam_community/maths/float_list
///
/// pub fn example () {
/// float_list.arrange(1.0, 5.0, 1.0)
/// float_list.arange(1.0, 5.0, 1.0)
/// |> should.equal([1.0, 2.0, 3.0, 4.0])
///
/// // No points returned since
/// // start smaller than stop and positive step
/// float_list.arrange(5.0, 1.0, 1.0)
/// float_list.arange(5.0, 1.0, 1.0)
/// |> should.equal([])
///
/// // Points returned since
/// // start smaller than stop but negative step
/// float_list.arrange(5.0, 1.0, -1.0)
/// float_list.arange(5.0, 1.0, -1.0)
/// |> should.equal([5.0, 4.0, 3.0, 2.0])
/// }
/// </details>
@ -537,7 +537,7 @@ pub fn geometric_space(
/// </a>
/// </div>
///
pub fn arrange(start: Float, stop: Float, step: Float) -> List(Float) {
pub fn arange(start: Float, stop: Float, step: Float) -> List(Float) {
case start >=. stop && step >. 0.0 || start <=. stop && step <. 0.0 {
True -> []
False -> {
@ -556,10 +556,6 @@ pub fn arrange(start: Float, stop: Float, step: Float) -> List(Float) {
}
}
// fn do_arrange(start: Float, step: Float, direction: Float) -> Float {
// case
// }
/// <div style="text-align: right;">
/// <a href="https://github.com/gleam-community/maths/issues">
/// <small>Spot a typo? Open an issue!</small>
@ -629,15 +625,15 @@ pub fn sum(arr: List(Float)) -> Float {
/// import gleam_community/maths/float_list
///
/// pub fn example () {
/// // An empty list returns an error
/// // An empty list returns 0.0
/// []
/// |> float_list.sum()
/// |> should.equal(0.)
/// |> should.equal(0.0)
///
/// // Valid input returns a result
/// [1., 2., 3.]
/// [1.0, 2.0, 3.0]
/// |> float_list.product()
/// |> should.equal(6.)
/// |> should.equal(6.0)
/// }
/// </details>
///
@ -652,7 +648,7 @@ pub fn product(arr: List(Float)) -> Float {
[] -> 0.0
_ ->
arr
|> list.fold(0.0, fn(acc: Float, a: Float) -> Float { a *. acc })
|> list.fold(1.0, fn(acc: Float, a: Float) -> Float { a *. acc })
}
}

View file

@ -30,12 +30,13 @@
//// * [`flip_sign`](#flipsign)
//// * **Misc. mathematical functions**
//// * [`minimum`](#min)
//// * [`maxximum`](#max)
//// * [`maximum`](#max)
//// * [`minmax`](#minmax)
//// * **Division functions**
//// * [`gcd`](#gcd)
//// * [`lcm`](#lcm)
//// * [`divisors`](#divisors)
//// * [`proper_divisors`](#proper_divisors)
//// * **Combinatorial functions**
//// * [`combination`](#combination)
//// * [`factorial`](#factorial)
@ -532,7 +533,7 @@ pub fn is_power(x: Int, y: Int) -> Bool {
/// </a>
/// </div>
///
/// A function that tests whether a given integer value $$x \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>
@ -564,8 +565,17 @@ pub fn is_power(x: Int, y: Int) -> Bool {
/// </a>
/// </div>
///
pub fn is_perfect(x: Int, y: Int) -> Bool {
todo
pub fn is_perfect(n: Int) -> Bool {
do_sum(proper_divisors(n)) == n
}
fn do_sum(arr: List(Int)) -> Int {
case arr {
[] -> 0
_ ->
arr
|> list.fold(0, fn(acc: Int, a: Int) -> Int { a + acc })
}
}
/// <div style="text-align: right;">
@ -574,7 +584,46 @@ pub fn is_perfect(x: Int, y: Int) -> Bool {
/// </a>
/// </div>
///
/// The function returns all the positive divisors of an integer.
/// The function returns all the positive divisors of an integer, excluding the number iteself.
///
/// <details>
/// <summary>Example:</summary>
///
/// import gleeunit/should
/// import gleam_community/maths/int as intx
///
/// pub fn example() {
/// intx.proper_divisors(4)
/// |> should.equal([1, 2])
///
/// intx.proper_divisors(6)
/// |> should.equal([1, 2, 3])
///
/// intx.proper_divisors(13)
/// |> should.equal([1])
///
/// }
/// </details>
///
/// <div style="text-align: right;">
/// <a href="#">
/// <small>Back to top </small>
/// </a>
/// </div>
///
pub fn proper_divisors(n: Int) -> List(Int) {
let divisors: List(Int) = find_divisors(n)
divisors
|> list.take(list.length(divisors) - 1)
}
/// <div style="text-align: right;">
/// <a href="https://github.com/gleam-community/maths/issues">
/// <small>Spot a typo? Open an issue!</small>
/// </a>
/// </div>
///
/// The function returns all the positive divisors of an integer, including the number iteself.
///
/// <details>
/// <summary>Example:</summary>
@ -588,6 +637,9 @@ pub fn is_perfect(x: Int, y: Int) -> Bool {
///
/// intx.divisors(6)
/// |> should.equal([1, 2, 3, 6])
///
/// intx.proper_divisors(13)
/// |> should.equal([1, 13])
/// }
/// </details>
///
@ -597,8 +649,26 @@ pub fn is_perfect(x: Int, y: Int) -> Bool {
/// </a>
/// </div>
///
pub fn divisors(x: Int) -> List(Int) {
todo
pub fn divisors(n: Int) -> List(Int) {
find_divisors(n)
}
pub fn find_divisors(n: Int) -> List(Int) {
let nabs: Float = float.absolute_value(to_float(n))
assert Ok(sqrt_result) = floatx.square_root(nabs)
let max: Int = floatx.to_int(sqrt_result) + 1
list.range(2, max)
|> list.fold(
[1, n],
fn(acc: List(Int), i: Int) -> List(Int) {
case n % i == 0 {
True -> [i, n / i, ..acc]
False -> acc
}
},
)
|> list.unique()
|> list.sort(int.compare)
}
/// <div style="text-align: right;">

View file

@ -26,9 +26,9 @@
//// * **Distances, sums and products**
//// * [`sum`](#sum)
//// * [`product`](#product)
//// * [`norm`](#norm)
//// * [`cumulative_sum`](#cumulative_sum)
//// * [`cumulative_product`](#cumulative_product)
//// * [`manhatten_distance`](#manhatten_distance)
//// * **Misc. mathematical functions**
//// * [`maximum`](#maximum)
//// * [`minimum`](#minimum)
@ -42,6 +42,164 @@ import gleam/float
import gleam/pair
import gleam_community/maths/int as intx
/// <div style="text-align: right;">
/// <a href="https://github.com/gleam-community/maths/issues">
/// <small>Spot a typo? Open an issue!</small>
/// </a>
/// </div>
///
/// Calculcate the Manhatten distance between two lists (representing vectors):
///
/// \\[
/// \sum_{i=1}^n \left|x_i - x_j \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, j$$.
///
/// <details>
/// <summary>Example:</summary>
///
/// import gleeunit/should
/// import gleam_community/maths/float as floatx
/// import gleam_community/maths/float_list
///
/// pub fn example () {
/// // Empty lists returns 0
/// float_list.manhatten_distance([], [])
/// |> should.equal(Ok(0.0))
///
/// // Differing lengths returns error
/// float_list.manhatten_distance([], [1])
/// |> should.be_error()
///
/// assert Ok(result) = int_list.manhatten_distance([0, 0], [1, 2])
/// result
/// |> should.equal(3)
/// }
/// </details>
///
/// <div style="text-align: right;">
/// <a href="#">
/// <small>Back to top </small>
/// </a>
/// </div>
///
pub fn manhatten_distance(
xarr: List(Int),
yarr: List(Int),
) -> Result(Int, 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 ->
list.zip(xarr, yarr)
|> list.map(fn(tuple: #(Int, Int)) -> Int {
int.absolute_value(pair.first(tuple) - pair.second(tuple))
})
|> sum()
|> 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>
///
/// Calculcate the sum of the elements in a list:
///
/// \\[
/// \sum_{i=1}^n x_i
/// \\]
///
/// In the formula, $$n$$ is the length of the list and $$x_i$$ is the value in the input list indexed by $$i$$.
///
/// <details>
/// <summary>Example:</summary>
///
/// import gleeunit/should
/// import gleam_community/maths/float_list
///
/// pub fn example () {
/// // An empty list returns 0
/// []
/// |> float_list.sum()
/// |> should.equal(0)
///
/// // Valid input returns a result
/// [1, 2, 3]
/// |> float_list.sum()
/// |> should.equal(6)
/// }
/// </details>
///
/// <div style="text-align: right;">
/// <a href="#">
/// <small>Back to top </small>
/// </a>
/// </div>
///
pub fn sum(arr: List(Int)) -> Int {
case arr {
[] -> 0
_ ->
arr
|> list.fold(0, fn(acc: Int, a: Int) -> Int { a + acc })
}
}
/// <div style="text-align: right;">
/// <a href="https://github.com/gleam-community/maths/issues">
/// <small>Spot a typo? Open an issue!</small>
/// </a>
/// </div>
///
/// Calculcate the product of the elements in a list:
///
/// \\[
/// \prod_{i=1}^n x_i
/// \\]
///
/// In the formula, $$n$$ is the length of the list and $$x_i$$ is the value in the input list indexed by $$i$$.
///
/// <details>
/// <summary>Example:</summary>
///
/// import gleeunit/should
/// import gleam_community/maths/float_list
///
/// pub fn example () {
/// // An empty list returns an error
/// []
/// |> float_list.sum()
/// |> should.equal(0.)
///
/// // Valid input returns a result
/// [1., 2., 3.]
/// |> float_list.product()
/// |> should.equal(6.)
/// }
/// </details>
///
/// <div style="text-align: right;">
/// <a href="#">
/// <small>Back to top </small>
/// </a>
/// </div>
///
pub fn product(arr: List(Int)) -> Int {
case arr {
[] -> 0
_ ->
arr
|> list.fold(1, fn(acc: Int, a: Int) -> Int { a * acc })
}
}
/// <div style="text-align: right;">
/// <a href="https://github.com/gleam-community/maths/issues">
/// <small>Spot a typo? Open an issue!</small>

View file

@ -88,7 +88,7 @@ pub fn float_list_minkowski_test() {
float_list.minkowski_distance([], [], 1.0)
|> should.equal(Ok(0.0))
// Differing lenghths returns error
// Differing lengths returns error
float_list.minkowski_distance([], [1.0], 1.0)
|> should.be_error()
@ -141,7 +141,7 @@ pub fn float_list_euclidean_test() {
float_list.euclidean_distance([], [])
|> should.equal(Ok(0.0))
// Differing lenghths returns error
// Differing lengths returns error
float_list.euclidean_distance([], [1.0])
|> should.be_error()
@ -159,7 +159,7 @@ pub fn float_list_manhatten_test() {
float_list.manhatten_distance([], [])
|> should.equal(Ok(0.0))
// Differing lenghths returns error
// Differing lengths returns error
float_list.manhatten_distance([], [1.0])
|> should.be_error()
@ -353,35 +353,35 @@ pub fn float_list_geometric_space_test() {
|> should.be_error()
}
pub fn float_list_arrange_test() {
pub fn float_list_arange_test() {
// Positive start, stop, step
float_list.arrange(1.0, 5.0, 1.0)
float_list.arange(1.0, 5.0, 1.0)
|> should.equal([1.0, 2.0, 3.0, 4.0])
float_list.arrange(1.0, 5.0, 0.5)
float_list.arange(1.0, 5.0, 0.5)
|> should.equal([1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5])
float_list.arrange(1.0, 2.0, 0.25)
float_list.arange(1.0, 2.0, 0.25)
|> should.equal([1.0, 1.25, 1.5, 1.75])
// Reverse (switch start/stop largest/smallest value)
float_list.arrange(5.0, 1.0, 1.0)
float_list.arange(5.0, 1.0, 1.0)
|> should.equal([])
// Reverse negative step
float_list.arrange(5.0, 1.0, -1.0)
float_list.arange(5.0, 1.0, -1.0)
|> should.equal([5.0, 4.0, 3.0, 2.0])
// Positive start, negative stop, step
float_list.arrange(5.0, -1.0, -1.0)
float_list.arange(5.0, -1.0, -1.0)
|> should.equal([5.0, 4.0, 3.0, 2.0, 1.0, 0.0])
// Negative start, stop, step
float_list.arrange(-5.0, -1.0, -1.0)
float_list.arange(-5.0, -1.0, -1.0)
|> should.equal([])
// Negative start, stop, positive step
float_list.arrange(-5.0, -1.0, 1.0)
float_list.arange(-5.0, -1.0, 1.0)
|> should.equal([-5.0, -4.0, -3.0, -2.0])
}
@ -445,6 +445,22 @@ pub fn float_list_extrema_test() {
|> should.equal(Ok(#(1.0, 4.0)))
}
pub fn float_list_sum_test() {
// An empty list returns 0
[]
|> float_list.sum()
|> should.equal(0.0)
// Valid input returns a result
[1.0, 2.0, 3.0]
|> float_list.sum()
|> should.equal(6.0)
[-2.0, 4.0, 6.0]
|> float_list.sum()
|> should.equal(8.0)
}
pub fn float_list_cumulative_sum_test() {
// An empty lists returns an empty list
[]
@ -455,6 +471,26 @@ pub fn float_list_cumulative_sum_test() {
[1.0, 2.0, 3.0]
|> float_list.cumulative_sum()
|> should.equal([1.0, 3.0, 6.0])
[-2.0, 4.0, 6.0]
|> float_list.cumulative_sum()
|> should.equal([-2.0, 2.0, 8.0])
}
pub fn float_list_product_test() {
// An empty list returns 0
[]
|> float_list.product()
|> should.equal(0.0)
// Valid input returns a result
[1.0, 2.0, 3.0]
|> float_list.product()
|> should.equal(6.0)
[-2.0, 4.0, 6.0]
|> float_list.product()
|> should.equal(-48.0)
}
pub fn float_list_cumulative_product_test() {
@ -467,4 +503,8 @@ pub fn float_list_cumulative_product_test() {
[1.0, 2.0, 3.0]
|> float_list.cumumlative_product()
|> should.equal([1.0, 2.0, 6.0])
[-2.0, 4.0, 6.0]
|> float_list.cumumlative_product()
|> should.equal([-2.0, -8.0, -48.0])
}

View file

@ -69,6 +69,22 @@ pub fn int_list_extrema_test() {
|> should.equal(Ok(#(1, 4)))
}
pub fn int_list_sum_test() {
// An empty list returns 0
[]
|> int_list.sum()
|> should.equal(0)
// Valid input returns a result
[1, 2, 3]
|> int_list.sum()
|> should.equal(6)
[-2, 4, 6]
|> int_list.sum()
|> should.equal(8)
}
pub fn int_list_cumulative_sum_test() {
// An empty lists returns an empty list
[]
@ -79,6 +95,26 @@ pub fn int_list_cumulative_sum_test() {
[1, 2, 3]
|> int_list.cumulative_sum()
|> should.equal([1, 3, 6])
[-2, 4, 6]
|> int_list.cumulative_sum()
|> should.equal([-2, 2, 8])
}
pub fn int_list_product_test() {
// An empty list returns 0
[]
|> int_list.product()
|> should.equal(0)
// Valid input returns a result
[1, 2, 3]
|> int_list.product()
|> should.equal(6)
[-2, 4, 6]
|> int_list.product()
|> should.equal(-48)
}
pub fn int_list_cumulative_product_test() {
@ -91,4 +127,22 @@ pub fn int_list_cumulative_product_test() {
[1, 2, 3]
|> int_list.cumumlative_product()
|> should.equal([1, 2, 6])
[-2, 4, 6]
|> int_list.cumumlative_product()
|> should.equal([-2, -8, -48])
}
pub fn int_list_manhatten_test() {
// Empty lists returns 0
int_list.manhatten_distance([], [])
|> should.equal(Ok(0))
// Differing lengths returns error
int_list.manhatten_distance([], [1])
|> should.be_error()
assert Ok(result) = int_list.manhatten_distance([0, 0], [1, 2])
result
|> should.equal(3)
}

View file

@ -277,3 +277,51 @@ pub fn int_to_float_test() {
intx.to_float(1)
|> should.equal(1.0)
}
pub fn int_proper_divisors_test() {
intx.proper_divisors(2)
|> should.equal([1])
intx.proper_divisors(6)
|> io.debug()
|> should.equal([1, 2, 3])
intx.proper_divisors(13)
|> should.equal([1])
intx.proper_divisors(18)
|> should.equal([1, 2, 3, 6, 9])
}
pub fn int_divisors_test() {
intx.divisors(2)
|> should.equal([1, 2])
intx.divisors(6)
|> should.equal([1, 2, 3, 6])
intx.divisors(13)
|> should.equal([1, 13])
intx.divisors(18)
|> should.equal([1, 2, 3, 6, 9, 18])
}
pub fn int_is_perfect_test() {
intx.is_perfect(6)
|> should.equal(True)
intx.is_perfect(28)
|> should.equal(True)
intx.is_perfect(496)
|> should.equal(True)
intx.is_perfect(1)
|> should.equal(False)
intx.is_perfect(3)
|> should.equal(False)
intx.is_perfect(13)
|> should.equal(False)
}