gleam_community/maths

Functions

pub fn absolute_difference(a: Float, b: Float) -> Float

The absolute difference:

x,yR,  xyR+. \forall x, y \in \mathbb{R}, \; |x - y| \in \mathbb{R}_{+}.

The function takes two inputs xx and yy and returns a positive float value which is the absolute difference of the inputs.

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.absolute_difference(-10.0, 10.0)
  |> should.equal(20.0)

  maths.absolute_difference(0.0, -2.0)
  |> should.equal(2.0)
}
pub fn acos(x: Float) -> Result(Float, Nil)

The inverse cosine function:

x[1,1],  cos1(x)=y[0,π] \forall x \in [-1, 1], \; \cos^{-1}{(x)} = y \in [0, \pi ]

The function takes a number xx in its domain [1,1][-1, 1] as input and returns a numeric value yy that lies in the range [0,π][0, \pi ] (an angle in radians). If the input value is outside the domain of the function an error is returned.

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.acos(1.0)
  |> should.equal(Ok(0.0))

  maths.acos(1.1)
  |> should.be_error()

  maths.acos(-1.1)
  |> should.be_error()
}
pub fn acosh(x: Float) -> Result(Float, Nil)

The inverse hyperbolic cosine function:

x[1,+),  cosh1(x)=y[0,+) \forall x \in [1, +\infty), \; \cosh^{-1}{(x)} = y \in [0, +\infty)

The function takes a number xx in its domain [1,+)[1, +\infty) as input and returns a numeric value yy that lies in the range [0,+)[0, +\infty) (an angle in radians). If the input value is outside the domain of the function an error is returned.

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.acosh(1.0)
  |> should.equal(Ok(0.0))

  maths.acosh(0.0)
  |> should.be_error()
}
pub fn all_close(
  arr: List(#(Float, Float)),
  rtol: Float,
  atol: Float,
) -> List(Bool)

Determine if each value xix_i is close to or equivalent to its corresponding reference value yiy_i, in a list of value pairs (xi,yi)(x_i, y_i), based on supplied relative rtolr_{tol} and absolute atola_{tol} tolerance values. The equivalence of each pair (xi,yi)(x_i, y_i) is determined by the equation:

xiyi(atol+rtolyi),  i=1,,n. |x_i - y_i| \leq (a_{tol} + r_{tol} \cdot |y_i|), \; \forall i=1,…,n.

A list of Bool values is returned, where each entry indicates if the corresponding pair satisfies the condition. If all conditions are satisfied, the list will contain only True values.

Example:
import gleam/list
import gleeunit/should
import gleam_community/maths

pub fn example () {
  let value = 99.0
  let reference_value = 100.0
  let xarr = list.repeat(value, 42)
  let yarr = list.repeat(reference_value, 42)
  let arr = list.zip(xarr, yarr)
  // We set 'absolute_tolerance' and 'relative_tolerance' such that
  // the values are equivalent if 'value' is within 1 percent of
  // 'reference_value' +/- 0.1
  let relative_tolerance = 0.01
  let absolute_tolerance = 0.1
  let assert Ok(result) =
    maths.all_close(arr, relative_tolerance, absolute_tolerance)
  result
  |> list.all(fn(x) { x == True })
  |> should.be_true()
}
pub fn arg_maximum(
  arr: List(a),
  compare: fn(a, a) -> Order,
) -> Result(List(Int), Nil)

Returns the indices of the maximum values in a given list.

Example:
import gleam/float
import gleeunit/should
import gleam_community/maths

pub fn example () {
  []
  |> maths.arg_maximum(float.compare)
  |> should.be_error()

  [4.0, 4.0, 3.0, 2.0, 1.0]
  |> maths.arg_maximum(float.compare)
  |> should.equal(Ok([0, 1]))
}
pub fn arg_minimum(
  arr: List(a),
  compare: fn(a, a) -> Order,
) -> Result(List(Int), Nil)

Returns the indices of the minimum values in a given list.

Example:
import gleam/float
import gleeunit/should
import gleam_community/maths

pub fn example () {
  []
  |> maths.arg_minimum(float.compare)
  |> should.be_error()

  [4.0, 4.0, 3.0, 2.0, 1.0]
  |> maths.arg_minimum(float.compare)
  |> should.equal(Ok([4]))
}
pub fn asin(x: Float) -> Result(Float, Nil)

The inverse sine function:

x[1,1],  sin1(x)=y(,+) \forall x \in [-1, 1], \; \sin^{-1}{(x)} = y \in (-\infty, +\infty)

The function takes a number xx in its domain [1,1][-1, 1] as input and returns a numeric value yy that lies in the range [π2,π2][-\frac{\pi}{2}, \frac{\pi}{2}] (an angle in radians). If the input value is outside the domain of the function an error is returned.

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.asin(0.0)
  |> should.equal(Ok(0.0))

  maths.asin(1.1)
  |> should.be_error()

  maths.asin(-1.1)
  |> should.be_error()
}
pub fn asinh(x: Float) -> Float

The inverse hyperbolic sine function:

x(,),  sinh1(x)=y(,+) \forall x \in (-\infty, \infty), \; \sinh^{-1}{(x)} = y \in (-\infty, +\infty)

The function takes a number xx in its domain (,+)(-\infty, +\infty) as input and returns a numeric value yy that lies in the range (,+)(-\infty, +\infty) (an angle in radians).

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.asinh(0.0)
  |> should.equal(0.0)
}
pub fn atan(x: Float) -> Float

The inverse tangent function:

x(,),  tan1(x)=y[π2,π2] \forall x \in (-\infty, \infty), \; \tan^{-1}{(x)} = y \in [-\frac{\pi}{2}, \frac{\pi}{2}]

The function takes a number xx in its domain (,+)(-\infty, +\infty) as input and returns a numeric value yy that lies in the range [π2,π2][-\frac{\pi}{2}, \frac{\pi}{2}] (an angle in radians).

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.atan(0.0)
  |> should.equal(0.0)
}
pub fn atan2(y: Float, x: Float) -> Float

The inverse 2-argument tangent function:

atan2(y,x)={tan1(yx)if x>0,tan1(yx)+πif x<0 and y0,tan1(yx)πif x<0 and y<0,+π2if x=0 and y>0,π2if x=0 and y<0,undefinedif x=0 and y=0. \text{atan2}(y, x) = \begin{cases} \tan^{-1}(\frac y x) &\text{if } x > 0, \\ \tan^{-1}(\frac y x) + \pi &\text{if } x < 0 \text{ and } y \ge 0, \\ \tan^{-1}(\frac y x) - \pi &\text{if } x < 0 \text{ and } y < 0, \\ +\frac{\pi}{2} &\text{if } x = 0 \text{ and } y > 0, \\ -\frac{\pi}{2} &\text{if } x = 0 \text{ and } y < 0, \\ \text{undefined} &\text{if } x = 0 \text{ and } y = 0. \end{cases}

The function returns the angle in radians from the x-axis to the line containing the origin (0,0)(0, 0) and a point given as input with coordinates (x,y)(x, y). The numeric value returned by atan2(y,x)\text{atan2}(y, x) is in the range [π,π][-\pi, \pi].

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.atan2(0.0, 0.0)
  |> should.equal(0.0)
}
pub fn atanh(x: Float) -> Result(Float, Nil)

The inverse hyperbolic tangent function:

x(1,1),  tanh1(x)=y(,+) \forall x \in (-1, 1), \; \tanh^{-1}{(x)} = y \in (-\infty, +\infty)

The function takes a number xx in its domain (1,1)(-1, 1) as input and returns a numeric value yy that lies in the range (,)(-\infty, \infty) (an angle in radians). If the input value is outside the domain of the function an error is returned.

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.atanh(0.0)
  |> should.equal(Ok(0.0))

  maths.atanh(1.0)
  |> should.be_error()

  maths.atanh(-1.0)
  |> should.be_error()
}
pub fn beta(x: Float, y: Float) -> Float

The beta function over the real numbers:

B(x,y)=Γ(x)Γ(y)Γ(x+y) \text{B}(x, y) = \frac{\Gamma(x) \cdot \Gamma(y)}{\Gamma(x + y)}

The beta function is evaluated through the use of the gamma function.

