Packages

ExTed is a naive implementation of a tree edit distance algorithm in Elixir. Please note that this algorithm has exponential runtime complexity!

Current section

Files

Jump to
exted lib ted.ex
Raw

lib/ted.ex

defmodule Ted do
def ted([], []) do
0
end
def ted(forest_1, []) do
v = get_leftmost_root(forest_1)
ted(remove_leftmost_root(forest_1), []) + cost_delete(v)
end
def ted([], forest_2) do
w = get_leftmost_root(forest_2)
ted([], remove_leftmost_root(forest_2)) + cost_insert(w)
end
def ted([_tree_1] = forest_1, [_tree_2] = forest_2) do
v = get_leftmost_root(forest_1)
w = get_leftmost_root(forest_2)
f_v = remove_leftmost_root(forest_1)
g_w = remove_leftmost_root(forest_2)
Enum.min([
ted(f_v, forest_2) + cost_delete(v),
ted(forest_1, g_w) + cost_insert(w),
ted(f_v, g_w) + cost_replace(v,w)
])
end
def ted(forest_1, forest_2) do
v = get_leftmost_root(forest_1)
w = get_leftmost_root(forest_2)
f_v = remove_leftmost_root(forest_1)
g_w = remove_leftmost_root(forest_2)
Enum.min([
ted(f_v, forest_2) + cost_delete(v),
ted(forest_1, g_w) + cost_insert(w),
ted([v], [w]) + ted(
remove_subtree(forest_1, v),
remove_subtree(forest_2, w)
)
])
end
def get_leftmost_root([head | _ ]), do: head
def get_leftmost_root([]), do: nil
def remove_leftmost_root([]), do: []
def remove_leftmost_root([head | tail ]) do
elem(head, 2) ++ tail
end
def remove_subtree(forest, subtree) do
Enum.filter(
Enum.map(
forest,
fn tree -> remove_subtree_from_tree(tree, subtree) end
),
&remove_empty/1
)
end
defp remove_subtree_from_tree(nil, _), do: nil
defp remove_subtree_from_tree(tree, nil), do: tree
defp remove_subtree_from_tree(
{label, _, _},
{label, _, _}
) do
nil
end
defp remove_subtree_from_tree(
{label, metadata, children},
subtree
) do
new_children = Enum.filter(
filter_nil_list(
Enum.map(
children,
fn child -> remove_subtree_from_tree(child, subtree) end
)
),
&remove_empty/1
)
{label, metadata, new_children}
end
defp filter_nil_list([nil]), do: []
defp filter_nil_list(list), do: list
defp cost_delete(nil) do
0
end
defp cost_delete(_node) do
1
end
defp cost_insert(nil) do
0
end
defp cost_insert(_node) do
1
end
defp cost_replace({label, _, _}, {label, _, _}) do
0
end
defp cost_replace(_node1, _node2) do
1
end
defp remove_empty([]), do: false
defp remove_empty(nil), do: false
defp remove_empty(_), do: true
end