Current section

Files

Jump to
bitgraph lib adjacency.ex
Raw

lib/adjacency.ex

defmodule BitGraph.Adjacency do
def init_adjacency_table(opts \\ []) do
opts = Keyword.merge(default_opts(), opts)
max_vertices = Keyword.get(opts, :max_vertices)
allocate? = Keyword.get(opts, :allocate_adjacency_table?)
%{
bit_vector: allocate? && allocate(max_vertices),
table_dimension: max_vertices
}
end
defp default_opts() do
[
max_vertices: 1024,
allocate_adjacency_table?: true
]
end
## Allocate a square matrix for adjacency table
defp allocate(v) do
:bit_vector.new(v * v)
end
def table_ref(%{bit_vector: bit_vector} = _adjacency_table) do
elem(bit_vector, 2)
end
def get(
%{
bit_vector: bit_vector,
table_dimension: table_dimension
}, i, j
) when is_integer(i) and is_integer(j) do
:bit_vector.get(bit_vector, position(i, j, table_dimension))
end
def get(_adjacency, _, _) do
0
end
def set(
%{
bit_vector: bit_vector,
table_dimension: table_dimension
}, i, j
) when is_integer(i) and is_integer(j) do
:bit_vector.set(bit_vector, position(i, j, table_dimension))
end
def set(_adjacency, _, _) do
0
end
def clear(
%{
bit_vector: bit_vector,
table_dimension: table_dimension
}, i, j
) when is_integer(i) and is_integer(j) do
:bit_vector.clear(bit_vector, position(i, j, table_dimension))
end
def clear(_adjacency, _, _) do
0
end
def row(table, row) do
row_iterator(table, row)
|> Iter.Iterable.to_list()
|> MapSet.new()
end
def row_iterator(
%{
table_dimension: table_dimension
} = table, row
) when is_integer(row) do
Iter.Iterable.Filterer.new(1..table_dimension,
fn j -> get(table, row, j) == 1
end)
end
def column(
table, column
) do
column_iterator(table, column)
|> Iter.Iterable.to_list()
|> MapSet.new()
end
def column_iterator(
%{
table_dimension: table_dimension
} = table, column
) when is_integer(column) do
Iter.Iterable.Filterer.new(1..table_dimension,
fn i -> get(table, i, column) == 1
end)
end
def copy(%{bit_vector: {:bit_vector, source_ref} = _bit_vector, table_dimension: dimension} = adjacency, edges \\ nil) do
vector_copy = {:bit_vector, target_ref} = allocate(dimension)
Map.put(adjacency, :bit_vector, vector_copy)
|> tap(fn adjacency ->
if edges do
copy_from_edges(edges, adjacency)
else
copy_from_vector(source_ref, target_ref)
end
end)
end
defp copy_from_vector(source_ref, vector_copy_ref) do
Enum.each(1..:atomics.info(source_ref)[:size], fn idx ->
:atomics.put(vector_copy_ref, idx, :atomics.get(source_ref, idx))
end)
end
defp copy_from_edges(edges, adjacency) do
Enum.each(edges, fn {{from, to}, _edge_data} ->
set(adjacency, from, to)
end)
end
defp position(i, j, table_dimension) when is_integer(i) and is_integer(j) do
(i - 1) * table_dimension + j - 1
end
defp position(_i, _j, _d) do
nil
end
end