pub fn braycurtis_distance(
  arr: List(#(Float, Float)),
) -> Result(Float, Nil)

Calculate the Bray-Curtis distance between two lists:

i=1nxiyii=1nxi+yi \frac{\sum_{i=1}^n \left| x_i - y_i \right|} {\sum_{i=1}^n \left| x_i + y_i \right|}

In the formula, nn is the length of the two lists, and xi,yix_i, y_i are the values in the respective input lists indexed by ii.

The Bray-Curtis distance is in the range [0,1][0, 1] if all entries xi,yix_i, y_i are positive.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.braycurtis_distance([])
  |> should.be_error()

  maths.braycurtis_distance([#(1.0, 3.0), #(2.0, 4.0)])
  |> should.equal(Ok(0.4))
}
pub fn braycurtis_distance_with_weights(
  arr: List(#(Float, Float, Float)),
) -> Result(Float, Nil)

Calculate the weighted Bray-Curtis distance between two lists:

i=1nwixiyii=1nwixi+yi \frac{\sum_{i=1}^n w_{i} \left| x_i - y_i \right|} {\sum_{i=1}^n w_{i}\left| x_i + y_i \right|}

In the formula, nn is the length of the two lists, and xi,yix_i, y_i are the values in the respective input lists indexed by ii, while the wiR+w_i \in \mathbb{R}_{+} are corresponding positive weights.

The Bray-Curtis distance is in the range [0,1][0, 1] if all entries xi,yix_i, y_i are positive and wi=1.0  i=1nw_i = 1.0\;\forall i=1…n.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.braycurtis_distance_with_weights([])
  |> should.be_error()

  maths.braycurtis_distance_with_weights([#(1.0, 3.0, 0.5), #(2.0, 4.0, 1.0)])
  |> should.equal(Ok(0.375))
}
pub fn canberra_distance(
  arr: List(#(Float, Float)),
) -> Result(Float, Nil)

Calculate the Canberra distance between two lists:

i=1nxiyixi+yi \sum_{i=1}^n \frac{\left| x_i - y_i \right|} {\left| x_i \right| + \left| y_i \right|}

In the formula, nn is the length of the two lists, and xi,yix_i, y_i are the values in the respective input lists indexed by ii.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.canberra_distance([])
  |> should.be_error()

  maths.canberra_distance([#(1.0, -2.0), #(2.0, -1.0)])
  |> should.equal(Ok(2.0))
}
pub fn canberra_distance_with_weights(
  arr: List(#(Float, Float, Float)),
) -> Result(Float, Nil)

Calculate the weighted Canberra distance between two lists:

i=1nwixiyixi+yi \sum_{i=1}^n w_{i}\frac{\left| x_i - y_i \right|} {\left| x_i \right| + \left| y_i \right|}

In the formula, nn is the length of the two lists, and xi,yix_i, y_i are the values in the respective input lists indexed by ii, while the wiR+w_i \in \mathbb{R}_{+} are corresponding positive weights.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.canberra_distance_with_weights([])
  |> should.be_error()

  maths.canberra_distance_with_weights([#(1.0, -2.0, 0.5), #(2.0, -1.0, 1.0)])
  |> should.equal(Ok(1.5))
}
pub fn cartesian_product(
  xset: Set(a),
  yset: Set(b),
) -> Set(#(a, b))

Generate a set containing all combinations of pairs of elements coming from two given sets.

Example:
import gleam/set
import gleeunit/should
import gleam_community/maths

pub fn example () {
  set.from_list([])
  |> maths.cartesian_product(set.from_list([]))
  |> should.equal(set.from_list([]))

  set.from_list([1.0, 10.0])
  |> maths.cartesian_product(set.from_list([1.0, 2.0]))
  |> should.equal(
    set.from_list([#(1.0, 1.0), #(1.0, 2.0), #(10.0, 1.0), #(10.0, 2.0)]),
  )
}
pub fn cartesian_to_polar(x: Float, y: Float) -> #(Float, Float)

Converts Cartesian coordinates (x,y)(x, y) to polar coordinates (r,θ)(r, \theta).

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.cartesian_to_polar(1.0, 0.0)
  |> should.equal((1.0, 0.0))

  maths.cartesian_to_polar(0.0, 1.0)
  |> should.equal((1.0, float.pi() /. 2.0))
}
pub fn chebyshev_distance(
  arr: List(#(Float, Float)),
) -> Result(Float, Nil)

Calculate the Chebyshev distance between two lists (representing vectors):

maxi=1nxiyi \text{max}_{i=1}^n \left|x_i - y_i \right|

In the formula, nn is the length of the two lists and xi,yix_i, y_i are the values in the respective input lists indexed by ii.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.chebyshev_distance([#(-5.0, -1.0), #(-10.0, -12.0), #(-3.0, -3.0)])
  |> should.equal(Ok(4.0))
}
pub fn chebyshev_distance_with_weights(
  arr: List(#(Float, Float, Float)),
) -> Result(Float, Nil)

Calculate the weighted Chebyshev distance between two lists (representing vectors):

maxi=1nwixiyi \text{max}_{i=1}^n w_i \left|x_i - y_i \right|

In the formula, nn is the length of the two lists and xi,yix_i, y_i are the values in the respective input lists indexed by ii, while the wiR+w_i \in \mathbb{R}_{+} are corresponding positive weights.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.chebyshev_distance_with_weights([
    #(-5.0, -1.0, 0.5),
    #(-10.0, -12.0, 1.0),
    #(-3.0, -3.0, 1.0),
  ])
  |> should.equal(Ok(2.0))
}
pub fn combination(n: Int, k: Int) -> Result(Int, Nil)

A combinatorial function for computing the number of kk-combinations of nn elements without repetitions:

C(n,k)=(nk)=n!k!(nk)! C(n, k) = \binom{n}{k} = \frac{n!}{k! (n-k)!}

Also known as “nn choose kk” or the binomial coefficient.

Details

A kk-combination without repetition is a sequence of kk elements selected from nn elements where the order of selection does not matter and elements are not allowed to repeat. For example, consider selecting 2 elements from a list of 3 elements: ["A", "B", "C"]. In this case, possible selections are:

  • ["A", "B"]
  • ["A", "C"]
  • ["B", "C"]
Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.combination(-1, 1)
  |> should.be_error()

  maths.combination(4, 0)
  |> should.equal(Ok(1))

  maths.combination(4, 4)
  |> should.equal(Ok(1))

  maths.combination(13, 5)
  |> should.equal(Ok(1287))
}
pub fn combination_with_repetitions(
  n: Int,
  k: Int,
) -> Result(Int, Nil)

A combinatorial function for computing the number of kk-combinations of nn elements with repetitions:

C(n,k)=(n+k1k)=(n+k1)!k!(n1)! C^*(n, k) = \binom{n + k - 1}{k} = \frac{(n + k - 1)!}{k! (n - 1)!}

Also known as the “stars and bars” problem in maths. Furthermore, the implementation uses an efficient iterative multiplicative formula for computing the result.

Details

A kk-combination with repetitions is a sequence of kk elements selected from nn elements where the order of selection does not matter and elements are allowed to repeat. For example, consider selecting 2 elements from a list of 3 elements: ["A", "B", "C"]. In this case, possible selections are:

  • ["A", "A"], ["A", "B"], ["A", "C"]
  • ["B", "B"], ["B", "C"], ["C", "C"]
Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.combination_with_repetitions(-1, 1)
  |> should.be_error()

  maths.combination_with_repetitions(2, 3)
  |> should.equal(Ok(4))

  maths.combination_with_repetitions(13, 5)
  |> should.equal(Ok(6188))
}
pub fn copy_sign(x: Float, y: Float) -> Float

The function takes two arguments x,yRx, y \in \mathbb{R} and returns xx such that it has the same sign as yy.

pub fn correlation(
  arr: List(#(Float, Float)),
) -> Result(Float, Nil)

Calculate Pearson’s sample correlation coefficient to determine the linear relationship between the elements in two lists of equal length. The correlation coefficient rxy[1,1]r_{xy} \in [-1, 1] is calculated as:

rxy=i=1n(xixˉ)(yiyˉ)i=1n(xixˉ)2i=1n(yiyˉ)2 r_{xy} =\frac{\sum ^n _{i=1}(x_i - \bar{x})(y_i - \bar{y})}{\sqrt{\sum^n _{i=1}(x_i - \bar{x})^2} \sqrt{\sum^n _{i=1}(y_i - \bar{y})^2}}

In the formula, nn is the sample size (the length of the input lists), xix_i, yiy_i are the corresponding sample points indexed by ii and xˉ\bar{x}, yˉ\bar{y} are the sample means.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  // An empty lists returns an error
  maths.correlation([], [])
  |> should.be_error()

  // Perfect positive correlation
  let xarr =
    list.range(0, 100)
    |> list.map(fn(x) { int.to_float(x) })
  let yarr =
    list.range(0, 100)
    |> list.map(fn(y) { int.to_float(y) })
  list.zip(xarr, yarr)
  |> maths.correlation()
  |> should.equal(Ok(1.0))

  // Perfect negative correlation
  let xarr =
    list.range(0, 100)
    |> list.map(fn(x) { -1.0 *. int.to_float(x) })
  let yarr =
    list.range(0, 100)
    |> list.map(fn(y) { int.to_float(y) })
  list.zip(xarr, yarr)
  |> maths.correlation()
  |> should.equal(Ok(-1.0))

  // No correlation (independent variables)
  let xarr = [1.0, 2.0, 3.0, 4.0]
  let yarr = [5.0, 5.0, 5.0, 5.0]
  list.zip(xarr, yarr)
  |> maths.correlation()
  |> should.equal(Ok(0.0))
}
pub fn cos(x: Float) -> Float

The cosine function:

x(,+),  cos(x)=y[1,1] \forall x \in (-\infty, +\infty), \; \cos{(x)} = y \in [-1, 1]

The function takes a number xx in its domain (,)(-\infty, \infty) (an angle in radians) as input and returns a numeric value yy that lies in the range [1,1][-1, 1].

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.cos(0.0)
  |> should.equal(1.0)

  maths.cos(maths.pi())
  |> should.equal(-1.0)
}
pub fn cosh(x: Float) -> Float

The hyperbolic cosine function:

x(,),  cosh(x)=y(,+) \forall x \in (-\infty, \infty), \; \cosh{(x)} = y \in (-\infty, +\infty)

The function takes a number xx in its domain (,)(-\infty, \infty) as input (an angle in radians) and returns a numeric value yy that lies in the range (,)(-\infty, \infty). If the input value is too large an overflow error might occur.

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.cosh(0.0)
  |> should.equal(0.0)
}
pub fn cosine_similarity(
  arr: List(#(Float, Float)),
) -> Result(Float, Nil)

Calculate the cosine similarity between two lists (representing vectors):

i=1nxiyi(i=1nxi2)12(i=1nyi2)12    [1,1] \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}}} \; \in \; \left[-1, 1\right]

In the formula, nn is the length of the two lists and xix_i, yiy_i are the values in the respective input lists indexed by ii.

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.

Example:
import gleam/option
import gleeunit/should
import gleam_community/maths

pub fn example() {
  // Two orthogonal vectors
  maths.cosine_similarity([#(-1.0, 1.0), #(1.0, 1.0), #(0.0, -1.0)])
  |> should.equal(Ok(0.0))

  // Two identical (parallel) vectors
  maths.cosine_similarity([#(1.0, 1.0), #(2.0, 2.0), #(3.0, 3.0)])
  |> should.equal(Ok(1.0))

  // Two parallel, but oppositely oriented vectors
  maths.cosine_similarity([#(-1.0, 1.0), #(-2.0, 2.0), #(-3.0, 3.0)])
  |> should.equal(Ok(-1.0))
}
pub fn cosine_similarity_with_weights(
  arr: List(#(Float, Float, Float)),
) -> Result(Float, Nil)

Calculate the weighted cosine similarity between two lists (representing vectors):

i=1nwixiyi(i=1nwixi2)12(i=1nwiyi2)12    [1,1] \frac{\sum_{i=1}^n w_{i} \cdot x_i \cdot y_i} {\left(\sum_{i=1}^n w_{i} \cdot x_i^2\right)^{\frac{1}{2}} \cdot \left(\sum_{i=1}^n w_{i} \cdot y_i^2\right)^{\frac{1}{2}}} \; \in \; \left[-1, 1\right]

In the formula, nn is the length of the two lists and xix_i, yiy_i are the values in the respective input lists indexed by ii, while the wiR+w_i \in \mathbb{R}_{+} are corresponding positive weights.

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.

Example:
import gleam/option
import gleeunit/should
import gleam_community/maths

pub fn example() {
  let assert Ok(tolerance) = float.power(10.0, -6.0)

  let assert Ok(result) =
    maths.cosine_similarity_with_weights([
      #(1.0, 1.0, 2.0),
      #(2.0, 2.0, 3.0),
      #(3.0, 3.0, 4.0),
    ])
  result
  |> maths.is_close(1.0, 0.0, tolerance)
  |> should.be_true()

  let assert Ok(result) =
    maths.cosine_similarity_with_weights([
      #(-1.0, 1.0, 1.0),
      #(-2.0, 2.0, 0.5),
      #(-3.0, 3.0, 0.33),
    ])
  result
  |> maths.is_close(-1.0, 0.0, tolerance)
  |> should.be_true()
}
pub fn cumulative_product(arr: List(Float)) -> List(Float)

Calculate the cumulative product of the elements in a list:

vj=i=1jxi    j=1,,n v_j = \prod_{i=1}^j x_i \;\; \forall j = 1,\dots, n

In the formula, vjv_j is the jj’th element in the cumulative product of nn elements. That is, nn is the length of the list and xiRx_i \in \mathbb{R} is the value in the input list indexed by ii. The value vjv_j is thus the sum of the 11 to jj first elements in the given list.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  []
  |> maths.cumulative_product()
  |> should.equal([])

  [1.0, 2.0, 3.0]
  |> maths.cumulative_product()
  |> should.equal([1.0, 2.0, 6.0])
}
pub fn cumulative_sum(arr: List(Float)) -> List(Float)

Calculate the cumulative sum of the elements in a list:

vj=i=1jxi    j=1,,n v_j = \sum_{i=1}^j x_i \;\; \forall j = 1,\dots, n

In the formula, vjv_j is the jj’th element in the cumulative sum of nn elements. That is, nn is the length of the list and xiRx_i \in \mathbb{R} is the value in the input list indexed by ii. The value vjv_j is thus the sum of the 11 to jj first elements in the given list.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  []
  |> maths.cumulative_sum()
  |> should.equal([])

  [1.0, 2.0, 3.0]
  |> maths.cumulative_sum()
  |> should.equal([1.0, 3.0, 6.0])
}
pub fn degrees_to_radians(x: Float) -> Float

Convert a value in degrees to a value measured in radians. That is, 1 degrees =π180 radians 1 \text{ degrees } = \frac{\pi}{180} \text{ radians }.

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.degrees_to_radians(360.)
  |> should.equal(2. *. maths.pi())
}
pub fn divisors(n: Int) -> List(Int)

The function returns all the positive divisors of an integer, including the number itself.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.divisors(4)
  |> should.equal([1, 2, 4])

  maths.divisors(6)
  |> should.equal([1, 2, 3, 6])

  maths.divisors(13)
  |> should.equal([1, 13])
}
pub fn e() -> Float

Euler’s number e2.71828e \approx 2.71828\dots.

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  let assert Ok(tolerance) = float.power(10.0, -6.0)

  // Test that the constant is approximately equal to 2.7128...
  maths.e()
  |> maths.is_close(2.7182818284590452353602, 0.0, tolerance)
  |> should.be_true()
}
pub fn erf(x: Float) -> Float
pub fn euclidean_distance(
  arr: List(#(Float, Float)),
) -> Result(Float, Nil)

Calculate the Euclidean distance between two lists (representing vectors):

(i=1nxiyi2)12 \left( \sum_{i=1}^n \left|x_i - y_i \right|^{2} \right)^{\frac{1}{2}}

In the formula, nn is the length of the two lists and xi,yix_i, y_i are the values in the respective input lists indexed by ii.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  let assert Ok(tolerance) = float.power(10.0, -6.0)

  let assert Ok(result) = maths.euclidean_distance([#(1.0, 2.0), #(3.0, 4.0)])
  result
  |> maths.is_close(1.4142135623730951, 0.0, tolerance)
  |> should.be_true()
}
pub fn euclidean_distance_with_weights(
  arr: List(#(Float, Float, Float)),
) -> Result(Float, Nil)

Calculate the weighted Euclidean distance between two lists (representing vectors):

(i=1nwixiyi2)12 \left( \sum_{i=1}^n w_{i} \left|x_i - y_i \right|^{2} \right)^{\frac{1}{2}}

In the formula, nn is the length of the two lists and xi,yix_i, y_i are the values in the respective input lists indexed by ii, while the wiR+w_i \in \mathbb{R}_{+} are corresponding positive weights.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  let assert Ok(tolerance) = float.power(10.0, -6.0)

  let assert Ok(result) =
    maths.euclidean_distance_with_weights([#(1.0, 2.0, 0.5), #(3.0, 4.0, 1.0)])
  result
  |> maths.is_close(1.224744871391589, 0.0, tolerance)
  |> should.be_true()
}
pub fn euclidean_modulo(x: Int, y: Int) -> Int

Given two integers, xx (dividend) and yy (divisor), the Euclidean modulo of xx by yy, denoted as xmod  yx \mod y, is the remainder rr of the division of xx by yy, such that:

x=qy+rand0r<y, x = q \cdot y + r \quad \text{and} \quad 0 \leq r < |y|,

where qq is an integer that represents the quotient of the division.

Note that like the Gleam division operator / this will return 0 if one of the arguments is 0.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.euclidean_modulo(15, 4)
  |> should.equal(3)

  maths.euclidean_modulo(-3, -2)
  |> should.equal(1)

  maths.euclidean_modulo(5, 0)
  |> should.equal(0)
}
pub fn exponential(x: Float) -> Float

The exponential function:

x(,),  ex=y(0,+) \forall x \in (-\infty, \infty), \; e^{x} = y \in (0, +\infty)

where e2.71828e \approx 2.71828\dots is Eulers’ number.

Note: If the input value xx is too large an overflow error might occur.

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.exponential(0.0)
  |> should.equal(1.0)
}
pub fn extrema(
  arr: List(a),
  compare: fn(a, a) -> Order,
) -> Result(#(a, a), Nil)

Returns a tuple consisting of the minimum and maximum values of a given list.

Example:
import gleam/float
import gleeunit/should
import gleam_community/maths

pub fn example () {
  []
  |> maths.extrema(float.compare)
  |> should.be_error()

  [4.0, 4.0, 3.0, 2.0, 1.0]
  |> maths.extrema(float.compare)
  |> should.equal(Ok(#(1.0, 4.0)))
}
pub fn factorial(n: Int) -> Result(Int, Nil)

A combinatorial function for computing the total number of combinations of nn elements, that is n!n!.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.factorial(-1)
  |> should.be_error()

  maths.factorial(0)
  |> should.equal(Ok(1))

  maths.factorial(3)
  |> should.equal(Ok(6))
}
pub fn flip_sign(x: Float) -> Float

The function flips the sign of a given input value xRx \in \mathbb{R}.

pub fn gamma(x: Float) -> Float

The gamma function over the real numbers. The function is essentially equal to the factorial for any positive integer argument: Γ(n)=(n1)!\Gamma(n) = (n - 1)!

The implemented gamma function is approximated through Lanczos approximation using the same coefficients used by the GNU Scientific Library.

pub fn gcd(x: Int, y: Int) -> Int

The function calculates the greatest common divisor of two integers x,yZx, y \in \mathbb{Z}. The greatest common divisor is the largest positive integer that is divisible by both xx and yy.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.gcd(1, 1)
  |> should.equal(1)

  maths.gcd(100, 10)
  |> should.equal(10)

  maths.gcd(-36, -17)
  |> should.equal(1)
}
pub fn geometric_mean(arr: List(Float)) -> Result(Float, Nil)

Calculate the geometric mean xˉ\bar{x} of the elements in a list:

xˉ=(i=1nxi)1n \bar{x} = \left(\prod^{n}_{i=1} x_i\right)^{\frac{1}{n}}

In the formula, nn is the sample size (the length of the list) and xix_i is the sample point in the input list indexed by ii. Note: The geometric mean is only defined for positive numbers.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  // An empty list returns an error
  []
  |> maths.geometric_mean()
  |> should.be_error()

  // List with negative numbers returns an error
  [-1.0, -3.0, -6.0]
  |> maths.geometric_mean()
  |> should.be_error()

  // Valid input returns a result
  [1.0, 3.0, 9.0]
  |> maths.geometric_mean()
  |> should.equal(Ok(3.0))
}
pub fn geometric_space(
  start: Float,
  stop: Float,
  steps: Int,
  endpoint: Bool,
) -> Result(List(Float), Nil)

The function returns a list of a geometric progression between two specified values, where each value is a constant multiple of the previous one. Unlike 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:
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(logspace) = maths.geometric_space(10.0, 1000.0, 3, True)
  let pairs = logspace |> list.zip([10.0, 100.0, 1000.0])
  let assert Ok(result) = maths.all_close(pairs, 0.0, tolerance)
  result
  |> list.all(fn(x) { x == True })
  |> should.be_true()

  // 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()

  maths.geometric_space(-1000.0, 0.0, 3, False)
  |> should.be_error()

  // A negative number of points (-3) does not work
  maths.geometric_space(10.0, 1000.0, -3, False)
  |> should.be_error()
}
pub fn golden_ratio() -> Float

The golden ratio: ϕ=1+52\phi = \frac{1 + \sqrt{5}}{2}.

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.golden_ratio()
  |> should.equal(1.618033988749895)
}
pub fn harmonic_mean(arr: List(Float)) -> Result(Float, Nil)

Calculate the harmonic mean xˉ\bar{x} of the elements in a list:

xˉ=ni=1n1xi \bar{x} = \frac{n}{\sum_{i=1}^{n}\frac{1}{x_i}}

In the formula, nn is the sample size (the length of the list) and xix_i is the sample point in the input list indexed by ii. Note: The harmonic mean is only defined for positive numbers.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  // An empty list returns an error
  []
  |> maths.harmonic_mean()
  |> should.be_error()

  // List with negative numbers returns an error
  [-1.0, -3.0, -6.0]
  |> maths.harmonic_mean()
  |> should.be_error()

  // Valid input returns a result
  [1.0, 3.0, 6.0]
  |> maths.harmonic_mean()
  |> should.equal(Ok(2.0))
}
pub fn incomplete_gamma(a: Float, x: Float) -> Result(Float, Nil)

The lower incomplete gamma function over the real numbers.

The implemented incomplete gamma function is evaluated through a power series expansion.

pub fn int_absolute_difference(a: Int, b: Int) -> Int

The absolute difference:

x,yZ,  xyZ+. \forall x, y \in \mathbb{Z}, \; |x - y| \in \mathbb{Z}_{+}.

The function takes two inputs xx and yy and returns a positive integer value which is the absolute difference of the inputs.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.absolute_difference(-10, 10)
  |> should.equal(20)

  maths.absolute_difference(0, -2)
  |> should.equal(2)
}
pub fn int_copy_sign(x: Int, y: Int) -> Int

The function takes two arguments x,yZx, y \in \mathbb{Z} and returns xx such that it has the same sign as yy.

pub fn int_cumulative_product(arr: List(Int)) -> List(Int)

Calculate the cumulative product of the elements in a list:

vj=i=1jxi    j=1,,n v_j = \prod_{i=1}^j x_i \;\; \forall j = 1,\dots, n

In the formula, vjv_j is the jj’th element in the cumulative product of nn elements. That is, nn is the length of the list and xiZx_i \in \mathbb{Z} is the value in the input list indexed by ii. The value vjv_j is thus the product of the 11 to jj first elements in the given list.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  []
  |> maths.int_cumulative_product()
  |> should.equal([])

  [1, 2, 3]
  |> maths.int_cumulative_product()
  |> should.equal([1, 2, 6])
}
pub fn int_cumulative_sum(arr: List(Int)) -> List(Int)

Calculate the cumulative sum of the elements in a list:

vj=i=1jxi    j=1,,n v_j = \sum_{i=1}^j x_i \;\; \forall j = 1,\dots, n

In the formula, vjv_j is the jj’th element in the cumulative sum of nn elements. That is, nn is the length of the list and xiZx_i \in \mathbb{Z} is the value in the input list indexed by ii. The value vjv_j is thus the sum of the 11 to jj first elements in the given list.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  []
  |> maths.int_cumulative_sum()
  |> should.equal([])

  [1, 2, 3]
  |> maths.int_cumulative_sum()
  |> should.equal([1, 3, 6])
}
pub fn int_flip_sign(x: Int) -> Int

The function flips the sign of a given input value xZx \in \mathbb{Z}.

pub fn int_sign(x: Int) -> Int

The function takes an input xZx \in \mathbb{Z} and returns the sign of the input, indicating whether it is positive (+1), negative (-1), or zero (0).

pub fn interquartile_range(
  arr: List(Float),
) -> Result(Float, Nil)

Calculate the interquartile range (IQR) of the elements in a list.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  // An empty list returns an error
  []
  |> maths.interquartile_range()
  |> should.be_error()

  // Valid input returns a result
  [1.0, 2.0, 3.0, 4.0, 5.0]
  |> maths.interquartile_range()
  |> should.equal(Ok(3.0))
}
pub fn is_between(x: Float, lower: Float, upper: Float) -> Bool

A function that tests whether a given real number xRx \in \mathbb{R} is strictly between two other real numbers, a,bRa,b \in \mathbb{R}, such that a<x<ba < x < b.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.is_between(5.5, 5.0, 6.0)
  |> should.equal(True)

  maths.is_between(5.0, 5.0, 6.0)
  |> should.equal(False)

  maths.is_between(6.0, 5.0, 6.0)
  |> should.equal(False)
}
pub fn is_close(
  x: Float,
  y: Float,
  rtol: Float,
  atol: Float,
) -> Bool

Determine if a given value xx is close to or equivalent to a reference value yy based on supplied relative rtolr_{tol} and absolute atola_{tol} tolerance values. The equivalance of the two given values are then determined based on the equation:

xy(atol+rtoly) |x - y| \leq (a_{tol} + r_{tol} \cdot |y|)

True is returned if the statement holds, otherwise False is returned.

Example
import gleeunit/should
import gleam_community/maths

pub fn example () {
  let value = 99.
  let reference_value = 100.
  // We set 'absolute_tolerance' and 'relative_tolerance' such that the values are
  // equivalent if 'value' is within 1 percent of 'reference_value' +/- 0.1
  let relative_tolerance = 0.01
  let absolute_tolerance = 0.10
  maths.is_close(value, reference_value, relative_tolerance, absolute_tolerance)
  |> should.be_true()
}
pub fn is_divisible(n: Int, d: Int) -> Bool

A function that tests whether a given integer nZn \in \mathbb{Z} is divisible by another integer dZd \in \mathbb{Z}, such that nmod  d=0n \mod d = 0.

Details

For example:

  • n=10n = 10 is divisible by d=2d = 2 because 10mod  2=010 \mod 2 = 0.
  • n=7n = 7 is not divisible by d=3d = 3 because 7mod  307 \mod 3 \neq 0.
Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.is_divisible(10, 2)
  |> should.equal(True)

  maths.is_divisible(7, 3)
  |> should.equal(False)
}
pub fn is_fractional(x: Float) -> Bool

Determine if a given value xx is fractional, i.e., if it contains a fractional part:

xx>0 x - \lfloor x \rfloor > 0

True is returned if the given value is fractional (i.e., it has a non-zero decimal part), otherwise False is returned.

Example
import gleeunit/should
import gleam_community/maths

pub fn example () {
  maths.is_fractional(0.3333)
  |> should.equal(True)

  maths.is_fractional(1.0)
  |> should.equal(False)
}
pub fn is_multiple(m: Int, k: Int) -> Bool

A function that tests whether a given integer mZm \in \mathbb{Z} is a multiple of another integer kZk \in \mathbb{Z}, such that m=kqm = k \cdot q, with qZq \in \mathbb{Z}.

Details

For example:

  • m=15m = 15 is a multiple of k=5k = 5 because 15=5315 = 5 \cdot 3.
  • m=14m = 14 is not a multiple of k=5k = 5 because 145\frac{14}{5} does not yield an integer quotient.
Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.is_multiple(15, 5)
  |> should.equal(True)

  maths.is_multiple(14, 5)
  |> should.equal(False)
}
pub fn is_perfect(n: Int) -> Bool

