Current section
Files
Jump to
Current section
Files
lib/sequences.ex
defmodule Sequences do
@moduledoc """
The Sequences module defines multiple methods that return a Stream of numbers, usually integers.
The different Streams can be tapped in on-demand, by running any `Enum` function on them.
*Be warned:* Do not use any function that iterates through the complete Stream. If you try this, *your code will hang*, as Elixir will never finish iterating through the infinite lists.
For efficiency, these sequences are calculated in a way that re-uses previously calculated results whenever possible.
See https://github.com/Qqwy/elixir-sequences for more information.
"""
@doc """
Defines an infinitely continuing integer Stream, starting at *start* , with step *step* between values.
*step* defaults to `1`.
## Usage:
Sequences.integers(start, step)
## Examples:
iex> Sequences.integers(0,3) |> Enum.take(5)
[0,3,6,9,12]
iex> Sequences.integers(10,-1) |> Enum.take(5)
[10,9,8,7,6]
"""
def integers(start, step \\ 1) do
Stream.iterate(start, &(&1+step))
end
@doc """
An ascending Stream containing the nonnegative integers (A001477)
## Examples:
iex> Sequences.integers |> Enum.take(5)
[0,1,2,3,4]
"""
def integers do
integers(0)
end
@doc """
An ascending Stream containing the positive integers (A000027)
## Examples:
iex> Sequences.positive_integers |> Enum.take(5)
[1,2,3,4,5]
"""
def positive_integers do
integers(1)
end
@doc """
An ascending Stream containing the odd integers (A005408)
## Examples:
iex> Sequences.odd_integers |> Enum.take(5)
[1,3,5,7,9]
"""
def odd_integers do
integers(1, 2)
end
@doc """
An ascending Stream containing the even integers (A005843)
## Examples:
iex> Sequences.even_integers |> Enum.take(5)
[0,2,4,6,8]
"""
def even_integers do
integers(0, 2)
end
@doc """
An infinite Stream of zeroes (A000004)
## Examples:
iex> Sequences.zeroes |> Enum.take(5)
[0,0,0,0,0]
"""
def zeroes do
integers(0,0)
end
@doc """
An infinite Stream of ones (A000012)
## Examples:
iex> Sequences.ones |> Enum.take(5)
[1,1,1,1,1]
"""
def ones do
integers(1,0)
end
@doc """
An infinite Stream containing the Factorial numbers (A000142).
Runs in O(n)
## Definition:
- fact(0) = 1
- fact(n) = n * fact(n-1)
## Examples:
iex> Sequences.factorials |> Enum.take(5)
[1, 1, 2, 6, 24]
"""
def factorials do
Stream.concat(
[1], # Factorial of 0
Stream.scan(Sequences.positive_integers, 1, &(&1*&2))
)
end
@doc """
An infinite Stream containing the Fibonacci numbers (A000045).
Runs in O(n)
## Definition:
- fib(0) = 1
- fib(1) = 1
- fib(n) = fib(n-1) + fib(n-2)
## Examples:
iex> Sequences.fibonacchi |> Enum.take(5)
[1, 1, 2, 3, 5]
"""
def fibonacchi do
Stream.iterate({1,0}, fn {n, prev} -> {n+prev, n} end)
|> Stream.map(fn {n, _} -> n end)
end
@doc """
An infinite Stream containing the Catalan numbers (A000108).
Runs in O(n²), memory consumption is O(n²)
## Definition:
- C(0) = 1
- C(1) = 1
- C(n) = Σ( C(i) * C(n-i)) for all i <- 0 <= i < n
## Examples:
iex> Sequences.catalan |> Enum.take(5)
[1, 2, 5, 14, 42]
"""
def catalan do
Sequences.integers
|> Stream.scan([1], fn _, catalan_list ->
[catalan_sum(catalan_list) | catalan_list]
end)
|> Stream.map(&List.first/1)
end
# Expects a list of the first `n-1` Catalan numbers.
# Will calculate the n-th Catalan number.
# C(n) = Sum for all i in 0 <= i < n
# C(i) * C(n-i)
defp catalan_sum(catalan_list) do
catalan_list
|> Enum.zip(Enum.reverse catalan_list)
|> Enum.map(fn {a,b}->a*b end)
|> Enum.sum
end
@doc """
An infinite Stream containing the Triangular numbers (A000217).
## Definition
- L(0) = 0
- L(1) = 1
- L(n) = L(n-2)+(2*n)-1
## Examples:
iex> Sequences.triangular |> Enum.take(5)
[0, 1, 3, 6, 10]
"""
def triangular do
Stream.concat(
[0], #Base cases
Stream.iterate([1, 0, 2], fn [prev, prevprev, n] ->
[prevprev + (n*2)-1, prev, n+1]
end)
|> Stream.map(&List.first/1)
)
end
@doc """
Defines an ascending integer Stream, containing the Prime numbers (A000040).
This function uses `Sequences.Primes.trial_division` internally, although this might change in the future when more, faster prime-discovery methods are added.
Runs in O(n*sqrt(n)/ln(n)²)
## Examples:
iex> Sequences.primes |> Enum.take(10)
[2,3,5,7,11,13,17,19,23,29]
"""
def primes do
Sequences.Primes.trial_division
end
end