2
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
3
# use this file except in compliance with the License. You may obtain a copy of
6
# http://www.apache.org/licenses/LICENSE-2.0
8
# Unless required by applicable law or agreed to in writing, software
9
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
# License for the specific language governing permissions and limitations under
15
package annoyindex_test
23
"github.com/stretchr/testify/assert"
24
"github.com/stretchr/testify/suite"
27
type AnnoyTestSuite struct {
31
func Round(f float64) float64 {
32
return math.Floor(f + 0.5)
35
func RoundPlus(f float64, places int) (float64) {
36
shift := math.Pow(10, float64(places))
37
return Round(f * shift) / shift
40
func (suite *AnnoyTestSuite) SetupTest() {
43
func (suite *AnnoyTestSuite) TestFileHandling() {
44
index := annoyindex.NewAnnoyIndexAngular(3)
45
index.AddItem(0, []float32{0, 0, 1})
46
index.AddItem(1, []float32{0, 1, 0})
47
index.AddItem(2, []float32{1, 0, 0})
50
index.Save("go_test.ann")
52
info, err := os.Stat("go_test.ann")
54
assert.Fail(suite.T(), "Failed to create file, file not found")
57
assert.Fail(suite.T(), "Failed to create file, file size zero")
60
annoyindex.DeleteAnnoyIndexAngular(index)
62
index = annoyindex.NewAnnoyIndexAngular(3)
63
if ret := index.Load("go_test.ann"); ret == false {
64
assert.Fail(suite.T(), "Failed to load file")
67
os.Remove("go_test.ann")
68
index.Save("go_test2.ann", false)
70
info, err = os.Stat("go_test2.ann")
72
assert.Fail(suite.T(), "Failed to create file without prefault, file not found")
75
assert.Fail(suite.T(), "Failed to create file without prefault, file size zero")
78
annoyindex.DeleteAnnoyIndexAngular(index)
80
index = annoyindex.NewAnnoyIndexAngular(3)
81
if ret := index.Load("go_test2.ann", false); ret == false {
82
assert.Fail(suite.T(), "Failed to load file without prefault")
85
os.Remove("go_test2.ann")
86
index.Save("go_test3.ann", true)
88
info, err = os.Stat("go_test3.ann")
90
assert.Fail(suite.T(), "Failed to create file allowing prefault, file not found")
93
assert.Fail(suite.T(), "Failed to create file allowing prefault, file size zero")
96
annoyindex.DeleteAnnoyIndexAngular(index)
98
index = annoyindex.NewAnnoyIndexAngular(3)
99
if ret := index.Load("go_test3.ann", true); ret == false {
100
assert.Fail(suite.T(), "Failed to load file allowing prefault")
102
annoyindex.DeleteAnnoyIndexAngular(index)
104
os.Remove("go_test3.ann")
107
func (suite *AnnoyTestSuite) TestOnDiskBuild() {
108
index := annoyindex.NewAnnoyIndexAngular(3)
109
index.OnDiskBuild("go_test.ann");
111
info, err := os.Stat("go_test.ann")
113
assert.Fail(suite.T(), "Failed to create file, file not found")
115
if info.Size() == 0 {
116
assert.Fail(suite.T(), "Failed to create file, file size zero")
119
index.AddItem(0, []float32{0, 0, 1})
120
index.AddItem(1, []float32{0, 1, 0})
121
index.AddItem(2, []float32{1, 0, 0})
125
index.Load("go_test.ann");
128
index.GetNnsByVector([]float32{3, 2, 1}, 3, -1, &result)
129
assert.Equal(suite.T(), []int{2, 1, 0}, result)
131
index.GetNnsByVector([]float32{1, 2, 3}, 3, -1, &result)
132
assert.Equal(suite.T(), []int{0, 1, 2}, result)
134
index.GetNnsByVector([]float32{2, 0, 1}, 3, -1, &result)
135
assert.Equal(suite.T(), []int{2, 0, 1}, result)
137
annoyindex.DeleteAnnoyIndexAngular(index)
139
os.Remove("go_test.ann")
142
func (suite *AnnoyTestSuite) TestGetNnsByVector() {
143
index := annoyindex.NewAnnoyIndexAngular(3)
144
index.AddItem(0, []float32{0, 0, 1})
145
index.AddItem(1, []float32{0, 1, 0})
146
index.AddItem(2, []float32{1, 0, 0})
150
index.GetNnsByVector([]float32{3, 2, 1}, 3, -1, &result)
151
assert.Equal(suite.T(), []int{2, 1, 0}, result)
153
index.GetNnsByVector([]float32{1, 2, 3}, 3, -1, &result)
154
assert.Equal(suite.T(), []int{0, 1, 2}, result)
156
index.GetNnsByVector([]float32{2, 0, 1}, 3, -1, &result)
157
assert.Equal(suite.T(), []int{2, 0, 1}, result)
159
annoyindex.DeleteAnnoyIndexAngular(index)
162
func (suite *AnnoyTestSuite) TestGetNnsByItem() {
163
index := annoyindex.NewAnnoyIndexAngular(3)
164
index.AddItem(0, []float32{2, 1, 0})
165
index.AddItem(1, []float32{1, 2, 0})
166
index.AddItem(2, []float32{0, 0, 1})
170
index.GetNnsByItem(0, 3, -1, &result)
171
assert.Equal(suite.T(), []int{0, 1, 2}, result)
173
index.GetNnsByItem(1, 3, -1, &result)
174
assert.Equal(suite.T(), []int{1, 0, 2}, result)
176
annoyindex.DeleteAnnoyIndexAngular(index)
179
func (suite *AnnoyTestSuite) TestGetItem() {
180
index := annoyindex.NewAnnoyIndexAngular(3)
181
index.AddItem(0, []float32{2, 1, 0})
182
index.AddItem(1, []float32{1, 2, 0})
183
index.AddItem(2, []float32{0, 0, 1})
188
index.GetItem(0, &result)
189
assert.Equal(suite.T(), []float32{2, 1, 0}, result)
191
index.GetItem(1, &result)
192
assert.Equal(suite.T(), []float32{1, 2, 0}, result)
194
index.GetItem(2, &result)
195
assert.Equal(suite.T(), []float32{0, 0, 1}, result)
197
annoyindex.DeleteAnnoyIndexAngular(index)
201
func (suite *AnnoyTestSuite) TestGetDistance() {
202
index := annoyindex.NewAnnoyIndexAngular(2)
203
index.AddItem(0, []float32{0, 1})
204
index.AddItem(1, []float32{1, 1})
207
assert.Equal(suite.T(), RoundPlus(math.Pow(2 * (1.0 - math.Pow(2, -0.5)), 0.5), 3), RoundPlus(float64(index.GetDistance(0, 1)), 3))
209
annoyindex.DeleteAnnoyIndexAngular(index)
212
func (suite *AnnoyTestSuite) TestGetDotProductDistance() {
213
index := annoyindex.NewAnnoyIndexDotProduct(2)
214
index.AddItem(0, []float32{0, 1})
215
index.AddItem(1, []float32{1, 1})
218
assert.True(suite.T(),
219
math.Abs(1.0-float64(index.GetDistance(0, 1))) < 0.00001)
221
annoyindex.DeleteAnnoyIndexDotProduct(index)
224
func (suite *AnnoyTestSuite) TestLargeEuclideanIndex() {
225
index := annoyindex.NewAnnoyIndexEuclidean(10)
227
for j := 0; j < 10000; j += 2 {
228
p := make([]float32, 0, 10)
229
for i := 0; i < 10; i++ {
230
p = append(p, rand.Float32())
232
x := make([]float32, 0, 10)
233
for i := 0; i < 10; i++ {
234
x = append(x, 1 + p[i] + rand.Float32() * 1e-2)
236
y := make([]float32, 0, 10)
237
for i := 0; i < 10; i++ {
238
y = append(y, 1 + p[i] + rand.Float32() * 1e-2)
241
index.AddItem(j + 1, y)
244
for j := 0; j < 10000; j += 2 {
246
index.GetNnsByItem(j, 2, -1, &result)
248
assert.Equal(suite.T(), result, []int{j, j + 1})
250
index.GetNnsByItem(j + 1, 2, -1, &result)
251
assert.Equal(suite.T(), result, []int{j + 1, j})
253
annoyindex.DeleteAnnoyIndexEuclidean(index)
256
func TestAnnoyTestSuite(t *testing.T) {
257
suite.Run(t, new(AnnoyTestSuite))