Current section

Files

Jump to
bitgraph test traversal algorithms_test.exs
Raw

test/traversal/algorithms_test.exs

defmodule BitGraphTest.Algorithms do
use ExUnit.Case
alias BitGraph.Common
alias BitGraph.Algorithms
alias BitGraph.V
test "Topsort for DAG" do
edges = [
{"2", "1"},
{"2", "0"},
{"2", "3"},
{"3", "0"},
{"3", "4"},
{"1", "5"},
{"4", "5"},
{"0", "5"}
]
graph =
BitGraph.new() |> BitGraph.add_edges(
edges
)
topsort_result =
graph
|> Algorithms.topsort()
|> then(fn indices -> Common.vertex_indices_to_ids(graph, indices) end)
assert Enum.all?(edges,
fn {from, to} ->
Enum.find_index(topsort_result, fn val -> val == from end)
< Enum.find_index(topsort_result, fn val -> val == to end)
end)
end
test "Topsort and acyclicity for graphs with/without cycles" do
cycle = BitGraph.new() |> BitGraph.add_edges([{:a, :b}, {:c, :a}, {:b, :c}])
refute Algorithms.acyclic?(cycle)
refute Algorithms.topsort(cycle)
bull = BitGraph.add_edges(cycle, [{:a, :e}, {:f, :b}])
refute Algorithms.acyclic?(bull)
refute Algorithms.topsort(bull)
star = BitGraph.delete_edge(bull, :b, :c)
assert Algorithms.acyclic?(star)
assert Algorithms.topsort(star)
end
test "SCC (Kosaraju) " do
## Example:
## https://en.wikipedia.org/wiki/Strongly_connected_component#/media/File:Scc-1.svg
## Modified to add a single-vertex component (by having :i -> :f edge)
edges = [
{:a, :b},
{:b, :c}, {:b, :e}, {:b, :f},
{:c, :d}, {:c, :g},
{:d, :c}, {:d, :h},
{:e, :a}, {:e, :f},
{:f, :g},
{:g, :f}, {:i, :f},
{:h, :d}, {:h, :g}
]
graph = BitGraph.new() |> BitGraph.add_edges(edges)
strong_components = Algorithms.strong_components(graph)
|> Enum.map(fn component -> Common.vertex_indices_to_ids(graph, component) end)
assert length(strong_components) == 4
assert Enum.sort(strong_components) == Enum.sort(
[
[:a, :b, :e],
[:f, :g],
[:c, :d, :h],
[:i]
]
)
end
test "SCC example 2" do
edges = [
{"A", "B"},
{"B", "D"}, {"B", "E"},
{"C", "F"},
{"E", "B"}, {"E", "F"},
{"F", "C"}, {"F", "H"},
{"G", "H"}, {"G", "J"},
{"H", "K"},
{"I", "G"},
{"J", "I"},
{"K", "L"},
{"L", "J"}
]
graph = BitGraph.new() |> BitGraph.add_edges(edges)
strong_components = Algorithms.strong_components(graph)
|> MapSet.new(fn component -> Common.vertex_indices_to_ids(graph, component) end)
assert MapSet.size(strong_components) == 5
assert Enum.sort(strong_components) == Enum.sort(
[
["A"],
["D"],
["B", "E"],
["C", "F"],
["H", "G", "J", "K", "I", "L"]
]
)
end
test "acyclic?" do
graph1 = BitGraph.new() |> BitGraph.add_edges([{:a, :b}, {:a, :c}, {:b, :c}])
assert Algorithms.acyclic?(graph1)
graph2 = BitGraph.new() |> BitGraph.add_edges([{:a, :b}, {:c, :a}, {:b, :c}])
refute Algorithms.acyclic?(graph2)
graph3 = BitGraph.new() |> BitGraph.add_edges(
[
{"2", "1"},
{"2", "0"},
{"2", "3"},
{"3", "0"},
{"3", "4"},
{"1", "5"},
{"4", "5"},
{"0", "5"}
]
)
assert Algorithms.acyclic?(graph3)
end
test "get_cycle" do
## Acyclic graph
graph1 = BitGraph.new() |> BitGraph.add_edges([{:a, :b}, {:a, :c}, {:b, :c}])
refute Enum.any?(BitGraph.vertex_indices(graph1),
fn v_idx -> Algorithms.get_cycle(graph1, v_idx) end)
## Cyclic triangle
graph2 = BitGraph.new() |> BitGraph.add_edges([{:a, :b}, {:c, :a}, {:b, :c}])
## For every starting vertex, there is a cycle of length 3
assert Enum.all?(BitGraph.vertex_indices(graph2),
fn v_idx ->
Algorithms.get_cycle(graph2, v_idx)
|> MapSet.new() |> MapSet.size() == 3
end)
## Bigger graph
edges = [
{:a, :b},
{:b, :c}, {:b, :e}, {:b, :f},
{:c, :d}, {:c, :g},
{:d, :c}, {:d, :h},
{:e, :a}, {:e, :f},
{:f, :g},
{:g, :f}, {:i, :f},
{:h, :d}, {:h, :g}
]
wiki_graph = BitGraph.new() |> BitGraph.add_edges(edges)
## No cycle for edge with a single neighbor
refute Algorithms.get_cycle(wiki_graph, V.get_vertex_index(wiki_graph, :i))
assert Enum.all?([:a, :b, :c, :d, :e, :f, :g],
fn v ->
v_idx = V.get_vertex_index(wiki_graph, v)
Common.cycle?(
wiki_graph,
Algorithms.get_cycle(wiki_graph, v_idx)
)
end)
end
test "components" do
edges = [
{:a, :b}, {:a, :c}, {:b, :c}, # component 1
{:d, :e}, {:d, :f}, {:e, :f}, # component 2
]
graph = BitGraph.new() |> BitGraph.add_edges(edges)
components = Algorithms.components(graph)
assert length(components) == 2
assert Enum.sort([MapSet.new([1, 2, 3]), MapSet.new([4, 5, 6])]) ==
Enum.sort(components)
single_component = BitGraph.add_edge(graph, :c, :f)
assert length(Algorithms.components(single_component)) == 1
end
end