-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcountrymaam.go
69 lines (57 loc) · 1.7 KB
/
countrymaam.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package countrymaam
import (
"context"
"io"
"github.com/ar90n/countrymaam/collection"
"github.com/ar90n/countrymaam/linalg"
)
type SearchResult struct {
Index uint
Distance float32
}
type Index[T linalg.Number] interface {
SearchChannel(ctx context.Context, query []T) <-chan SearchResult
Save(reader io.Writer) error
}
type MutableIndex[T linalg.Number] interface {
SearchChannel(ctx context.Context, query []T) <-chan SearchResult
Save(reader io.Writer) error
Add(feature []T)
}
type EntryPointIndex[T linalg.Number] interface {
SearchChannel(ctx context.Context, query []T) <-chan SearchResult
SearchChannelWithEntries(ctx context.Context, query []T, entries []uint) <-chan SearchResult
Save(reader io.Writer) error
}
type IndexBuilder[T linalg.Number, I Index[T]] interface {
Build(ctx context.Context, features [][]T) (*I, error)
GetPrameterString() string
}
func Search(ch <-chan SearchResult, n uint, maxCandidates uint) ([]SearchResult, error) {
items := make([]collection.WithPriority[uint], 0, maxCandidates)
for item := range ch {
if maxCandidates <= uint(len(items)) {
break
}
items = append(items, collection.WithPriority[uint]{Item: item.Index, Priority: item.Distance})
}
pq := collection.NewPriorityQueueFromSlice(items)
// take unique neighbors
ret := make([]SearchResult, 0, n)
founds := make(map[uint]struct{}, maxCandidates)
for uint(len(ret)) < n {
item, err := pq.PopWithPriority()
if err != nil {
if err == collection.ErrEmptyPriorityQueue {
break
}
return nil, err
}
if _, ok := founds[item.Item]; ok {
continue
}
founds[item.Item] = struct{}{}
ret = append(ret, SearchResult{Index: item.Item, Distance: item.Priority})
}
return ret, nil
}