A function that tests whether a given integer value nZn \in \mathbb{Z} is a perfect number. A number is perfect if it is equal to the sum of its proper positive divisors.

Details

For example:

  • 66 is a perfect number since the divisors of 6 are 1+2+3=61 + 2 + 3 = 6.
  • 2828 is a perfect number since the divisors of 28 are 1+2+4+7+14=281 + 2 + 4 + 7 + 14 = 28.
Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.is_perfect(6)
  |> should.equal(True)

  maths.is_perfect(28)
  |> should.equal(True)
}
pub fn is_power(x: Int, y: Int) -> Bool

A function that determines if a given integer value xZx \in \mathbb{Z} is a power of another integer value yZy \in \mathbb{Z}, i.e., the function evaluates whether xx can be expressed as yny^n for some integer n0n \geq 0, by computing the base-yy logarithm of xx:

n=logy(x) n = \log_y(x)

If nn is an integer (i.e., it has no fractional part), then xx is a power of yy and True is returned. Otherwise False is returned.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  // Check if 4 is a power of 2 (it is)
  maths.is_power(4, 2)
  |> should.equal(True)

  // Check if 5 is a power of 2 (it is not)
  maths.is_power(5, 2)
  |> should.equal(False)
}
pub fn is_prime(x: Int) -> Bool

