Current section
Files
Jump to
Current section
Files
test/dot_index_test.exs
defmodule AnnoyExDotIndexTest do
use ExUnit.Case, async: true
import AnnoyTestHelper
test "get_nns_by_vector" do
i = AnnoyEx.new(2, :dot)
AnnoyEx.add_item(i, 0, [2, 2])
AnnoyEx.add_item(i, 1, [3, 2])
AnnoyEx.add_item(i, 2, [3, 3])
AnnoyEx.build(i, 10)
{res, _} = AnnoyEx.get_nns_by_vector(i, [4, 4], 3)
assert res == [2, 1, 0]
{res, _} = AnnoyEx.get_nns_by_vector(i, [1, 1], 3)
assert res == [2, 1, 0]
{res, _} = AnnoyEx.get_nns_by_vector(i, [4, 2], 3)
assert res == [2, 1, 0]
end
test "get_nns_by_item" do
i = AnnoyEx.new(2, :dot)
AnnoyEx.add_item(i, 0, [2, 2])
AnnoyEx.add_item(i, 1, [3, 2])
AnnoyEx.add_item(i, 2, [3, 3])
AnnoyEx.build(i, 10)
{res, _} = AnnoyEx.get_nns_by_item(i, 0, 3)
assert res == [2, 1, 0]
{res, _} = AnnoyEx.get_nns_by_item(i, 2, 3)
assert res == [2, 1, 0]
end
test "dist" do
i = AnnoyEx.new(2, :dot)
AnnoyEx.add_item(i, 0, [0, 1])
AnnoyEx.add_item(i, 1, [1, 1])
AnnoyEx.add_item(i, 2, [0, 0])
assert_in_delta(AnnoyEx.get_distance(i, 0, 1), 1.0, 0.01)
assert_in_delta(AnnoyEx.get_distance(i, 1, 2), 0.0, 0.01)
end
# def recall_at(self, n, n_trees=10, n_points=1000, n_rounds=5):
# # the best movie/variable name
# total_recall = 0.
# for r in range(n_rounds):
# # create random points at distance x
# f = 10
# idx = AnnoyIndex(f, 'dot')
# data = numpy.array([
# [random.gauss(0, 1) for z in range(f)]
# for j in range(n_points)
# ])
# expected_results = [
# sorted(
# range(n_points),
# key=lambda j: dot_metric(data[i], data[j])
# )[:n]
# for i in range(n_points)
# ]
# for i, vec in enumerate(data):
# idx.add_item(i, vec)
# idx.build(n_trees)
# for i in range(n_points):
# nns = idx.get_nns_by_vector(data[i], n)
# total_recall += recall(nns, expected_results[i])
# return total_recall / float(n_rounds * n_points)
# def test_recall_at_10(self):
# value = self.recall_at(10)
# self.assertGreaterEqual(value, 0.65)
# def test_recall_at_100(self):
# value = self.recall_at(100)
# self.assertGreaterEqual(value, 0.95)
# def test_recall_at_1000(self):
# value = self.recall_at(1000)
# self.assertGreaterEqual(value, 0.99)
# def test_recall_at_1000_fewer_trees(self):
# value = self.recall_at(1000, n_trees=4)
# self.assertGreaterEqual(value, 0.99)
test "get nns with distances" do
f = 3
i = AnnoyEx.new(f, :dot)
AnnoyEx.add_item(i, 0, [0, 0, 2])
AnnoyEx.add_item(i, 1, [0, 1, 1])
AnnoyEx.add_item(i, 2, [1, 0, 0])
AnnoyEx.build(i, 10)
{l, d} = AnnoyEx.get_nns_by_item(i, 0, 3, -1, true)
assert l == [0, 1, 2]
assert_in_delta(Enum.at(d, 0), 4.0, 0.01)
assert_in_delta(Enum.at(d, 1), 2.0, 0.01)
assert_in_delta(Enum.at(d, 2), 0.0, 0.01)
{l, d} = AnnoyEx.get_nns_by_vector(i, [2, 2, 2], 3, -1, true)
assert l == [0, 1, 2]
assert_in_delta(Enum.at(d, 0), 4.0, 0.01)
assert_in_delta(Enum.at(d, 1), 4.0, 0.01)
assert_in_delta(Enum.at(d, 2), 2.0, 0.01)
end
test "include dists" do
f = 40
i = AnnoyEx.new(f, :dot)
l1 = normal_list(f)
l2 = Enum.map(l1, fn x -> -x end)
AnnoyEx.add_item(i, 0, l1)
AnnoyEx.add_item(i, 1, l2)
AnnoyEx.build(i, 10)
{indices, dists} = AnnoyEx.get_nns_by_item(i, 0, 2, 10, true)
assert indices == [0, 1]
assert_in_delta(Enum.at(dists, 0), dot_product(l1, l1), 0.01)
end
test "distance consistency" do
{n, f} = {1000, 3}
i = AnnoyEx.new(f, :dot)
for j <- 0..(n - 1) do
AnnoyEx.add_item(i, j, normal_list(f))
end
AnnoyEx.build(i, 10)
for a <- Enum.take_random(0..(n - 1), 100) do
{indices, dists} = AnnoyEx.get_nns_by_item(i, a, 100, -1, true)
for {b, dist} <- Enum.zip(indices, dists) do
dp = dot_product(AnnoyEx.get_item_vector(i, a), AnnoyEx.get_item_vector(i, b))
assert_in_delta(dist, dp, 0.01)
assert_in_delta(dist, AnnoyEx.get_distance(i, a, b), 0.01)
end
end
end
end