defmodule Set do
@moduledoc """
Operations for sets.
"""
@doc """
Returns a power set of the given set.
## Mathematical expression
$$
\\mathfrak{P}(S)
$$
## Examples
iex> Set.power_set(MapSet.new([1, 2, 3]))
MapSet.new([MapSet.new([]), MapSet.new([1]), MapSet.new([2]), MapSet.new([3]), MapSet.new([1, 2]), MapSet.new([1, 3]), MapSet.new([2, 3]), MapSet.new([1, 2, 3])])
"""
def power_set(set) do
set
|> MapSet.to_list()
|> power_list
|> Enum.map(&MapSet.new(&1))
|> MapSet.new()
end
@spec intersection(MapSet.t()) :: MapSet.t()
@doc """
Returns a intersection of the given sets.
## Mathematical expression
$$
\\cap_{\\lambda \\in \\Lambda} S_{\\lambda}
$$
## Examples
iex> Set.intersection(MapSet.new([MapSet.new([3, 4, 6]), MapSet.new([1, 4, 3]), MapSet.new([5, 2, 3])]))
MapSet.new([3])
"""
def intersection(set) do
set |> Enum.reduce(fn e, acc -> MapSet.intersection(e, acc) end)
end
@spec union(MapSet.t()) :: MapSet.t()
@doc """
Returns a union of the given sets.
## Mathematical expression
$$
\\cup_{\\lambda \\in \\Lambda} S_{\\lambda}
$$
## Examples
iex> Set.union(MapSet.new([MapSet.new([3, 4, 6]), MapSet.new([1, 4, 3]), MapSet.new([5, 2, 3])]))
MapSet.new([1, 2, 3, 4, 5, 6])
"""
def union(set) do
set |> Enum.reduce(fn e, acc -> MapSet.union(e, acc) end)
end
@spec function_set(MapSet.t(), MapSet.t()) :: MapSet.t()
@doc """
Returns a function set of the given sets.
## Mathematical expression
$$
\\mathfrak{F} (S, T),\\ S^T
$$
## Examples
iex> Set.function_set(MapSet.new([:a, :b, :c]), MapSet.new([1, 2, 3]))
MapSet.new([%{a: 1}, %{a: 2}, %{a: 3}, %{b: 1}, %{b: 2}, %{b: 3}, %{c: 1}, %{c: 2}, %{c: 3}])
"""
def function_set(domain_set, codomain_set) do
domain_set
|> Enum.map(fn domain ->
codomain_set
|> Enum.map(fn codomain -> %{domain => codomain} end)
end)
|> List.flatten()
|> MapSet.new()
end
defp power_list(list) do
case list do
list when length(tl(list)) === 0 ->
list
|> hd
|> then(&[&1])
|> then(&[[], &1])
[head | tail] ->
power_list(tail) ++ Enum.map(power_list(tail), &[head | &1])
end
end
end