A function that tests whether a given integer value xZx \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 xx 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

Examples of prime numbers:

  • 22 is a prime number since it has only two divisors: 11 and 22.
  • 77 is a prime number since it has only two divisors: 11 and 77.
  • 44 is not a prime number since it has divisors other than 11 and itself, such as 22.
Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.is_prime(2)
  |> should.equal(True)

  maths.is_prime(4)
  |> should.equal(False)

  // Test the 2nd Carmichael number
  maths.is_prime(1105)
  |> should.equal(False)
}
pub fn jaccard_index(xset: Set(a), yset: Set(a)) -> Float

The Jaccard index measures similarity between two sets of elements. Mathematically, the Jaccard index is defined as:

XYXY    [0,1] \frac{|X \cap Y|}{|X \cup Y|} \; \in \; \left[0, 1\right]

where:

  • XX and YY are two sets being compared
  • XY|X \cap Y| represents the size of the intersection of the two sets
  • XY|X \cup Y| denotes the size of the union of the two sets

The value of the Jaccard index ranges from 0 to 1, where 0 indicates that the two sets share no elements and 1 indicates that the sets are identical. The Jaccard index is a special case of the Tversky index (with α=β=1\alpha=\beta=1).

Example:
import gleam/set
import gleeunit/should
import gleam_community/maths

pub fn example () {
  let xset = set.from_list(["cat", "dog", "hippo", "monkey"])
  let yset = set.from_list(["monkey", "rhino", "ostrich", "salmon"])
  maths.jaccard_index(xset, yset)
  |> should.equal(1.0 /. 7.0)
}
pub fn kurtosis(arr: List(Float)) -> Result(Float, Nil)

Calculate the sample kurtosis of a list of elements using the definition of Fisher.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  // An empty list returns an error
  []
  |> maths.kurtosis()
  |> should.be_error()

  // To calculate kurtosis at least four values are needed
  [1.0, 2.0, 3.0]
  |> maths.kurtosis()
  |> should.be_error()

  [1.0, 2.0, 3.0, 4.0]
  |> maths.kurtosis()
  |> should.equal(Ok(-1.36))
}
pub fn lcm(x: Int, y: Int) -> Int

The function calculates the least common multiple of two integers x,yZx, y \in \mathbb{Z}. The least common multiple is the smallest positive integer that has both xx and yy as factors.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.lcm(1, 1)
  |> should.equal(1)

  maths.lcm(100, 10)
  |> should.equal(100)

  maths.lcm(-36, -17)
  |> should.equal(612)
}
pub fn linear_space(
  start: Float,
  stop: Float,
  steps: Int,
  endpoint: Bool,
) -> Result(List(Float), Nil)

The function returns a list of linearly 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.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  let assert Ok(tolerance) = float.power(10.0, -6.0)
  let assert Ok(linspace) = maths.linear_space(10.0, 20.0, 5, True)
  let pairs = linspace |> list.zip([10.0, 12.5, 15.0, 17.5, 20.0])
  let assert Ok(result) = maths.all_close(pairs, 0.0, tolerance)
  result
  |> list.all(fn(x) { x == True })
  |> should.be_true()

  // A negative number of points (-5) does not work
  maths.linear_space(10.0, 50.0, -5, True)
  |> should.be_error()
}
pub fn list_combination(
  arr: List(a),
  k: Int,
) -> Result(Yielder(List(a)), Nil)

Generates all possible combinations of kk elements selected from a given list of size nn. The function handles the case without repetitions, that is, repeated elements are not treated as distinct.

Example:
import gleam/yielder
import gleeunit/should
import gleam_community/maths

pub fn example () {
  // All 2-combinations of [1, 2, 3] without repetition
  let assert Ok(combinations) = maths.list_combination([1, 2, 3], 2)

  combinations
  |> yielder.to_list()
  |> should.equal([[1, 2], [1, 3], [2, 3]])
}
pub fn list_combination_with_repetitions(
  arr: List(a),
  k: Int,
) -> Result(Yielder(List(a)), Nil)

Generates all possible combinations of kk elements selected from a given list of size nn. The function handles the case when the repetition of elements is allowed, that is, repeated elements are treated as distinct.

Example:
import gleam/yielder
import gleeunit/should
import gleam_community/maths

pub fn example () {
  // All 2-combinations of [1, 2, 3] with repetition
  let assert Ok(combinations) =
    maths.list_combination_with_repetitions([1, 2, 3], 2)

  combinations
  |> yielder.to_list()
  |> should.equal([[1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 3]])
}
pub fn list_maximum(
  arr: List(a),
  compare: fn(a, a) -> Order,
) -> Result(a, Nil)

Returns the maximum value of a given list.

Example:
import gleam/float
import gleeunit/should
import gleam_community/maths

pub fn example () {
  []
  |> maths.list_maximum(float.compare)
  |> should.be_error()

  [4.0, 4.0, 3.0, 2.0, 1.0]
  |> maths.list_maximum(float.compare)
  |> should.equal(Ok(4.0))
}
pub fn list_minimum(
  arr: List(a),
  compare: fn(a, a) -> Order,
) -> Result(a, Nil)

Returns the minimum value of a given list.

Example:
import gleam/int
import gleeunit/should
import gleam_community/maths

pub fn example () {
  []
  |> maths.list_minimum(int.compare)
  |> should.be_error()

  [4, 4, 3, 2, 1]
  |> maths.list_minimum(int.compare)
  |> should.equal(Ok(1))
}
pub fn list_permutation(
  arr: List(a),
  k: Int,
) -> Result(Yielder(List(a)), Nil)

Generates all possible permutations of kk elements selected from a given list of size nn. The function handles the case without repetitions, that is, repeated elements are not treated as distinct.

Example:
import gleam/yielder
import gleeunit/should
import gleam_community/maths

pub fn example () {
  // All 2-permutations of [1, 2] without repetition
  let assert Ok(permutations) =
    [1, 2]
    |> maths.list_permutation(2)
  permutations
  |> yielder.to_list()
  |> should.equal([[1, 2], [2, 1]])
}
pub fn list_permutation_with_repetitions(
  arr: List(a),
  k: Int,
) -> Result(Yielder(List(a)), Nil)

Generates all possible permutations of kk elements selected from a given list of size nn. The function handles the case when the repetition of elements is allowed, that is, repeated elements are treated as distinct.

Example:
import gleam/yielder
import gleeunit/should
import gleam_community/maths

pub fn example () {
  // All 2-permutations of [1, 2] with repetition
  let assert Ok(permutations) =
    [1, 2]
    |> maths.list_permutation_with_repetitions(2)
  permutations
  |> yielder.to_list()
  |> set.from_list()
  |> should.equal(set.from_list([[1, 1], [1, 2], [2, 2], [2, 1]]))
}
pub fn logarithm(x: Float, base: Float) -> Result(Float, Nil)

The base bb logarithm function (computed through the “change of base” formula):

x(0,) and b>1,  logb(x)=y(,+) \forall x \in (0, \infty) \textnormal{ and } b > 1, \; \log_{b}{(x)} = y \in (-\infty, +\infty)

The function takes a number xx in its domain (0,)(0, \infty) and a base b>1b > 1 as input and returns a numeric value yy that lies in the range (,)(-\infty, \infty). If the input value is outside the domain of the function an error is returned.

Example
import gleeunit/should
import gleam_community/maths

pub fn example () {
  maths.logarithm(1.0, 10.0)
  |> should.equal(Ok(0.0))

  maths.logarithm(maths.e(), maths.e())
  |> should.equal(Ok(1.0))

  maths.logarithm(-1.0, 2.0)
  |> should.be_error()
}
pub fn logarithm_10(x: Float) -> Result(Float, Nil)

The base-10 logarithm function:

x(0,),  log10(x)=y(,+) \forall x \in (0, \infty), \; \log_{10}{(x)} = y \in (-\infty, +\infty)

The function takes a number xx in its domain (0,)(0, \infty) as input and returns a numeric value yy that lies in the range (,)(-\infty, \infty). If the input value is outside the domain of the function an error is returned.

Example
import gleeunit/should
import gleam_community/maths

pub fn example () {
  maths.logarithm_10(1.0)
  |> should.equal(Ok(0.0))

  maths.logarithm_10(10.0)
  |> should.equal(Ok(1.0))

  maths.logarithm_10(-1.0)
  |> should.be_error()
}
pub fn logarithm_2(x: Float) -> Result(Float, Nil)

The base-2 logarithm function:

x(0,),  log2(x)=y(,+) \forall x \in (0, \infty), \; \log_{2}{(x)} = y \in (-\infty, +\infty)

The function takes a number xx in its domain (0,)(0, \infty) as input and returns a numeric value yy that lies in the range (,)(-\infty, \infty). If the input value is outside the domain of the function an error is returned.

Example
import gleeunit/should
import gleam_community/maths

pub fn example () {
  maths.logarithm_2(1.0)
  |> should.equal(Ok(0.0))

  maths.logarithm_2(2.0)
  |> should.equal(Ok(1.0))

  maths.logarithm_2(-1.0)
  |> should.be_error()
}
pub fn logarithmic_space(
  start: Float,
  stop: Float,
  steps: Int,
  endpoint: Bool,
  base: Float,
) -> Result(List(Float), Nil)

The function returns a list of logarithmically spaced points over a specified 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:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  let assert Ok(tolerance) = float.power(10.0, -6.0)
  let assert Ok(logspace) = maths.logarithmic_space(1.0, 3.0, 3, True, 10.0)
  let pairs = logspace |> list.zip([10.0, 100.0, 1000.0])
  let assert Ok(result) = maths.all_close(pairs, 0.0, tolerance)
  result
  |> list.all(fn(x) { x == True })
  |> should.be_true()

  // A negative number of points (-3) does not work
  maths.logarithmic_space(1.0, 3.0, -3, False, 10.0)
  |> should.be_error()
}
pub fn manhattan_distance(
  arr: List(#(Float, Float)),
) -> Result(Float, Nil)

Calculate the Manhattan distance between two lists (representing vectors):

i=1nxiyi \sum_{i=1}^n \left|x_i - y_i \right|

In the formula, nn is the length of the two lists and xi,yix_i, y_i are the values in the respective input lists indexed by ii.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.manhattan_distance([#(1.0, 2.0), #(2.0, 3.0)])
  |> should.equal(Ok(2.0))
}
pub fn manhattan_distance_with_weights(
  arr: List(#(Float, Float, Float)),
) -> Result(Float, Nil)

Calculate the weighted Manhattan distance between two lists (representing vectors):

i=1nwixiyi \sum_{i=1}^n w_{i} \left|x_i - y_i \right|

In the formula, nn is the length of the two lists and xi,yix_i, y_i are the values in the respective input lists indexed by ii, while the wiR+w_i \in \mathbb{R}_{+} are corresponding positive weights.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.manhattan_distance_with_weights([#(1.0, 2.0, 0.5), #(2.0, 3.0, 1.0)])
  |> should.equal(Ok(1.5))
}
pub fn mean(arr: List(Float)) -> Result(Float, Nil)

Calculate the arithmetic mean of the elements in a list:

xˉ=1ni=1nxi \bar{x} = \frac{1}{n}\sum_{i=1}^n x_i

In the formula, nn is the sample size (the length of the list) and xix_i is the sample point in the input list indexed by ii.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  []
  |> maths.mean()
  |> should.be_error()

  [1.0, 2.0, 3.0]
  |> maths.mean()
  |> should.equal(Ok(2.0))
}
pub fn median(arr: List(Float)) -> Result(Float, Nil)

Calculate the median of the elements in a list.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  []
  |> maths.median()
  |> should.be_error()

  [1.0, 2.0, 3.0]
  |> maths.median()
  |> should.equal(Ok(2.0))

  [1.0, 2.0, 3.0, 4.0]
  |> maths.median()
  |> should.equal(Ok(2.5))
}
pub fn minkowski_distance(
  arr: List(#(Float, Float)),
  p: Float,
) -> Result(Float, Nil)

Calculate the Minkowski distance between two lists (representing vectors):

(i=1nwixiyip)1p \left( \sum_{i=1}^n w_{i} \left|x_i - y_i \right|^{p} \right)^{\frac{1}{p}}

In the formula, p>=1p >= 1 is the order, nn is the length of the two lists and xi,yix_i, y_i are the values in the respective input lists indexed by ii.

The Minkowski distance is a generalization of the Euclidean distance (p=2p=2) and the Manhattan distance (p=1p = 1).

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  let assert Ok(tolerance) = float.power(10.0, -6.0)

  let assert Ok(result) =
    maths.minkowski_distance([#(1.0, 2.0), #(3.0, 4.0), #(5.0, 6.0)], 4.0)
  result
  |> maths.is_close(1.3160740129524924, 0.0, tolerance)
  |> should.be_true()
}
pub fn minkowski_distance_with_weights(
  arr: List(#(Float, Float, Float)),
  p: Float,
) -> Result(Float, Nil)

Calculate the weighted Minkowski distance between two lists (representing vectors):

(i=1nwixiyip)1p \left( \sum_{i=1}^n w_{i} \left|x_i - y_i \right|^{p} \right)^{\frac{1}{p}}

In the formula, p>=1p >= 1 is the order, nn is the length of the two lists and xi,yix_i, y_i are the values in the respective input lists indexed by ii. The wiR+w_i \in \mathbb{R}_{+} are corresponding positive weights.

The Minkowski distance is a generalization of the Euclidean distance (p=2p=2) and the Manhattan distance (p=1p = 1).

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  let assert Ok(tolerance) = float.power(10.0, -6.0)

  let assert Ok(result) =
    maths.minkowski_distance_with_weights(
      [#(1.0, 2.0, 0.5), #(3.0, 4.0, 1.0), #(5.0, 6.0, 1.0)],
      4.0,
    )
  result
  |> maths.is_close(1.2574334296829355, 0.0, tolerance)
  |> should.be_true()
}
pub fn minmax(x: a, y: a, compare: fn(a, a) -> Order) -> #(a, a)

The minmax function takes two arguments x,yx, y along with a function for comparing x,yx, y. The function returns a tuple with the smallest value first and largest second.

Example
import gleam/float
import gleam/int
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.minmax(2.0, 1.5, float.compare)
  |> should.equal(#(1.5, 2.0))

  maths.minmax(1, 2, int.compare)
  |> should.equal(#(1, 2))
}
pub fn moment(arr: List(Float), n: Int) -> Result(Float, Nil)

Calculate the n’th moment about the mean of a list of elements.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  // An empty list returns an error
  []
  |> maths.moment(0)
  |> should.be_error()

  // 0th moment about the mean is 1. per definition
  [0.0, 1.0, 2.0, 3.0, 4.0]
  |> maths.moment(0)
  |> should.equal(Ok(1.0))

  // 1st moment about the mean is 0. per definition
  [0.0, 1.0, 2.0, 3.0, 4.0]
  |> maths.moment(1)
  |> should.equal(Ok(0.0))

  // 2nd moment about the mean
  [0.0, 1.0, 2.0, 3.0, 4.0]
  |> maths.moment(2)
  |> should.equal(Ok(2.0))
}
pub fn natural_logarithm(x: Float) -> Result(Float, Nil)

The natural logarithm function:

x(0,),  loge(x)=y(,+) \forall x \in (0, \infty), \; \log_{e}{(x)} = y \in (-\infty, +\infty)

The function takes a number xx in its domain (0,)(0, \infty) as input and returns a numeric value yy that lies in the range (,)(-\infty, \infty). If the input value is outside the domain of the function an error is returned.

Example
import gleeunit/should
import gleam_community/maths

pub fn example () {
  maths.natural_logarithm(1.0)
  |> should.equal(Ok(0.0))

  maths.natural_logarithm(maths.e())
  |> should.equal(Ok(1.0))

  maths.natural_logarithm(-1.0)
  |> should.be_error()
}
pub fn norm(arr: List(Float), p: Float) -> Result(Float, Nil)

Calculate the pp-norm of a list (representing a vector):

(i=1nxip)1p \left( \sum_{i=1}^n \left|x_{i}\right|^{p} \right)^{\frac{1}{p}}

In the formula, nn is the length of the list and xix_i is the value in the input list indexed by ii.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  [1.0, 1.0, 1.0]
  |> maths.norm(1.0)
  |> should.equal(Ok(3.0))

  let assert Ok(tolerance) = float.power(10.0, -6.0)
  let assert Ok(result) =
    [1.0, 2.0, 3.0]
    |> maths.norm(2.0)
  result
  |> maths.is_close(3.7416573867739413, 0.0, tolerance)
  |> should.be_true()
}
pub fn norm_with_weights(
  arr: List(#(Float, Float)),
  p: Float,
) -> Result(Float, Nil)

Calculate the weighted pp-norm of a list (representing a vector):

(i=1nwixip)1p \left( \sum_{i=1}^n w_{i} \left|x_{i}\right|^{p} \right)^{\frac{1}{p}}

In the formula, nn is the length of the list and xix_i is the value in the input list indexed by ii, while wiR+w_i \in \mathbb{R}_{+} is a corresponding positive weight.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  [#(1.0, 0.5), #(1.0, 0.5), #(1.0, 0.5)]
  |> maths.norm_with_weights(1.0)
  |> should.equal(Ok(1.5))

  let assert Ok(tolerance) = float.power(10.0, -6.0)
  let assert Ok(result) =
    [#(1.0, 0.5), #(2.0, 0.5), #(3.0, 0.5)]
    |> maths.norm_with_weights(2.0)
  result
  |> maths.is_close(2.6457513110645907, 0.0, tolerance)
  |> should.be_true()
}
pub fn nth_root(x: Float, n: Int) -> Result(Float, Nil)

The nn’th root function: y=xn=x1ny = \sqrt[n]{x} = x^{\frac{1}{n}}.

Note that the function is not defined if the input is negative (x<0x < 0). An error will be returned as an imaginary number will otherwise have to be returned.

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.nth_root(-1.0, 2)
  |> should.be_error()

  maths.nth_root(1.0, 2)
  |> should.equal(Ok(1.0))

  maths.nth_root(27.0, 3)
  |> should.equal(Ok(3.0))

  maths.nth_root(256.0, 4)
  |> should.equal(Ok(4.0))
}
pub fn overlap_coefficient(xset: Set(a), yset: Set(a)) -> Float

The Overlap coefficient, also known as the Szymkiewicz–Simpson coefficient, is a measure of similarity between two sets that focuses on the size of the intersection relative to the smaller of the two sets. It is defined mathematically as:

XYmin(X,Y)    [0,1] \frac{|X \cap Y|}{\min(|X|, |Y|)} \; \in \; \left[0, 1\right]

where:

  • XX and YY are the sets being compared
  • XY|X \cap Y| is the size of the intersection of the sets
  • min(X,Y)\min(|X|, |Y|) is the size of the smaller set among XX and YY

The coefficient ranges from 0 to 1, where 0 indicates no overlap and 1 indicates that the smaller set is a suyset of the larger set. This measure is especially useful in situations where the similarity in terms of the proportion of overlap is more relevant than the difference in sizes between the two sets.

Example:
import gleam/set
import gleeunit/should
import gleam_community/maths

pub fn example () {
  let set_a = set.from_list(["horse", "dog", "hippo", "monkey", "bird"])
  let set_b = set.from_list(["monkey", "bird", "ostrich", "salmon"])
  maths.overlap_coefficient(set_a, set_b)
  |> should.equal(2.0 /. 4.0)
}
pub fn percentile(arr: List(Float), n: Int) -> Result(Float, Nil)

Calculate the n’th percentile of the elements in a list using linear interpolation between closest ranks.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  // An empty list returns an error
  []
  |> maths.percentile(40)
  |> should.be_error()

  // Calculate 40th percentile
  [15.0, 20.0, 35.0, 40.0, 50.0]
  |> maths.percentile(40)
  |> should.equal(Ok(29.0))
}
pub fn permutation(n: Int, k: Int) -> Result(Int, Nil)

A combinatorial function for computing the number of kk-permutations without repetitions:

P(n,k)=(nk)k!=n!(nk)! P(n, k) = \binom{n}{k} \cdot k! = \frac{n!}{(n - k)!}

The implementation uses an efficient iterative multiplicative formula for computing the result.

Details

A kk-permutation without repetitions is a sequence of kk elements selected from
nn elements where the order of selection matters and elements are not allowed to repeat. For example, consider selecting 2 elements from a list of 3 elements: ["A", "B", "C"]. In this case, possible selections are:

  • ["A", "B"], ["B", "A"]
  • ["A", "C"], ["C", "A"]
  • ["B", "C"], ["C", "B"]
Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.permutation(-1, 1)
  |> should.be_error()

  maths.permutation(4, 0)
  |> should.equal(Ok(1))

  maths.permutation(4, 2)
  |> should.equal(Ok(12))

  maths.permutation(13, 5)
  |> should.equal(Ok(154_440))
}
pub fn permutation_with_repetitions(
  n: Int,
  k: Int,
) -> Result(Int, Nil)

A combinatorial function for computing the number of kk-permutations with repetitions:

P(n,k)=nk P^*(n, k) = n^k

Details

A kk-permutation with repetitions is a sequence of kk elements selected from nn elements where the order of selection matters and elements are allowed to repeat. For example, consider selecting 2 elements from a list of 3 elements: ["A", "B", "C"]. In this case, possible selections are:

  • ["A", "A"], ["A", "B"], ["A", "C"]
  • ["B", "A"], ["B", "B"], ["B", "C"]
  • ["C", "A"], ["C", "B"], ["C", "C"]
Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.permutation_with_repetitions(1, -1)
  |> should.be_error()

  maths.permutation_with_repetitions(2, 3)
  |> should.equal(Ok(8))

  maths.permutation_with_repetitions(4, 4)
  |> should.equal(Ok(256))

  maths.permutation_with_repetitions(6, 3)
  |> should.equal(Ok(216))
}
pub fn pi() -> Float

The mathematical constant pi: π3.1415\pi \approx 3.1415\dots

pub fn polar_to_cartesian(
  r: Float,
  theta: Float,
) -> #(Float, Float)

Converts polar coordinates (r,θ)(r, \theta) to Cartesian coordinates (x,y)(x, y).

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.polar_to_cartesian(1.0, 0.0)
  |> should.equal(#(1.0, 0.0))

  maths.polar_to_cartesian(1.0, float.pi() /. 2.0)
  |> should.equal(#(0.0, 1.0))
}
pub fn proper_divisors(n: Int) -> List(Int)

The function returns all the positive divisors of an integer, excluding the number itself.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.proper_divisors(4)
  |> should.equal([1, 2])

  maths.proper_divisors(6)
  |> should.equal([1, 2, 3])

  maths.proper_divisors(13)
  |> should.equal([1])
}
pub fn radians_to_degrees(x: Float) -> Float

Convert a value in degrees to a value measured in radians. That is, 1 radians =180π degrees 1 \text{ radians } = \frac{180}{\pi} \text{ degrees }.

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.radians_to_degrees(0.0)
  |> should.equal(0.0)

  maths.radians_to_degrees(2. *. maths.pi())
  |> should.equal(360.)
}
pub fn round_down(x: Float, p: Int) -> Float

The function rounds a float to a specific number of digits (after the decimal place or before if negative). In particular, the input xx is rounded to the nearest integer value (at the specified digit) that is less than or equal to the input xx. This rounding behaviour is similar to behaviour of the Gleam stdlib floor function.

Details

The rounding mode rounds 12.065412.0654 to:

  • 12.012.0 for 0 digits after the decimal point (digits = 0)
  • 12.012.0 for 1 digits after the decimal point (digits = 1)
  • 12.0612.06 for 2 digits after the decimal point (digits = 2)
  • 12.06512.065 for 3 digits after the decimal point (digits = 3)

It is also possible to specify a negative number of digits. In that case, the negative number refers to the digits before the decimal point.

  • 10.010.0 for 1 digit before the decimal point (digits = -1)
  • 0.00.0 for 2 digits before the decimal point (digits = -2)
  • 0.00.0 for 3 digits before the decimal point (digits = -3)
Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.round_down(12.0654, 2)
  |> should.equal(12.06)
}
pub fn round_ties_away(x: Float, p: Int) -> Float

The function rounds a float to a specific number of digits (after the decimal place or before if negative). In particular, the input xx is rounded to the nearest integer value (at the specified digit) with ties (fractional values of 0.5) being rounded away from zero (C/C++ rounding behaviour).

Details

The rounding mode rounds 12.065412.0654 to:

  • 12.012.0 for 0 digits after the decimal point (digits = 0)
  • 12.112.1 for 1 digit after the decimal point (digits = 1)
  • 12.0712.07 for 2 digits after the decimal point (digits = 2)
  • 12.06512.065 for 3 digits after the decimal point (digits = 3)

It is also possible to specify a negative number of digits. In that case, the negative number refers to the digits before the decimal point.

  • 10.010.0 for 1 digit before the decimal point (digits = -1)
  • 0.00.0 for 2 digits before the decimal point (digits = -2)
  • 0.00.0 for 3 digits before the decimal point (digits = -3)
Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.round_ties_away(12.0654, 2)
  |> should.equal(12.07)
}
pub fn round_ties_up(x: Float, p: Int) -> Float

The function rounds a float to a specific number of digits (after the decimal place or before if negative). In particular, the input xx is rounded to the nearest integer value (at the specified digit) with ties (fractional values of 0.5) being rounded towards ++\infty (Java/JavaScript rounding behaviour).

Details

The rounding mode rounds 12.065412.0654 to:

  • 12.012.0 for 0 digits after the decimal point (digits = 0)
  • 12.112.1 for 1 digits after the decimal point (digits = 1)
  • 12.0712.07 for 2 digits after the decimal point (digits = 2)
  • 12.06512.065 for 3 digits after the decimal point (digits = 3)

It is also possible to specify a negative number of digits. In that case, the negative number refers to the digits before the decimal point.

  • 10.010.0 for 1 digit before the decimal point (digits = -1)
  • 0.00.0 for 2 digits before the decimal point (digits = -2)
  • 0.00.0 for 3 digits before the decimal point (digits = -3)
Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.round_ties_up(12.0654, 2)
  |> should.equal(12.07)
}
pub fn round_to_nearest(x: Float, p: Int) -> Float

The function rounds a float to a specific number of digits (after the decimal place or before if negative). In particular, the input xx is rounded to the nearest integer value (at the specified digit) with ties (fractional values of 0.5) being rounded to the nearest even integer.

Details

The rounding mode rounds 12.065412.0654 to:

  • 12.012.0 for 0 digits after the decimal point (digits = 0)
  • 12.112.1 for 1 digit after the decimal point (digits = 1)
  • 12.0712.07 for 2 digits after the decimal point (digits = 2)
  • 12.06512.065 for 3 digits after the decimal point (digits = 3)

It is also possible to specify a negative number of digits. In that case, the negative number refers to the digits before the decimal point.

  • 10.010.0 for 1 digit before the decimal point (digits = -1)
  • 0.00.0 for 2 digits before the decimal point (digits = -2)
  • 0.00.0 for 3 digits before the decimal point (digits = -3)
Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.round_to_nearest(12.0654, 2)
  |> should.equal(12.07)
}
pub fn round_to_zero(x: Float, p: Int) -> Float

The function rounds a float to a specific number of digits (after the decimal place or before if negative). In particular, the input xx is rounded to the nearest integer value (at the specified digit) that is less than or equal to the absolute value of the input xx. This rounding behaviour is similar to behaviour of the Gleam stdlib truncate function.

Details

The rounding mode rounds 12.065412.0654 to:

  • 12.012.0 for 0 digits after the decimal point (digits = 0)
  • 12.012.0 for 1 digit after the decimal point (digits = 1)
  • 12.0612.06 for 2 digits after the decimal point (digits = 2)
  • 12.06512.065 for 3 digits after the decimal point (digits = 3)

It is also possible to specify a negative number of digits. In that case, the negative number refers to the digits before the decimal point.

  • 10.010.0 for 1 digit before the decimal point (digits = -1)
  • 0.00.0 for 2 digits before the decimal point (digits = -2)
  • 0.00.0 for 3 digits before the decimal point (digits = -3)
Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.round_to_zero(12.0654, 2)
  |> should.equal(12.06)
}
pub fn round_up(x: Float, p: Int) -> Float

The function rounds a float to a specific number of digits (after the decimal place or before if negative). In particular, the input xx is rounded to the nearest integer value (at the specified digit) that is larger than or equal to the input xx. This rounding behaviour is similar to behaviour of the Gleam stdlib ceiling function.

Details

The rounding mode rounds 12.065412.0654 to:

  • 13.013.0 for 0 digits after the decimal point (digits = 0)
  • 12.112.1 for 1 digit after the decimal point (digits = 1)
  • 12.0712.07 for 2 digits after the decimal point (digits = 2)
  • 12.06612.066 for 3 digits after the decimal point (digits = 3)

It is also possible to specify a negative number of digits. In that case, the negative number refers to the digits before the decimal point.

  • 20.020.0 for 1 digit places before the decimal point (digit = -1)
  • 100.0100.0 for 2 digits before the decimal point (digits = -2)
  • 1000.01000.0 for 3 digits before the decimal point (digits = -3)
Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.round_up(12.0654, 2)
  |> should.equal(12.07)
}
pub fn sign(x: Float) -> Float

The function takes an input xRx \in \mathbb{R} and returns the sign of the input, indicating whether it is positive (+1.0), negative (-1.0), or zero (0.0).

pub fn sin(x: Float) -> Float

The sine function:

x(,+),  sin(x)=y[1,1] \forall x \in (-\infty, +\infty), \; \sin{(x)} = y \in [-1, 1]

The function takes a number xx in its domain (,)(-\infty, \infty) (an angle in radians) as input and returns a numeric value yy that lies in the range [1,1][-1, 1].

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.sin(0.0)
  |> should.equal(0.0)

  maths.sin(0.5 *. maths.pi())
  |> should.equal(1.0)
}
pub fn sinh(x: Float) -> Float

The hyperbolic sine function:

x(,+),  sinh(x)=y(,+) \forall x \in (-\infty, +\infty), \; \sinh{(x)} = y \in (-\infty, +\infty)

The function takes a number xx in its domain (,+)(-\infty, +\infty) as input (an angle in radians) and returns a numeric value yy that lies in the range (,+)(-\infty, +\infty). If the input value is too large an overflow error might occur.

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.sinh(0.0)
  |> should.equal(0.0)
}
pub fn skewness(arr: List(Float)) -> Result(Float, Nil)

Calculate the sample skewness of a list of elements using the Fisher-Pearson coefficient of skewness.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  // An empty list returns an error
  []
  |> maths.skewness()
  |> should.be_error()

  // To calculate skewness at least three values are needed
  [1.0, 2.0, 3.0]
  |> maths.skewness()
  |> should.equal(Ok(0.0))

  [1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 3.0, 3.0, 4.0]
  |> maths.skewness()
  |> should.equal(Ok(0.6))
}
pub fn sorensen_dice_coefficient(
  xset: Set(a),
  yset: Set(a),
) -> Float

The Sørensen-Dice coefficient measures the similarity between two sets of elements. Mathematically, the coefficient is defined as:

2XYX+Y    [0,1] \frac{2 |X \cap Y|}{|X| + |Y|} \; \in \; \left[0, 1\right]

where:

  • XX and YY are two sets being compared
  • XY|X \cap Y| is the size of the intersection of the two sets (i.e., the number of elements common to both sets)
  • X|X| and Y|Y| are the sizes of the sets XX and YY, respectively

The coefficient ranges from 0 to 1, where 0 indicates no similarity (the sets share no elements) and 1 indicates perfect similarity (the sets are identical). The higher the coefficient, the greater the similarity between the two sets. The Sørensen-Dice coefficient is a special case of the Tversky index (with α=β=0.5\alpha=\beta=0.5).

Example:
import gleam/set
import gleeunit/should
import gleam_community/maths

pub fn example () {
  let xset = set.from_list(["cat", "dog", "hippo", "monkey"])
  let yset = set.from_list(["monkey", "rhino", "ostrich", "salmon", "spider"])
  maths.sorensen_dice_coefficient(xset, yset)
  |> should.equal(2.0 *. 1.0 /. { 4.0 +. 5.0 })
}
pub fn standard_deviation(
  arr: List(Float),
  ddof: Int,
) -> Result(Float, Nil)

Calculate the sample standard deviation of the elements in a list: s=(1ndi=1n(xixˉ))12 s = \left(\frac{1}{n - d} \sum_{i=1}^{n}(x_i - \bar{x})\right)^{\frac{1}{2}}

In the formula, nn is the sample size (the length of the list) and xix_i is the sample point in the input list indexed by ii. Furthermore, xˉ\bar{x} is the sample mean and dd is the “Delta Degrees of Freedom”, and is typically set to d=1d = 1, which gives an unbiased estimate.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  // Degrees of freedom
  let ddof = 1

  []
  |> maths.standard_deviation(ddof)
  |> should.be_error()

  [1.0, 2.0, 3.0]
  |> maths.standard_deviation(ddof)
  |> should.equal(Ok(1.0))
}
pub fn step_range(
  start: Float,
  stop: Float,
  increment: Float,
) -> List(Float)

The function returns a list of evenly spaced values within a specified interval [start, stop) based on a given increment size.

Note that if increment > 0, the sequence progresses from start towards stop, while if increment < 0, the sequence progresses from start towards stop in reverse.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  maths.step_range(1.0, 5.0, 1.0)
  |> should.equal([1.0, 2.0, 3.0, 4.0])

  // No points returned since
  // start is smaller than stop and the step is positive
  maths.step_range(5.0, 1.0, 1.0)
  |> should.equal([])

  // Points returned since
  // start smaller than stop but negative step
  maths.step_range(5.0, 1.0, -1.0)
  |> should.equal([5.0, 4.0, 3.0, 2.0])
}
pub fn symmetric_space(
  center: Float,
  radius: Float,
  steps: Int,
) -> Result(List(Float), Nil)

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:
import gleeunit/should
import gleam_community/maths

pub fn example() {
  let assert Ok(symspace) = maths.symmetric_space(0.0, 5.0, 5)
  symspace
  |> should.equal([-5.0, -2.5, 0.0, 2.5, 5.0])

  // A negative radius reverses the order of the values
  let assert Ok(symspace) = maths.symmetric_space(0.0, -5.0, 5)
  symspace
  |> should.equal([5.0, 2.5, 0.0, -2.5, -5.0])
}
pub fn tan(x: Float) -> Float

The tangent function:

x(,+),  tan(x)=y(,+) \forall x \in (-\infty, +\infty), \; \tan{(x)} = y \in (-\infty, +\infty)

The function takes a number xx in its domain (,+)(-\infty, +\infty) as input (an angle in radians) and returns a numeric value yy that lies in the range (,+)(-\infty, +\infty).

Example
import gleeunit/should
import gleam_community/maths

pub fn example() {
  maths.tan(0.0)
  |> should.equal(0.0)
}
pub fn tanh(x: Float) -> Float

The hyperbolic tangent function:

x(,),  tanh(x)=y[1,1] \forall x \in (-\infty, \infty), \; \tanh{(x)} = y \in [-1, 1]

The function takes a number xx in its domain (,)(-\infty, \infty) as input (an angle in radians) and returns a numeric value yy that lies in the range [1,1][-1, 1].

Example
import gleeunit/should
import gleam_community/maths

pub fn example () {
  maths.tanh(0.0)
  |> should.equal(0.0)

  maths.tanh(25.0)
  |> should.equal(1.0)

  maths.tanh(-25.0)
  |> should.equal(-1.0)
}
pub fn tau() -> Float

The mathematical (circle) constant tau: τ=2π6.283\tau = 2 \cdot \pi \approx 6.283\dots

pub fn tversky_index(
  xset: Set(a),
  yset: Set(a),
  alpha: Float,
  beta: Float,
) -> Result(Float, Nil)

The Tversky index is a generalization of the Jaccard index and Sørensen-Dice coefficient, which adds flexibility in measuring similarity between two sets using two parameters, α\alpha and β\beta. These parameters allow for asymmetric similarity measures between sets. The Tversky index is defined as:

XYXY+αXY+βYX \frac{|X \cap Y|}{|X \cap Y| + \alpha|X - Y| + \beta|Y - X|}

where:

  • XX and YY are the sets being compared
  • XY|X - Y| and YX|Y - X| are the sizes of the relative complements of YY in XX and XX in YY, respectively,
  • α\alpha and β\beta are parameters that weight the relative importance of the elements unique to XX and YY

The Tversky index reduces to the Jaccard index when α=β=1\alpha = \beta = 1 and to the Sørensen-Dice coefficient when α=β=0.5\alpha = \beta = 0.5. In general, the Tversky index can take on any non-negative value, including 0. The index equals 0 when there is no intersection between the two sets, indicating no similarity. The Tversky index does not have a strict upper limit of 1 when αβ\alpha \neq \beta.

Example:
import gleam/set
import gleeunit/should
import gleam_community/maths

pub fn example () {
  let yset = set.from_list(["cat", "dog", "hippo", "monkey"])
  let xset = set.from_list(["monkey", "rhino", "ostrich", "salmon"])
  // Test Jaccard index (alpha = beta = 1)
  maths.tversky_index(xset, yset, 1.0, 1.0)
  |> should.equal(Ok(1.0 /. 7.0))
}
pub fn variance(
  arr: List(Float),
  ddof: Int,
) -> Result(Float, Nil)

Calculate the sample variance of the elements in a list:

s2=1ndi=1n(xixˉ) s^{2} = \frac{1}{n - d} \sum_{i=1}^{n}(x_i - \bar{x})

In the formula, nn is the sample size (the length of the list) and xix_i is the sample point in the input list indexed by ii. Furthermore, xˉ\bar{x} is the sample mean and dd is the “Delta Degrees of Freedom”. It is typically set to d=1d = 1, which gives an unbiased estimate.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  // Degrees of freedom
  let ddof = 1

  []
  |> maths.variance(ddof)
  |> should.be_error()

  [1.0, 2.0, 3.0]
  |> maths.variance(ddof)
  |> should.equal(Ok(1.0))
}
pub fn weighted_product(
  arr: List(#(Float, Float)),
) -> Result(Float, Nil)

Calculate the weighted product of the elements in a list:

i=1nxiwi \prod_{i=1}^n x_i^{w_i}

In the formula, nn is the length of the list and xiRx_i \in \mathbb{R} is the value in the input list indexed by ii, while the wiRw_i \in \mathbb{R} are corresponding positive weights.

Example:
import gleam/float
import gleeunit/should
import gleam_community/maths

pub fn example () {
  []
  |> maths.weighted_product()
  |> should.equal(Ok(1.0))

  [#(1.0, 1.0), #(2.0, 1.0), #(3.0, 1.0)]
  |> 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.weighted_product()
  result
  |> maths.is_close(30.0, 0.0, tolerance)
  |> should.be_true()
}
pub fn weighted_sum(
  arr: List(#(Float, Float)),
) -> Result(Float, Nil)

Calculate the weighted sum of the elements in a list:

i=1nwixi \sum_{i=1}^n w_i x_i

In the formula, nn is the length of the list and xiRx_i \in \mathbb{R} is the value in the input list indexed by ii, while the wiRw_i \in \mathbb{R} are corresponding positive weights.

Example:
import gleam/float
import gleeunit/should
import gleam_community/maths

pub fn example () {
  []
  |> maths.weighted_sum()
  |> should.equal(Ok(0.0))

  [#(1.0, 1.0), #(2.0, 1.0), #(3.0, 1.0)]
  |> maths.weighted_sum()
  |> should.equal(Ok(6.0))

  [#(9.0, 0.5), #(10.0, 0.5), #(10.0, 0.5)]
  |> maths.weighted_sum()
  |> should.equal(Ok(14.5))
}
pub fn yield_geometric_space(
  start: Float,
  stop: Float,
  steps: Int,
  endpoint: Bool,
) -> Result(Yielder(Float), Nil)

The function is similar to geometric_space but instead returns a yielder (lazily evaluated sequence of elements). This function can be used whenever there is a need to generate a larger-than-usual sequence of elements.

Example:
import gleam/yielder.{Next, Done}
import gleeunit/should
import gleam_community/maths

pub fn example () {
  let assert Ok(logspace) = maths.yield_geometric_space(10.0, 1000.0, 3, True)

  let assert Next(element, rest) = yielder.step(logspace)
  should.equal(element, 10.0)

  let assert Next(element, rest) = yielder.step(rest)
  should.equal(element, 100.0)

  let assert Next(element, rest) = yielder.step(rest)
  should.equal(element, 1000.0)

  // We have generated 3 values, so the 4th will be 'Done'
  should.equal(yielder.step(rest), Done)
}
pub fn yield_linear_space(
  start: Float,
  stop: Float,
  steps: Int,
  endpoint: Bool,
) -> Result(Yielder(Float), Nil)

The function is similar to linear_space but instead returns a yielder (lazily evaluated sequence of elements). This function can be used whenever there is a need to generate a larger-than-usual sequence of elements.

Example:
import gleam/yielder.{Next, Done}
import gleeunit/should
import gleam_community/maths

pub fn example () {
  let assert Ok(linspace) = maths.yield_linear_space(10.0, 20.0, 5, True)

  let assert Next(element, rest) = yielder.step(linspace)
  should.equal(element, 10.0)

  let assert Next(element, rest) = yielder.step(rest)
  should.equal(element, 12.5)

  let assert Next(element, rest) = yielder.step(rest)
  should.equal(element, 15.0)

  let assert Next(element, rest) = yielder.step(rest)
  should.equal(element, 17.5)

  let assert Next(element, rest) = yielder.step(rest)
  should.equal(element, 20.0)

  // We have generated 5 values, so the 6th will be 'Done'
  should.equal(yielder.step(rest), Done)
}
pub fn yield_logarithmic_space(
  start: Float,
  stop: Float,
  steps: Int,
  endpoint: Bool,
  base: Float,
) -> Result(Yielder(Float), Nil)

The function is similar to logarithmic_space but instead returns a yielder (lazily evaluated sequence of elements). This function can be used whenever there is a need to generate a larger-than-usual sequence of elements.

Example:
import gleam/yielder.{Next, Done}
import gleeunit/should
import gleam_community/maths

pub fn example () {
  let assert Ok(logspace) =
    maths.yield_logarithmic_space(1.0, 3.0, 3, True, 10.0)

  let assert Next(element, rest) = yielder.step(logspace)
  should.equal(element, 10.0)

  let assert Next(element, rest) = yielder.step(rest)
  should.equal(element, 100.0)

  let assert Next(element, rest) = yielder.step(rest)
  should.equal(element, 1000.0)

  // We have generated 3 values, so the 4th will be 'Done'
  should.equal(yielder.step(rest), Done)
}
pub fn yield_step_range(
  start: Float,
  stop: Float,
  increment: Float,
) -> Yielder(Float)

The function is similar to step_range but instead returns a yielder (lazily evaluated sequence of elements). This function can be used whenever there is a need to generate a larger-than-usual sequence of elements.

Example:
import gleam/yielder.{Next, Done}
import gleeunit/should
import gleam_community/maths

pub fn example () {
  let range = maths.yield_step_range(1.0, 2.5, 0.5)

  let assert Next(element, rest) = yielder.step(range)
  should.equal(element, 1.0)

  let assert Next(element, rest) = yielder.step(rest)
  should.equal(element, 1.5)

  let assert Next(element, rest) = yielder.step(rest)
  should.equal(element, 2.0)

  // We have generated 3 values over the interval [1.0, 2.5)
  // in increments of 0.5, so the 4th will be 'Done'
  should.equal(yielder.step(rest), Done)
}
pub fn yield_symmetric_space(
  center: Float,
  radius: Float,
  steps: Int,
) -> Result(Yielder(Float), Nil)

The function is similar to symmetric_space but instead returns a yielder (lazily evaluated sequence of elements). This function can be used whenever there is a need to generate a larger-than-usual sequence of elements.

Example:
import gleam/yielder.{Next, Done}
import gleeunit/should
import gleam_community/maths

pub fn example() {
  let assert Ok(symspace) = maths.yield_symmetric_space(0.0, 5.0, 5)

  let assert Next(element, rest) = yielder.step(symspace)
  should.equal(element, -5.0)

  let assert Next(element, rest) = yielder.step(rest)
  should.equal(element, -2.5)

  let assert Next(element, rest) = yielder.step(rest)
  should.equal(element, 0.0)

  let assert Next(element, rest) = yielder.step(rest)
  should.equal(element, 2.5)

  let assert Next(element, rest) = yielder.step(rest)
  should.equal(element, 5.0)

  // We have generated 5 values, so the 6th will be 'Done'
  should.equal(yielder.step(rest), Done)
}
pub fn zscore(
  arr: List(Float),
  ddof: Int,
) -> Result(List(Float), Nil)

Calculate the z-score of each value in the list relative to the sample mean and standard deviation.

Example:
import gleeunit/should
import gleam_community/maths

pub fn example () {
  // An empty list returns an error
  []
  // Use degrees of freedom = 1
  |> maths.zscore(1)
  |> should.be_error()

  [1.0, 2.0, 3.0]
  // Use degrees of freedom = 1
  |> maths.zscore(1)
  |> should.equal(Ok([-1.0, 0.0, 1.0]))
}
Search Document