├── doc ├── hnsw-viz-words-4K-3d.png ├── hnsw-viz-words-4K-layer0.png ├── hnsw-viz-words-4K-layer1.png └── hnsw-viz-words-4K-layer2.png ├── .gitignore ├── cmd └── hnsw │ ├── main.go │ ├── go.mod │ ├── glove │ ├── decoder.go │ └── glove.go │ ├── opt │ ├── root.go │ ├── sift.go │ └── glove.go │ ├── num │ └── num.go │ ├── sift │ └── sift.go │ ├── viz │ └── visualize.go │ └── go.sum ├── go.mod ├── .github └── workflows │ ├── check-code.yml │ ├── check-test.yml │ └── build.yml ├── pipe.go ├── internal ├── types │ └── types.go └── pq │ ├── pq_test.go │ └── pq.go ├── LICENSE ├── vector └── vector.go ├── go.sum ├── iterator.go ├── hnsw_test.go ├── search.go ├── hnsw.go ├── option.go ├── codec.go ├── insert.go ├── README.md └── examples ├── basic └── main.go └── attributes └── main.go /doc/hnsw-viz-words-4K-3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fogfish/hnsw/HEAD/doc/hnsw-viz-words-4K-3d.png -------------------------------------------------------------------------------- /doc/hnsw-viz-words-4K-layer0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fogfish/hnsw/HEAD/doc/hnsw-viz-words-4K-layer0.png -------------------------------------------------------------------------------- /doc/hnsw-viz-words-4K-layer1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fogfish/hnsw/HEAD/doc/hnsw-viz-words-4K-layer1.png -------------------------------------------------------------------------------- /doc/hnsw-viz-words-4K-layer2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fogfish/hnsw/HEAD/doc/hnsw-viz-words-4K-layer2.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | go.work 2 | go.work.sum 3 | cmd/sift_* 4 | 5 | *.html 6 | *.fvecs 7 | *.ivecs 8 | *.bvecs 9 | 10 | -------------------------------------------------------------------------------- /cmd/hnsw/main.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package main 10 | 11 | import ( 12 | "github.com/fogfish/hnsw/cmd/hnsw/opt" 13 | ) 14 | 15 | func main() { 16 | opt.Execute() 17 | } 18 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/fogfish/hnsw 2 | 3 | go 1.22.2 4 | 5 | require ( 6 | github.com/bits-and-blooms/bitset v1.13.0 7 | github.com/fogfish/faults v0.2.0 8 | github.com/fogfish/guid/v2 v2.0.4 9 | github.com/fogfish/it/v2 v2.0.1 10 | github.com/kelindar/binary v1.0.19 11 | github.com/kshard/vector v0.1.1 12 | ) 13 | 14 | require ( 15 | github.com/chewxy/math32 v1.10.1 // indirect 16 | github.com/fogfish/golem/pure v0.10.1 // indirect 17 | golang.org/x/sys v0.24.0 // indirect 18 | ) 19 | -------------------------------------------------------------------------------- /.github/workflows/check-code.yml: -------------------------------------------------------------------------------- 1 | ## 2 | ## Quality checks 3 | ## 4 | name: check 5 | on: 6 | pull_request: 7 | types: 8 | - opened 9 | - synchronize 10 | 11 | jobs: 12 | 13 | code: 14 | runs-on: ubuntu-latest 15 | steps: 16 | 17 | - uses: actions/setup-go@v5 18 | with: 19 | go-version: "1.21" 20 | 21 | - uses: actions/checkout@v4 22 | 23 | - uses: dominikh/staticcheck-action@v1.3.0 24 | with: 25 | install-go: false 26 | -------------------------------------------------------------------------------- /.github/workflows/check-test.yml: -------------------------------------------------------------------------------- 1 | ## 2 | ## Unit Tests 3 | ## 4 | name: test 5 | on: 6 | pull_request: 7 | types: 8 | - opened 9 | - synchronize 10 | 11 | jobs: 12 | 13 | unit: 14 | runs-on: ubuntu-latest 15 | steps: 16 | 17 | - uses: actions/setup-go@v5 18 | with: 19 | go-version: "1.21" 20 | 21 | - uses: actions/checkout@v4 22 | 23 | - name: go build 24 | run: | 25 | go build ./... 26 | 27 | - name: go test 28 | run: | 29 | go test -v -coverprofile=profile.cov $(go list ./... | grep -v /examples/) 30 | 31 | - uses: shogo82148/actions-goveralls@v1 32 | continue-on-error: true 33 | with: 34 | path-to-profile: profile.cov 35 | -------------------------------------------------------------------------------- /pipe.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package hnsw 10 | 11 | // Create pipe ("channel") for batch insert 12 | // 13 | // ch := index.Pipe(runtime.NumCPU()) 14 | // ch <- vector.VF32{Key: 1, Vec: []float32{0.1, 0.2, /* ... */ 0.128}} 15 | // 16 | // The HNSW library supports batch insert operations, making it efficient to 17 | // add large datasets. It leverages Golang channels to handle parallel writes, 18 | // ensuring that multiple data points can be inserted concurrently. 19 | func (h *HNSW[Vector]) Pipe(workers int) chan<- Vector { 20 | pipe := make(chan Vector, workers) 21 | 22 | for i := 1; i <= workers; i++ { 23 | go func() { 24 | for v := range pipe { 25 | h.Insert(v) 26 | } 27 | }() 28 | } 29 | 30 | return pipe 31 | } 32 | -------------------------------------------------------------------------------- /cmd/hnsw/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/fogfish/hnsw/cmd/hnsw 2 | 3 | go 1.22.2 4 | 5 | require ( 6 | github.com/akrylysov/pogreb v0.10.2 7 | github.com/danaugrs/go-tsne/tsne v0.0.0-20220306155740-2250969e057f 8 | github.com/fogfish/hnsw v0.0.4 9 | github.com/go-echarts/go-echarts/v2 v2.4.1 10 | github.com/kshard/atom v0.0.3 11 | github.com/kshard/fvecs v0.0.1 12 | github.com/kshard/vector v0.1.1 13 | github.com/sjwhitworth/golearn v0.0.0-20221228163002-74ae077eafb2 14 | github.com/spf13/cobra v1.8.0 15 | gonum.org/v1/gonum v0.15.0 16 | ) 17 | 18 | require github.com/fogfish/golem/pure v0.10.1 // indirect 19 | 20 | require ( 21 | github.com/bits-and-blooms/bitset v1.13.0 // indirect 22 | github.com/chewxy/math32 v1.10.1 // indirect 23 | github.com/fogfish/faults v0.2.0 // indirect 24 | github.com/fogfish/guid/v2 v2.0.4 // indirect 25 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 26 | github.com/kelindar/binary v1.0.19 // indirect 27 | github.com/spf13/pflag v1.0.5 // indirect 28 | golang.org/x/sys v0.24.0 // indirect 29 | ) 30 | -------------------------------------------------------------------------------- /internal/types/types.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package types 10 | 11 | // Vertex to graph node 12 | type Vertex struct { 13 | Distance float32 14 | Addr uint32 15 | } 16 | 17 | // Forward Vertex Ordering 18 | type ordForwardVertex int 19 | 20 | func (ordForwardVertex) Compare(a, b Vertex) int { 21 | if a.Distance < b.Distance { 22 | return -1 23 | } 24 | 25 | if a.Distance > b.Distance { 26 | return 1 27 | } 28 | 29 | return 0 30 | } 31 | 32 | // Reverse Vertex Ordering 33 | type ordReverseVertex int 34 | 35 | func (ordReverseVertex) Compare(a, b Vertex) int { 36 | if a.Distance > b.Distance { 37 | return -1 38 | } 39 | 40 | if a.Distance < b.Distance { 41 | return 1 42 | } 43 | 44 | return 0 45 | } 46 | 47 | const ( 48 | OrdForwardVertex = ordForwardVertex(0) 49 | OrdReverseVertex = ordReverseVertex(1) 50 | ) 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Dmitry Kolesnikov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | ## 2 | ## Build the main branch 3 | ## 4 | name: build 5 | on: 6 | push: 7 | branches: 8 | - main 9 | - /refs/heads/main 10 | 11 | jobs: 12 | 13 | build: 14 | runs-on: ubuntu-latest 15 | steps: 16 | 17 | - uses: actions/setup-go@v5 18 | with: 19 | go-version: "1.21" 20 | 21 | - uses: actions/checkout@v4 22 | 23 | - name: go build 24 | run: | 25 | go build ./... 26 | 27 | - name: go test 28 | run: | 29 | go test -v -coverprofile=profile.cov $(go list ./... | grep -v /examples/) 30 | 31 | - uses: shogo82148/actions-goveralls@v1 32 | continue-on-error: true 33 | with: 34 | path-to-profile: profile.cov 35 | 36 | - uses: reecetech/version-increment@2023.10.2 37 | id: version 38 | with: 39 | scheme: semver 40 | increment: patch 41 | 42 | - name: publish 43 | run: | 44 | git config user.name "GitHub Actions" 45 | git config user.email "github-actions@users.noreply.github.com" 46 | git tag ${{ steps.version.outputs.v-version }} 47 | git push origin -u ${{ steps.version.outputs.v-version }} 48 | 49 | -------------------------------------------------------------------------------- /internal/pq/pq_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package pq_test 10 | 11 | import ( 12 | "math/rand" 13 | "testing" 14 | 15 | "github.com/fogfish/hnsw/internal/pq" 16 | "github.com/fogfish/it/v2" 17 | ) 18 | 19 | type E struct { 20 | weight int 21 | value int 22 | } 23 | 24 | type ordE string 25 | 26 | func (ordE) Compare(a, b E) int { 27 | if a.weight < b.weight { 28 | return -1 29 | } 30 | 31 | if a.weight > b.weight { 32 | return 1 33 | } 34 | 35 | return 0 36 | } 37 | 38 | const SIZE = 500000 39 | 40 | func TestPQ(t *testing.T) { 41 | vl := 0 42 | pq := pq.New(ordE("")) 43 | mw := 0 44 | 45 | for i := 0; i < SIZE; i++ { 46 | w := rand.Intn(20) 47 | if w > mw { 48 | mw = w 49 | } 50 | pq.Enq(E{weight: w, value: i}) 51 | vl += i 52 | } 53 | 54 | priority := 0 55 | 56 | for i := 0; i < SIZE; i++ { 57 | e := pq.Deq() 58 | 59 | it.Then(t).ShouldNot( 60 | it.Less(e.weight, priority), 61 | ) 62 | 63 | priority = e.weight 64 | vl -= e.value 65 | } 66 | 67 | it.Then(t).Should( 68 | it.Equal(vl, 0), 69 | ) 70 | } 71 | -------------------------------------------------------------------------------- /cmd/hnsw/glove/decoder.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package glove 10 | 11 | import ( 12 | "bufio" 13 | "io" 14 | "strconv" 15 | "strings" 16 | ) 17 | 18 | type Decoder struct { 19 | scanner *bufio.Scanner 20 | txt string 21 | vec []float32 22 | err error 23 | } 24 | 25 | func NewDecoder(r io.Reader) *Decoder { 26 | return &Decoder{ 27 | scanner: bufio.NewScanner(r), 28 | } 29 | } 30 | 31 | func (dec *Decoder) Scan() bool { 32 | if !dec.scanner.Scan() { 33 | return false 34 | } 35 | 36 | dec.txt, dec.vec, dec.err = dec.parse(dec.scanner.Text()) 37 | return dec.err == nil 38 | } 39 | 40 | func (dec *Decoder) parse(line string) (string, []float32, error) { 41 | seq := strings.Split(line, " ") 42 | 43 | vec := make([]float32, len(seq)-1) 44 | for i := 1; i < len(seq); i++ { 45 | v, err := strconv.ParseFloat(seq[i], 32) 46 | if err != nil { 47 | return "", nil, err 48 | } 49 | vec[i-1] = float32(v) 50 | } 51 | 52 | return seq[0], vec, nil 53 | } 54 | 55 | func (dec *Decoder) Err() error { 56 | if dec.err != nil { 57 | return dec.err 58 | } 59 | return dec.scanner.Err() 60 | } 61 | 62 | func (dec *Decoder) Text() (string, []float32) { 63 | return dec.txt, dec.vec 64 | } 65 | -------------------------------------------------------------------------------- /vector/vector.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package vector 10 | 11 | import ( 12 | "strconv" 13 | 14 | "github.com/fogfish/guid/v2" 15 | "github.com/kshard/vector" 16 | ) 17 | 18 | // Vector of float32 annotated with uint32 key 19 | type VF32 struct { 20 | Key uint32 `json:"k"` 21 | Vec vector.F32 `json:"v"` 22 | } 23 | 24 | func (v VF32) String() string { return strconv.Itoa(int(v.Key)) } 25 | 26 | // Create surface distance function for type VF32 27 | func SurfaceVF32(surface vector.Surface[vector.F32]) vector.Surface[VF32] { 28 | return vector.ContraMap[vector.F32, VF32]{ 29 | Surface: surface, 30 | ContraMap: func(e VF32) vector.F32 { return e.Vec }, 31 | } 32 | } 33 | 34 | //------------------------------------------------------------------------------ 35 | 36 | // Vector of float32 annotated with K-order number 37 | type KF32 struct { 38 | Key guid.K `json:"k"` 39 | Vec vector.F32 `json:"v"` 40 | } 41 | 42 | func (v KF32) String() string { return v.Key.String() } 43 | 44 | // Create surface distance function for type VF32 45 | func SurfaceKF32(surface vector.Surface[vector.F32]) vector.Surface[KF32] { 46 | return vector.ContraMap[vector.F32, KF32]{ 47 | Surface: surface, 48 | ContraMap: func(e KF32) vector.F32 { return e.Vec }, 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /cmd/hnsw/opt/root.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package opt 10 | 11 | import ( 12 | "fmt" 13 | "os" 14 | "strings" 15 | 16 | "github.com/spf13/cobra" 17 | ) 18 | 19 | // Execute is entry point for cobra cli application 20 | func Execute() { 21 | if err := rootCmd.Execute(); err != nil { 22 | e := err.Error() 23 | fmt.Println(strings.ToUpper(e[:1]) + e[1:]) 24 | os.Exit(1) 25 | } 26 | } 27 | 28 | func init() { 29 | rootCmd.PersistentFlags().IntVarP(&sysThreads, "threads", "t", 1, "number of threads") 30 | rootCmd.PersistentFlags().Int64Var(&sysSeed, "seed", 0, "seed for random generator (default current timestamp)") 31 | rootCmd.PersistentFlags().StringVarP(&hnswDataset, "index", "i", "", "path to HNSW persistent index") 32 | } 33 | 34 | var rootCmd = &cobra.Command{ 35 | Use: "hnsw", 36 | Short: "Command-line utility for for hyper-optimizing the parameters of your HNSW graphs.", 37 | Long: ` 38 | The command-line utility designed for hyper-optimizing the parameters of your 39 | HNSW graphs. This tool allows you to efficiently explore various configurations, 40 | such as M, M0, efConstruction, and others, to find the optimal settings for 41 | your specific dataset and use case. 42 | 43 | The command line utility is tailored for working with 44 | * GLoVe https://nlp.stanford.edu/projects/glove/ 45 | * SIFT http://corpus-texmex.irisa.fr 46 | * your own dataset in the textual (GLoVe format). 47 | `, 48 | Run: root, 49 | } 50 | 51 | func root(cmd *cobra.Command, args []string) { 52 | cmd.Help() 53 | } 54 | 55 | var ( 56 | hnswEfConn int 57 | hnswM int 58 | hnswM0 int 59 | hnswDataset string 60 | sysSeed int64 61 | sysThreads int 62 | ) 63 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= 2 | github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= 3 | github.com/chewxy/math32 v1.10.1 h1:LFpeY0SLJXeaiej/eIp2L40VYfscTvKh/FSEZ68uMkU= 4 | github.com/chewxy/math32 v1.10.1/go.mod h1:dOB2rcuFrCn6UHrze36WSLVPKtzPMRAQvBvUwkSsLqs= 5 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 6 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 7 | github.com/fogfish/faults v0.2.0 h1:3KHvZN3cgv2omAGw0MCVH/AbrqxfNag+TFGpgUp6m1w= 8 | github.com/fogfish/faults v0.2.0/go.mod h1:PtvzLt9TP4IF/hRkwRp4dZub42oaMrLbxdS6vmSCJOs= 9 | github.com/fogfish/golem/pure v0.10.1 h1:0+cnvdaV9zF+0NN8SZMgR5bgFM6yNfBHU4rynYSDfmE= 10 | github.com/fogfish/golem/pure v0.10.1/go.mod h1:kLPfgu5uKP0CrwVap7jejisRwV7vo1q8Eyqnc/Z0qyw= 11 | github.com/fogfish/guid/v2 v2.0.4 h1:EZiPlM4UAghqf7DU5/nLEF+iRH7ODe0AiFuYOMRvITQ= 12 | github.com/fogfish/guid/v2 v2.0.4/go.mod h1:KkZ5T4EE3BqWQJFZBPLSHV/tBe23Xq4KvuPfwtNtepU= 13 | github.com/fogfish/it/v2 v2.0.1 h1:vu3kV2xzYDPHoMHMABxXeu5CoMcTfRc4gkWkzOUkRJY= 14 | github.com/fogfish/it/v2 v2.0.1/go.mod h1:h5FdKaEQT4sUEykiVkB8VV4jX27XabFVeWhoDZaRZtE= 15 | github.com/kelindar/binary v1.0.19 h1:DNyQCtKjkLhBh9pnP49OWREddLB0Mho+1U/AOt/Qzxw= 16 | github.com/kelindar/binary v1.0.19/go.mod h1:/twdz8gRLNMffx0U4UOgqm1LywPs6nd9YK2TX52MDh8= 17 | github.com/kshard/vector v0.1.1 h1:4sz566fGYEyYdDBDLUJHBMrb7XKdR4UJVsxBEy+UpPM= 18 | github.com/kshard/vector v0.1.1/go.mod h1:gHkE5jmnnl1T7hX5rFHuY7lWbg35XzWieRl+qsnihXU= 19 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 20 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 21 | github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= 22 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 23 | golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= 24 | golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 25 | -------------------------------------------------------------------------------- /internal/pq/pq.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package pq 10 | 11 | import ( 12 | "container/heap" 13 | ) 14 | 15 | type Ord[T any] interface{ Compare(T, T) int } 16 | 17 | type Queue[T any] struct { 18 | heap *heaps[T] 19 | } 20 | 21 | func New[T any](ord Ord[T], seq ...T) Queue[T] { 22 | mm := [64]T{} 23 | pq := Queue[T]{ 24 | heap: &heaps[T]{ 25 | ord: ord, 26 | mem: mm[0:0:64], // make([]T, 0), 27 | }, 28 | } 29 | 30 | for _, x := range seq { 31 | pq.Enq(x) 32 | } 33 | 34 | return pq 35 | } 36 | 37 | func (q Queue[T]) Len() int { 38 | return len(q.heap.mem) 39 | } 40 | 41 | func (q Queue[T]) Head() T { 42 | return q.heap.mem[0] 43 | } 44 | 45 | func (q Queue[T]) Enq(v T) { 46 | // avoid unnecessary casting of T 47 | q.heap.mem = append(q.heap.mem, v) 48 | heap.Push(q.heap, 1) 49 | } 50 | 51 | func (q Queue[T]) Deq() T { 52 | // avoid unnecessary casting of T 53 | heap.Pop(q.heap) 54 | 55 | mem, n := q.heap.maybeShrink() 56 | item := (*mem)[n-1] 57 | q.heap.mem = (*mem)[0 : n-1] 58 | return item 59 | } 60 | 61 | // 62 | // 63 | // 64 | 65 | const shrinkMinCap = 1000 66 | const shrinkNewSizeFactor = 2 67 | const shrinkCapLenFactorCondition = 4 68 | 69 | type heaps[T any] struct { 70 | ord Ord[T] 71 | mem []T 72 | } 73 | 74 | func (h *heaps[T]) Len() int { 75 | return len(h.mem) 76 | } 77 | 78 | func (h *heaps[T]) Less(i, j int) bool { 79 | return h.ord.Compare(h.mem[i], h.mem[j]) == -1 80 | } 81 | 82 | func (h *heaps[T]) Swap(i, j int) { 83 | h.mem[i], h.mem[j] = h.mem[j], h.mem[i] 84 | } 85 | 86 | func (h *heaps[T]) Push(x any) {} 87 | 88 | func (h *heaps[T]) Pop() any { 89 | return nil 90 | } 91 | 92 | func (h *heaps[T]) maybeShrink() (*[]T, int) { 93 | l, c := len(h.mem), cap(h.mem) 94 | if cap(h.mem) > shrinkMinCap && c/l > shrinkCapLenFactorCondition { 95 | mem := make([]T, shrinkNewSizeFactor*l) 96 | copy(mem, h.mem) 97 | return &mem, l 98 | } 99 | return &h.mem, l 100 | } 101 | -------------------------------------------------------------------------------- /iterator.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package hnsw 10 | 11 | import ( 12 | "fmt" 13 | "io" 14 | 15 | "github.com/bits-and-blooms/bitset" 16 | ) 17 | 18 | // Node visitor function. 19 | type FMap[Vector any] func(rank int, vector Vector, edges []Vector) error 20 | 21 | // Breadth-first search iterator over all nodes linked at the level. 22 | // 23 | // This method provides an iterator that traverses all nodes linked at a specific 24 | // level of the graph. By performing a full scan, the `ForAll` method ensures 25 | // comprehensive exploration of the graph's nodes, making it useful for 26 | // applications that require a complete overview of the graph structure at a given level. 27 | func (h *HNSW[Vector]) ForAll(level int, fmap FMap[Vector]) error { 28 | var visited bitset.BitSet 29 | 30 | return h.forNode(level, h.head, &visited, fmap) 31 | } 32 | 33 | func (h *HNSW[Vector]) forNode(level int, addr Pointer, visited *bitset.BitSet, fmap FMap[Vector]) error { 34 | if visited.Test(uint(addr)) { 35 | return nil 36 | } 37 | visited.Set(uint(addr)) 38 | 39 | node := h.heap[addr] 40 | 41 | var edges []Vector 42 | if len(node.Connections) > level { 43 | edges = make([]Vector, len(node.Connections[level])) 44 | for i, addr := range node.Connections[level] { 45 | edges[i] = h.heap[addr].Vector 46 | } 47 | } 48 | 49 | if err := fmap(len(node.Connections), node.Vector, edges); err != nil { 50 | return err 51 | } 52 | 53 | if len(node.Connections) > level { 54 | for _, addr := range node.Connections[level] { 55 | if err := h.forNode(level, addr, visited, fmap); err != nil { 56 | return err 57 | } 58 | } 59 | } 60 | 61 | return nil 62 | } 63 | 64 | // Heap iterator over data structure 65 | func (h *HNSW[Vector]) FMap(level int, fmap FMap[Vector]) error { 66 | for _, node := range h.heap { 67 | if len(node.Connections) > level { 68 | edges := make([]Vector, len(node.Connections[level])) 69 | for i, addr := range node.Connections[level] { 70 | edges[i] = h.heap[addr].Vector 71 | } 72 | 73 | if err := fmap(len(node.Connections), node.Vector, edges); err != nil { 74 | return err 75 | } 76 | } 77 | } 78 | 79 | return nil 80 | } 81 | 82 | // Dump index as text 83 | func (h *HNSW[Vector]) Dump(w io.Writer, f func(Vector) string) { 84 | for lvl := h.level - 1; lvl >= 0; lvl-- { 85 | w.Write([]byte(fmt.Sprintf("\n\n==> %v\n", lvl))) 86 | 87 | h.FMap(lvl, func(level int, vector Vector, vertex []Vector) error { 88 | 89 | w.Write([]byte(fmt.Sprintf("%s | ", f(vector)))) 90 | for _, e := range vertex { 91 | w.Write([]byte(fmt.Sprintf("%s ", f(e)))) 92 | } 93 | w.Write([]byte("\n")) 94 | 95 | return nil 96 | }) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /hnsw_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package hnsw_test 10 | 11 | import ( 12 | "math/rand" 13 | "testing" 14 | 15 | "github.com/fogfish/hnsw" 16 | "github.com/fogfish/hnsw/vector" 17 | surface "github.com/kshard/vector" 18 | ) 19 | 20 | const ( 21 | d = 128 22 | n = 1000 23 | ) 24 | 25 | var ( 26 | rnd = rand.NewSource(0x211111111) 27 | vectors = rndVectors() 28 | ) 29 | 30 | func sut(surface surface.Surface[surface.F32]) *hnsw.HNSW[vector.VF32] { 31 | return hnsw.New( 32 | vector.SurfaceVF32(surface), 33 | hnsw.WithRandomSource(rnd), 34 | hnsw.WithM0(64), 35 | ) 36 | } 37 | 38 | func TestInsert(t *testing.T) { 39 | for _, df := range []surface.Surface[surface.F32]{ 40 | surface.Euclidean(), 41 | surface.Cosine(), 42 | } { 43 | index := sut(df) 44 | for i, v := range vectors { 45 | index.Insert(vector.VF32{Key: uint32(i), Vec: v}) 46 | } 47 | 48 | for _, q := range nodes(index) { 49 | seq := index.Search(q, 1, 100) 50 | if seq[0].Key != q.Key { 51 | t.Errorf("Not found %v in %v", q, seq) 52 | } 53 | } 54 | } 55 | } 56 | 57 | func TestUpdate(t *testing.T) { 58 | for _, df := range []surface.Surface[surface.F32]{ 59 | surface.Euclidean(), 60 | surface.Cosine(), 61 | } { 62 | index := sut(df) 63 | for i, v := range vectors { 64 | index.Insert(vector.VF32{Key: uint32(i), Vec: v}) 65 | } 66 | 67 | // Update vectors (set new key) 68 | for i, v := range vectors { 69 | key := uint32((1 << 31) | i) 70 | index.Insert(vector.VF32{Key: key, Vec: v}) 71 | } 72 | 73 | // Check that key is updated 74 | for _, n := range nodes(index) { 75 | if (n.Key & (1 << 31)) == 0 { 76 | t.Errorf("Not updated %v", n.Key) 77 | } 78 | } 79 | } 80 | } 81 | 82 | //------------------------------------------------------------------------------ 83 | 84 | func random() float32 { 85 | again: 86 | f := float64(rnd.Int63()) / (1 << 63) 87 | if f == 1 { 88 | goto again // resample; this branch is taken O(never) 89 | } 90 | return float32(f) 91 | } 92 | 93 | func rndVector() surface.F32 { 94 | v := make(surface.F32, d) 95 | for i := 0; i < d; i++ { 96 | v[i] = 2*random() - 1 97 | } 98 | return v 99 | } 100 | 101 | func rndVectors() []surface.F32 { 102 | vecs := make([]surface.F32, n) 103 | for i := 0; i < n; i++ { 104 | vecs[i] = rndVector() 105 | } 106 | return vecs 107 | } 108 | 109 | func nodes(index *hnsw.HNSW[vector.VF32]) []vector.VF32 { 110 | nodes := make([]vector.VF32, 0) 111 | index.ForAll(0, 112 | func(rank int, vector vector.VF32, edges []vector.VF32) error { 113 | nodes = append(nodes, vector) 114 | return nil 115 | }, 116 | ) 117 | return nodes 118 | } 119 | -------------------------------------------------------------------------------- /search.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package hnsw 10 | 11 | import ( 12 | "github.com/bits-and-blooms/bitset" 13 | "github.com/fogfish/hnsw/internal/pq" 14 | "github.com/fogfish/hnsw/internal/types" 15 | ) 16 | 17 | // skip the graph to "nearest" node 18 | func (h *HNSW[Vector]) skip(level int, addr Pointer, q Vector) Pointer { 19 | for { 20 | skip := h.skipToNearest(level, addr, q) 21 | if skip == addr { 22 | return skip 23 | } 24 | addr = skip 25 | } 26 | } 27 | 28 | // skip to "nearest" connection at the node. 29 | // it return input address if no "movements" is possible 30 | func (h *HNSW[Vector]) skipToNearest(level int, addr Pointer, q Vector) Pointer { 31 | node := h.heap[addr] 32 | dist := h.surface.Distance(node.Vector, q) 33 | 34 | for _, a := range node.Connections[level] { 35 | d := h.surface.Distance(h.heap[a].Vector, q) 36 | if d < dist { 37 | dist = d 38 | addr = a 39 | } 40 | } 41 | 42 | return addr 43 | } 44 | 45 | // search "nearest" vectors on the layer 46 | func (h *HNSW[Vector]) searchLayer(level int, addr Pointer, q Vector, ef int) pq.Queue[types.Vertex] { 47 | visited := bitset.New(uint(ef)) 48 | visited.Set(uint(addr)) 49 | 50 | this := types.Vertex{ 51 | Distance: h.surface.Distance(h.heap[addr].Vector, q), 52 | Addr: addr, 53 | } 54 | 55 | candidates := pq.New(types.OrdForwardVertex, this) 56 | setadidnac := pq.New(types.OrdReverseVertex, this) 57 | 58 | for candidates.Len() > 0 { 59 | c := candidates.Deq() 60 | f := setadidnac.Head() 61 | 62 | if c.Distance > f.Distance { 63 | break 64 | } 65 | 66 | slot := c.Addr % heapRWSlots 67 | h.rwHeap[slot].RLock() 68 | cnode := h.heap[c.Addr] 69 | cedge := cnode.Connections[level] 70 | h.rwHeap[slot].RUnlock() 71 | 72 | for _, e := range cedge { 73 | if !visited.Test(uint(e)) { 74 | visited.Set(uint(e)) 75 | 76 | dist := h.surface.Distance(h.heap[e].Vector, q) 77 | item := types.Vertex{Distance: dist, Addr: e} 78 | 79 | if setadidnac.Len() < ef { 80 | if e != addr { 81 | setadidnac.Enq(item) 82 | } 83 | candidates.Enq(item) 84 | } else if dist < setadidnac.Head().Distance { 85 | setadidnac.Enq(item) 86 | setadidnac.Deq() 87 | candidates.Enq(item) 88 | } 89 | } 90 | } 91 | } 92 | 93 | return setadidnac 94 | } 95 | 96 | // Search K-nearest vectors from the graph 97 | func (h *HNSW[Vector]) Search(q Vector, K int, efSearch int) []Vector { 98 | 99 | h.rwCore.RLock() 100 | head := h.head 101 | hLevel := h.level 102 | h.rwCore.RUnlock() 103 | 104 | for lvl := hLevel - 1; lvl >= 0; lvl-- { 105 | head = h.skip(lvl, head, q) 106 | } 107 | 108 | w := h.searchLayer(0, head, q, efSearch) 109 | for w.Len() > K { 110 | w.Deq() 111 | } 112 | 113 | v := make([]Vector, w.Len()) 114 | for i := w.Len() - 1; i >= 0; i-- { 115 | x := w.Deq() 116 | v[i] = h.heap[x.Addr].Vector 117 | } 118 | 119 | return v 120 | } 121 | -------------------------------------------------------------------------------- /cmd/hnsw/num/num.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | // Package num implements numeric computation utilities for HNSW dataset. 10 | package num 11 | 12 | import ( 13 | "math" 14 | 15 | "github.com/danaugrs/go-tsne/tsne" 16 | "github.com/fogfish/hnsw" 17 | "github.com/fogfish/hnsw/vector" 18 | "github.com/sjwhitworth/golearn/pca" 19 | "gonum.org/v1/gonum/mat" 20 | ) 21 | 22 | // Transform layer of HNSW index to matrix. Each row is vector. 23 | func ToMatrix(level int, h *hnsw.HNSW[vector.VF32]) *mat.Dense { 24 | var ( 25 | data []float64 26 | rows, cols int 27 | ) 28 | 29 | cols = len(h.Head().Vec) 30 | 31 | h.ForAll(level, func(rank int, vector vector.VF32, vertex []vector.VF32) error { 32 | for _, x := range vector.Vec { 33 | data = append(data, float64(x)) 34 | } 35 | 36 | rows++ 37 | return nil 38 | }) 39 | 40 | if rows == 0 { 41 | return nil 42 | } 43 | 44 | return mat.NewDense(rows, cols, data) 45 | } 46 | 47 | // Reduces matrix dimension to (x, y) coordinates using t-SNE algorithms. 48 | // t-SNE params optimized for GLoVe datasets 49 | func Text2D(matrix *mat.Dense) mat.Matrix { 50 | t := tsne.NewTSNE(2, 50, 10, 300, true) 51 | 52 | if r, _ := matrix.Dims(); r > 5000 { 53 | pcaTransform := pca.NewPCA(50) 54 | return t.EmbedData(pcaTransform.FitTransform(matrix), nil) 55 | } 56 | 57 | return t.EmbedData(matrix, nil) 58 | } 59 | 60 | // Reduces matrix dimension to (x, y, z) coordinates using t-SNE algorithms. 61 | // t-SNE params optimized for GLoVe datasets 62 | func Text3D(matrix *mat.Dense) mat.Matrix { 63 | t := tsne.NewTSNE(3, 50, 10, 300, true) 64 | 65 | if r, _ := matrix.Dims(); r > 5000 { 66 | pcaTransform := pca.NewPCA(50) 67 | return t.EmbedData(pcaTransform.FitTransform(matrix), nil) 68 | } 69 | 70 | return t.EmbedData(matrix, nil) 71 | } 72 | 73 | // Calculate min-max value for each coordinate dimension. 74 | // Return matrix - rows are dimensions, cols are (min, max) values 75 | func MinMax(coords mat.Matrix) mat.Matrix { 76 | r, c := coords.Dims() 77 | 78 | data := make([]float64, c*2) 79 | minmax := mat.NewDense(c, 2, data) 80 | 81 | for j := 0; j < c; j++ { 82 | minmax.Set(j, 0, coords.At(0, j)) 83 | minmax.Set(j, 1, coords.At(0, j)) 84 | } 85 | 86 | for i := 1; i < r; i++ { 87 | for j := 0; j < c; j++ { 88 | v := coords.At(i, j) 89 | 90 | if v < minmax.At(j, 0) { 91 | minmax.Set(j, 0, v) 92 | } 93 | 94 | if v > minmax.At(j, 1) { 95 | minmax.Set(j, 1, v) 96 | } 97 | } 98 | } 99 | 100 | return minmax 101 | } 102 | 103 | // Calculate min-max value for node distances 104 | func MinMaxDistance(level int, h *hnsw.HNSW[vector.VF32]) (min, max float32) { 105 | minD := math.Inf(1) 106 | maxD := math.Inf(-1) 107 | 108 | h.ForAll(level, func(rank int, vector vector.VF32, vertex []vector.VF32) error { 109 | for _, dst := range vertex { 110 | d := float64(h.Distance(vector, dst)) 111 | if d < minD { 112 | minD = d 113 | } 114 | if d > maxD { 115 | maxD = d 116 | } 117 | } 118 | return nil 119 | }) 120 | 121 | return float32(minD), float32(maxD) 122 | } 123 | -------------------------------------------------------------------------------- /hnsw.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package hnsw 10 | 11 | import ( 12 | "fmt" 13 | "sync" 14 | 15 | "github.com/kshard/vector" 16 | ) 17 | 18 | // Slots to coordinate concurrent I/O 19 | const heapRWSlots = 1024 20 | 21 | // Pointer to Node 22 | type Pointer = uint32 23 | 24 | // Node of Hierarchical Navigable Small World Graph 25 | type Node[Vector any] struct { 26 | Vector Vector 27 | Connections [][]Pointer 28 | } 29 | 30 | // Collection of serializable Hierarchical Navigable Small World Graph Nodes 31 | type Nodes[Vector any] struct { 32 | Rank int 33 | Head Pointer 34 | Heap []Node[Vector] 35 | } 36 | 37 | // Hierarchical Navigable Small World Graph 38 | type HNSW[Vector any] struct { 39 | rwCore sync.RWMutex 40 | rwHeap [heapRWSlots]sync.RWMutex 41 | 42 | config Config 43 | surface vector.Surface[Vector] 44 | 45 | heap []Node[Vector] 46 | head Pointer 47 | level int 48 | } 49 | 50 | // Creates Hierarchical Navigable Small World Graph 51 | func New[Vector any]( 52 | surface vector.Surface[Vector], 53 | opts ...Option, 54 | ) *HNSW[Vector] { 55 | config := Config{} 56 | WithDefault()(&config) 57 | for _, opt := range opts { 58 | opt(&config) 59 | } 60 | 61 | hnsw := &HNSW[Vector]{ 62 | config: config, 63 | surface: surface, 64 | } 65 | 66 | hnsw.level = 0 67 | hnsw.heap = []Node[Vector]{} 68 | hnsw.head = 0 69 | 70 | return hnsw 71 | } 72 | 73 | // Hierarchical Navigable Small World Graph from exported nodes 74 | func FromNodes[Vector any]( 75 | surface vector.Surface[Vector], 76 | nodes Nodes[Vector], 77 | opts ...Option, 78 | ) *HNSW[Vector] { 79 | config := Config{} 80 | WithDefault()(&config) 81 | for _, opt := range opts { 82 | opt(&config) 83 | } 84 | 85 | hnsw := &HNSW[Vector]{ 86 | config: config, 87 | surface: surface, 88 | } 89 | 90 | hnsw.level = nodes.Rank 91 | hnsw.heap = nodes.Heap 92 | hnsw.head = nodes.Head 93 | 94 | return hnsw 95 | } 96 | 97 | func (h *HNSW[Vector]) String() string { 98 | return fmt.Sprintf("{ %d | Levels: %d M: %d M0: %d mL: %f efC: %d}", 99 | len(h.heap), h.level, h.config.mLayerN, h.config.mLayer0, h.config.mL, h.config.efConstruction) 100 | } 101 | 102 | // Return data structure nodes as serializable container. 103 | func (h *HNSW[Vector]) Nodes() Nodes[Vector] { 104 | return Nodes[Vector]{ 105 | Rank: h.level, 106 | Head: h.head, 107 | Heap: h.heap, 108 | } 109 | } 110 | 111 | // Return current head (entry point) 112 | func (h *HNSW[Vector]) Head() Vector { return h.heap[h.head].Vector } 113 | 114 | // Return current level 115 | func (h *HNSW[Vector]) Level() int { return h.level } 116 | 117 | // Return number of vectors in the data structure 118 | func (h *HNSW[Vector]) Size() int { return len(h.heap) } 119 | 120 | // Calculate distance between two vectors using defined surface distance function. 121 | // 122 | // The function is useful to fine-tune neighbors results, filtering non relevant values. 123 | // 124 | // for _, vector := range neighbors { 125 | // if index.Distance(query, vector) < 0.2 { 126 | // // do something 127 | // } 128 | // } 129 | func (h *HNSW[Vector]) Distance(a, b Vector) float32 { 130 | return h.surface.Distance(a, b) 131 | } 132 | -------------------------------------------------------------------------------- /cmd/hnsw/glove/glove.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | // Package glove implements testing of HNSW implementation using GLoVe dataset: 10 | // - https://nlp.stanford.edu/projects/glove/ 11 | package glove 12 | 13 | import ( 14 | "fmt" 15 | "math" 16 | "math/rand" 17 | "os" 18 | "time" 19 | 20 | "github.com/fogfish/hnsw" 21 | "github.com/fogfish/hnsw/vector" 22 | "github.com/kshard/atom" 23 | surface "github.com/kshard/vector" 24 | ) 25 | 26 | // New HNSW Index for given vector's dimension 27 | func New(m, m0, efC int, seed int64) *hnsw.HNSW[vector.VF32] { 28 | opts := hnsw.With( 29 | hnsw.WithEfConstruction(efC), 30 | hnsw.WithM(m), 31 | hnsw.WithM0(m0), 32 | ) 33 | if seed != 0 { 34 | opts = hnsw.With(opts, hnsw.WithRandomSource(rand.NewSource(seed))) 35 | } 36 | 37 | return hnsw.New(vector.SurfaceVF32(surface.Cosine()), opts) 38 | } 39 | 40 | func scanner(atoms *atom.Pool, dataset string, f func(string, vector.VF32) error) error { 41 | os.Stderr.WriteString(fmt.Sprintf("==> reading %s\n", dataset)) 42 | fd, err := os.Open(dataset) 43 | if err != nil { 44 | return err 45 | } 46 | defer fd.Close() 47 | 48 | t := time.Now() 49 | c := uint32(0) 50 | 51 | progress := func() { 52 | os.Stderr.WriteString( 53 | fmt.Sprintf("==> %9d vectors in %s (%d ns/op)\n", c, time.Since(t), time.Since(t).Nanoseconds()/int64(c)), 54 | ) 55 | } 56 | 57 | scanner := NewDecoder(fd) 58 | for scanner.Scan() { 59 | txt, vec := scanner.Text() 60 | key, err := atoms.Atom(txt) 61 | if err != nil { 62 | return err 63 | } 64 | 65 | c++ 66 | if err := f(txt, vector.VF32{Key: key, Vec: vec}); err != nil { 67 | return err 68 | } 69 | 70 | if c%10000 == 0 { 71 | progress() 72 | } 73 | } 74 | if err := scanner.Err(); err != nil { 75 | return err 76 | } 77 | 78 | progress() 79 | return nil 80 | } 81 | 82 | //------------------------------------------------------------------------------ 83 | 84 | // Create new index from GLoVe dataset 85 | func Create(atoms *atom.Pool, h *hnsw.HNSW[vector.VF32], threads int, dataset string) error { 86 | w := h.Pipe(threads) 87 | 88 | err := scanner(atoms, dataset, 89 | func(txt string, v vector.VF32) error { 90 | w <- v 91 | return nil 92 | }, 93 | ) 94 | if err != nil { 95 | return err 96 | } 97 | 98 | close(w) 99 | return nil 100 | } 101 | 102 | //------------------------------------------------------------------------------ 103 | 104 | // Query dataset, absence of zero distance implies error 105 | func Query(atoms *atom.Pool, h *hnsw.HNSW[vector.VF32], dataset string) error { 106 | c := 0 107 | 108 | err := scanner(atoms, dataset, 109 | func(txt string, v vector.VF32) error { 110 | seq := h.Search(v, 5, 100) 111 | 112 | os.Stdout.WriteString(fmt.Sprintf("\n==> %s\n", txt)) 113 | for i, x := range seq { 114 | d := h.Distance(v, x) 115 | os.Stdout.WriteString(fmt.Sprintf(" %16s : %2.5f\n", atoms.String(x.Key), d)) 116 | 117 | if i == 0 && math.Abs(float64(d)) > 1e-5 { 118 | c++ 119 | } 120 | } 121 | 122 | return nil 123 | }, 124 | ) 125 | if err != nil { 126 | return err 127 | } 128 | 129 | os.Stderr.WriteString(fmt.Sprintf("==> failed %d times\n", c)) 130 | 131 | return nil 132 | } 133 | -------------------------------------------------------------------------------- /option.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package hnsw 10 | 11 | import ( 12 | "math" 13 | "time" 14 | 15 | "math/rand" 16 | ) 17 | 18 | // HNSW data structure configuration 19 | type Config struct { 20 | // size of the dynamic candidate list efConstruction. 21 | efConstruction int 22 | 23 | // Number of established connections from each node. 24 | mLayerN int 25 | mLayer0 int 26 | 27 | // Normalization factor for level generation 28 | mL float64 29 | 30 | // 31 | random rand.Source 32 | } 33 | 34 | // HNSW data structure configuration option 35 | type Option func(*Config) 36 | 37 | func With(opts ...Option) Option { 38 | return func(c *Config) { 39 | for _, opt := range opts { 40 | opt(c) 41 | } 42 | } 43 | } 44 | 45 | // Construction Efficiency Factor (efConstruction) 46 | // 47 | // The parameter controls the number of candidates evaluated during the graph 48 | // construction phase. Higher values of efConstruction result in a more accurate 49 | // and densely connected graph, leading to better search performance but at 50 | // the cost of longer construction times. 51 | // 52 | // Typical values range from 100 to 500 (default 200). 53 | func WithEfConstruction(ef int) Option { 54 | return func(c *Config) { 55 | c.efConstruction = ef 56 | } 57 | } 58 | 59 | // Maximum number of connections per node (M) 60 | // 61 | // This parameter controls the maximum number of neighbors each node can have. 62 | // Higher values of M increase the connectivity and robustness of the graph, 63 | // potentially improving search accuracy but at the cost of increased memory 64 | // usage and longer construction times. Small M gives better result for low 65 | // dimensional data. Big M is better for high dimensional data. 66 | // 67 | // Typical values range from 5 to 48 (default 16). 68 | func WithM(m int) Option { 69 | return func(c *Config) { 70 | c.mLayerN = m 71 | } 72 | } 73 | 74 | // Maximum number of connections per node at level 0 (M0) 75 | // 76 | // This parameter controls the maximum number of neighbors each node can have 77 | // at level 0. 78 | // 79 | // Typical value M0 >> M (default M * 2) 80 | func WithM0(m int) Option { 81 | return func(c *Config) { 82 | c.mLayer0 = m 83 | } 84 | } 85 | 86 | func WithDefaultM0() Option { 87 | return func(c *Config) { 88 | c.mLayer0 = c.mLayerN * 2 89 | } 90 | } 91 | 92 | // Maximum Level Factor 93 | // 94 | // The maximum level a node can be assigned to in this hierarchical structure. 95 | // The level of each node is determined probabilistically based on an 96 | // exponential distribution. The maximum level factor controls the level 97 | // distribution: 98 | // 99 | // P(level) = ⌊-log2(unif(0..1))∙mL⌋ 100 | // 101 | // Typical value 1/log2(M) but this option helps to adjust it. 102 | func WithL(l float64) Option { 103 | return func(c *Config) { 104 | c.mL = l 105 | } 106 | } 107 | 108 | func WithDefaultL() Option { 109 | return func(c *Config) { 110 | c.mL = 1 / math.Log2(1.0*float64(c.mLayerN)) 111 | } 112 | } 113 | 114 | // Random Source 115 | // 116 | // Uniform random source for seeding exponential distribution. 117 | func WithRandomSource(random rand.Source) Option { 118 | return func(c *Config) { 119 | c.random = random 120 | } 121 | } 122 | 123 | // Default options 124 | func WithDefault() Option { 125 | return With( 126 | WithEfConstruction(200), 127 | WithM(16), 128 | WithDefaultM0(), 129 | WithDefaultL(), 130 | WithRandomSource(rand.NewSource(time.Now().UnixNano())), 131 | ) 132 | } 133 | -------------------------------------------------------------------------------- /cmd/hnsw/sift/sift.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package sift 10 | 11 | import ( 12 | "errors" 13 | "fmt" 14 | "io" 15 | "math/rand" 16 | "os" 17 | "path/filepath" 18 | "time" 19 | 20 | "github.com/fogfish/hnsw" 21 | "github.com/fogfish/hnsw/vector" 22 | "github.com/kshard/fvecs" 23 | surface "github.com/kshard/vector" 24 | ) 25 | 26 | // New HNSW Index for given vector's dimension 27 | func New(m, m0, efC int, seed int64) *hnsw.HNSW[vector.VF32] { 28 | opts := hnsw.With( 29 | hnsw.WithEfConstruction(efC), 30 | hnsw.WithM(m), 31 | hnsw.WithM0(m0), 32 | ) 33 | if seed != 0 { 34 | opts = hnsw.With(opts, hnsw.WithRandomSource(rand.NewSource(seed))) 35 | } 36 | 37 | return hnsw.New(vector.SurfaceVF32(surface.Euclidean()), opts) 38 | } 39 | 40 | func scanner(dataset string, f func(vector.VF32) error) error { 41 | os.Stderr.WriteString(fmt.Sprintf("==> reading %s\n", dataset)) 42 | fd, err := os.Open(dataset) 43 | if err != nil { 44 | return err 45 | } 46 | defer fd.Close() 47 | 48 | t := time.Now() 49 | c := uint32(0) 50 | 51 | progress := func() { 52 | os.Stderr.WriteString( 53 | fmt.Sprintf("==> %9d vectors in %s (%d ns/op)\n", c, time.Since(t), time.Since(t).Nanoseconds()/int64(c)), 54 | ) 55 | } 56 | 57 | scanner := fvecs.NewDecoder[float32](fd) 58 | for { 59 | vec, err := scanner.Read() 60 | if err != nil { 61 | if errors.Is(err, io.EOF) { 62 | break 63 | } 64 | return nil 65 | } 66 | 67 | c++ 68 | if err := f(vector.VF32{Key: c, Vec: vec}); err != nil { 69 | return err 70 | } 71 | 72 | if c%10000 == 0 { 73 | progress() 74 | } 75 | } 76 | 77 | progress() 78 | return nil 79 | } 80 | 81 | //------------------------------------------------------------------------------ 82 | 83 | // Create new index from SIFT dataset 84 | func Create(h *hnsw.HNSW[vector.VF32], threads int, dataset string) error { 85 | w := h.Pipe(threads) 86 | 87 | data := fmt.Sprintf("%s/%s_base.fvecs", dataset, filepath.Base(dataset)) 88 | err := scanner(data, 89 | func(v vector.VF32) error { 90 | w <- v 91 | return nil 92 | }, 93 | ) 94 | if err != nil { 95 | return err 96 | } 97 | 98 | time.Sleep(5 * time.Second) 99 | return nil 100 | } 101 | 102 | //------------------------------------------------------------------------------ 103 | 104 | func Query(h *hnsw.HNSW[vector.VF32], dataset string) error { 105 | query := fmt.Sprintf("%s/%s_query.fvecs", dataset, filepath.Base(dataset)) 106 | 107 | truth := fmt.Sprintf("%s/%s_groundtruth.ivecs", dataset, filepath.Base(dataset)) 108 | fd, err := os.Open(truth) 109 | if err != nil { 110 | return err 111 | } 112 | defer fd.Close() 113 | 114 | tv := fvecs.NewDecoder[uint32](fd) 115 | 116 | k := 5 117 | success := 0 118 | failure := 0 119 | err = scanner(query, 120 | func(v vector.VF32) error { 121 | ids, err := tv.Read() 122 | if err != nil { 123 | return err 124 | } 125 | 126 | seq := h.Search(v, k, 100) 127 | i := 0 128 | s := 0 129 | 130 | for s < len(seq) && i < len(ids) { 131 | if ids[i] == uint32(seq[s].Key-1) { 132 | i++ 133 | s++ 134 | } else { 135 | i++ 136 | } 137 | } 138 | 139 | if s < k || i > k { 140 | fmt.Printf("FAIL: drift %2d, seq %2d\n", i-s, s) 141 | failure++ 142 | } else { 143 | success++ 144 | } 145 | 146 | return nil 147 | }, 148 | ) 149 | if err != nil { 150 | return err 151 | } 152 | 153 | rate := float64(failure) / float64(success+failure) 154 | fmt.Printf("==> %d success, %d failures (%2.3f)\n", success, failure, rate) 155 | 156 | return nil 157 | } 158 | -------------------------------------------------------------------------------- /codec.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package hnsw 10 | 11 | import ( 12 | "github.com/fogfish/faults" 13 | "github.com/kelindar/binary" 14 | ) 15 | 16 | const ( 17 | errIO = faults.Type("i/o error") 18 | errCodec = faults.Type("codec failed") 19 | ) 20 | 21 | // Reader interface abstracts persistent key/value storage 22 | type Reader interface{ Get([]byte) ([]byte, error) } 23 | 24 | // Writer interface abstract persistent key/value storage 25 | type Writer interface{ Put([]byte, []byte) error } 26 | 27 | type header struct { 28 | EfConstruction int 29 | MLayerN int 30 | MLayer0 int 31 | ML float64 32 | Size int 33 | Head Pointer 34 | Level int 35 | } 36 | 37 | // Write index 38 | func (h *HNSW[Vector]) Write(w Writer) error { 39 | h.rwCore.Lock() 40 | defer h.rwCore.Unlock() 41 | 42 | for i := 0; i < heapRWSlots; i++ { 43 | h.rwHeap[i].Lock() 44 | defer h.rwHeap[i].Unlock() 45 | } 46 | 47 | if err := h.writeHeader(w); err != nil { 48 | return err 49 | } 50 | 51 | if err := h.writeNodes(w); err != nil { 52 | return err 53 | } 54 | 55 | return nil 56 | } 57 | 58 | func (h *HNSW[Vector]) writeHeader(w Writer) error { 59 | v := header{ 60 | EfConstruction: h.config.efConstruction, 61 | MLayerN: h.config.mLayerN, 62 | MLayer0: h.config.mLayer0, 63 | ML: h.config.mL, 64 | Size: len(h.heap), 65 | Head: h.head, 66 | Level: h.level, 67 | } 68 | 69 | b, err := binary.Marshal(v) 70 | if err != nil { 71 | return errCodec.New(err) 72 | } 73 | 74 | err = w.Put([]byte("&root"), b) 75 | if err != nil { 76 | return errIO.New(err) 77 | } 78 | 79 | return nil 80 | } 81 | 82 | func (h *HNSW[Vector]) writeNodes(w Writer) error { 83 | var bkey [5]byte 84 | bkey[0] = '&' 85 | 86 | for key, node := range h.heap { 87 | binary.LittleEndian.PutUint32(bkey[1:], uint32(key)) 88 | 89 | b, err := binary.Marshal(node) 90 | if err != nil { 91 | return errCodec.New(err) 92 | } 93 | 94 | err = w.Put(bkey[:], b) 95 | if err != nil { 96 | return errIO.New(err) 97 | } 98 | } 99 | 100 | return nil 101 | } 102 | 103 | // Read index 104 | func (h *HNSW[Vector]) Read(r Reader) error { 105 | h.rwCore.Lock() 106 | defer h.rwCore.Unlock() 107 | 108 | for i := 0; i < heapRWSlots; i++ { 109 | h.rwHeap[i].Lock() 110 | defer h.rwHeap[i].Unlock() 111 | } 112 | 113 | if err := h.readHeader(r); err != nil { 114 | return err 115 | } 116 | 117 | if err := h.readNodes(r); err != nil { 118 | return err 119 | } 120 | 121 | return nil 122 | } 123 | 124 | func (h *HNSW[Vector]) readHeader(r Reader) error { 125 | var v header 126 | 127 | b, err := r.Get([]byte("&root")) 128 | if err != nil { 129 | return errIO.New(err) 130 | } 131 | 132 | if err := binary.Unmarshal(b, &v); err != nil { 133 | return errCodec.New(err) 134 | } 135 | 136 | h.config.efConstruction = v.EfConstruction 137 | h.config.mLayerN = v.MLayerN 138 | h.config.mLayer0 = v.MLayer0 139 | h.config.mL = v.ML 140 | h.heap = make([]Node[Vector], v.Size) 141 | h.head = v.Head 142 | h.level = v.Level 143 | 144 | return nil 145 | } 146 | 147 | func (h *HNSW[Vector]) readNodes(r Reader) error { 148 | var bkey [5]byte 149 | bkey[0] = '&' 150 | 151 | for key := 0; key < len(h.heap); key++ { 152 | binary.LittleEndian.PutUint32(bkey[1:], uint32(key)) 153 | 154 | b, err := r.Get(bkey[:]) 155 | if err != nil { 156 | return errIO.New(err) 157 | } 158 | 159 | if err := binary.Unmarshal(b, &h.heap[key]); err != nil { 160 | return errCodec.New(err) 161 | } 162 | } 163 | 164 | return nil 165 | } 166 | -------------------------------------------------------------------------------- /insert.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package hnsw 10 | 11 | import ( 12 | "math" 13 | 14 | "github.com/fogfish/hnsw/internal/pq" 15 | "github.com/fogfish/hnsw/internal/types" 16 | ) 17 | 18 | // anything in the range (-eps; +eps) is considered as similar item 19 | const minEps = -1e-6 20 | const maxEps = +1e-6 21 | 22 | // generate random float from random source generator 23 | func (h *HNSW[Vector]) rand() float64 { 24 | again: 25 | f := float64(h.config.random.Int63()) / (1 << 63) 26 | if f == 1 { 27 | goto again // resample; this branch is taken O(never) 28 | } 29 | return f 30 | } 31 | 32 | // Insert vector 33 | func (h *HNSW[Vector]) Insert(v Vector) { 34 | // 35 | // allocate new node 36 | // 37 | level := int(math.Floor(-math.Log2(h.rand()) * h.config.mL)) 38 | 39 | addr := Pointer(0) 40 | node := Node[Vector]{ 41 | Vector: v, 42 | Connections: make([][]Pointer, level+1), 43 | } 44 | 45 | // 46 | // Empty insert 47 | // 48 | if len(h.heap) == 0 { 49 | h.rwCore.Lock() 50 | if len(h.heap) == 0 { 51 | h.heap = append(h.heap, node) 52 | h.level = len(node.Connections) 53 | h.head = addr 54 | h.rwCore.Unlock() 55 | return 56 | } 57 | h.rwCore.Unlock() 58 | } 59 | 60 | // 61 | // skip down through layers 62 | // 63 | 64 | h.rwCore.RLock() 65 | head := h.head 66 | hLevel := h.level 67 | h.rwCore.RUnlock() 68 | 69 | for lvl := hLevel - 1; lvl > level; lvl-- { 70 | head = h.skip(lvl, head, v) 71 | } 72 | 73 | // 74 | // start building neighborhood 75 | // 76 | 77 | for lvl := min(level, hLevel-1); lvl >= 0; lvl-- { 78 | M := h.config.mLayerN 79 | if lvl == 0 { 80 | M = h.config.mLayer0 81 | } 82 | 83 | w := h.searchLayer(lvl, head, v, h.config.efConstruction) 84 | 85 | for w.Len() > M { 86 | w.Deq() 87 | } 88 | 89 | // Add Edges from new node to existing one 90 | edges := make([]Pointer, w.Len()) 91 | for i := w.Len() - 1; i >= 0; i-- { 92 | candidate := w.Deq() 93 | edges[i] = candidate.Addr 94 | 95 | // Consider the update 96 | if minEps < candidate.Distance && candidate.Distance < maxEps { 97 | if h.surface.Equal(h.heap[candidate.Addr].Vector, v) { 98 | h.heap[candidate.Addr].Vector = v 99 | return 100 | } 101 | } 102 | } 103 | node.Connections[lvl] = edges 104 | } 105 | 106 | // 107 | // Append new node 108 | // 109 | 110 | h.rwCore.Lock() 111 | addr = Pointer(len(h.heap)) 112 | h.rwHeap[addr%heapRWSlots].Lock() 113 | h.heap = append(h.heap, node) 114 | h.rwHeap[addr%heapRWSlots].Unlock() 115 | h.rwCore.Unlock() 116 | 117 | for lvl, edges := range node.Connections { 118 | for i := 0; i < len(edges); i++ { 119 | h.addConnection(lvl, edges[i], addr) 120 | } 121 | } 122 | 123 | // 124 | // Shrink Connections 125 | // 126 | 127 | for lvl, edges := range node.Connections { 128 | M := h.config.mLayerN 129 | if lvl == 0 { 130 | M = h.config.mLayer0 131 | } 132 | 133 | for _, e := range edges { 134 | slot := e % heapRWSlots 135 | h.rwHeap[slot].RLock() 136 | enode := h.heap[e] 137 | eedges := enode.Connections[lvl] 138 | h.rwHeap[slot].RUnlock() 139 | 140 | if len(eedges) > M { 141 | edges := pq.New(types.OrdReverseVertex) 142 | 143 | for _, n := range eedges { 144 | if n != addr { 145 | nnode := h.heap[n] 146 | 147 | dist := h.surface.Distance(enode.Vector, nnode.Vector) 148 | item := types.Vertex{Distance: dist, Addr: n} 149 | edges.Enq(item) 150 | } 151 | } 152 | 153 | for edges.Len() > M-1 { 154 | edges.Deq() 155 | } 156 | 157 | // Note: adjustment to original algorithms. 158 | // new connection is always created into the target node. 159 | // it reduces probability for new node to be disconnected. 160 | dist := h.surface.Distance(enode.Vector, node.Vector) 161 | item := types.Vertex{Distance: dist, Addr: addr} 162 | edges.Enq(item) 163 | 164 | conns := make([]Pointer, edges.Len()) 165 | for i := edges.Len() - 1; i >= 0; i-- { 166 | conns[i] = edges.Deq().Addr 167 | } 168 | 169 | h.rwHeap[slot].Lock() 170 | h.heap[e].Connections[lvl] = conns 171 | h.rwHeap[slot].Unlock() 172 | } 173 | } 174 | } 175 | 176 | // 177 | // Update Heap 178 | // 179 | 180 | h.rwCore.Lock() 181 | if len(node.Connections) > h.level { 182 | h.level = len(node.Connections) 183 | h.head = addr 184 | } 185 | h.rwCore.Unlock() 186 | } 187 | 188 | func (h *HNSW[Vector]) addConnection(level int, src, dst Pointer) { 189 | slot := src % heapRWSlots 190 | 191 | h.rwHeap[slot].RLock() 192 | n := h.heap[src] 193 | c := n.Connections[level] 194 | h.rwHeap[slot].RUnlock() 195 | 196 | h.rwHeap[slot].Lock() 197 | n.Connections[level] = append(c, dst) 198 | h.rwHeap[slot].Unlock() 199 | } 200 | -------------------------------------------------------------------------------- /cmd/hnsw/opt/sift.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package opt 10 | 11 | import ( 12 | "errors" 13 | "fmt" 14 | "io" 15 | "os" 16 | "strconv" 17 | 18 | "github.com/akrylysov/pogreb" 19 | "github.com/fogfish/hnsw" 20 | "github.com/fogfish/hnsw/cmd/hnsw/num" 21 | "github.com/fogfish/hnsw/cmd/hnsw/sift" 22 | "github.com/fogfish/hnsw/cmd/hnsw/viz" 23 | kv "github.com/fogfish/hnsw/vector" 24 | "github.com/spf13/cobra" 25 | ) 26 | 27 | func init() { 28 | rootCmd.AddCommand(siftCmd) 29 | 30 | siftCmd.AddCommand(siftCreateCmd) 31 | siftCreateCmd.Flags().StringVarP(&siftDataset, "sift", "s", "", "path to SIFT dataset") 32 | siftCreateCmd.Flags().IntVarP(&hnswEfConn, "efficiency-factor", "e", 200, "Construction Efficiency Factor") 33 | siftCreateCmd.Flags().IntVarP(&hnswM, "max-connections", "m", 16, "Maximum Connections") 34 | siftCreateCmd.Flags().IntVarP(&hnswM0, "max-connections-0", "0", 32, "Maximum Connections at Layer 0") 35 | 36 | siftCmd.AddCommand(siftQueryCmd) 37 | siftQueryCmd.Flags().StringVarP(&siftDataset, "sift", "s", "", "path to SIFT dataset") 38 | 39 | siftCmd.AddCommand(siftDrawCmd) 40 | siftDrawCmd.Flags().StringVar(&siftDrawHTML, "html", "hnsw.html", "visualized dataset") 41 | siftDrawCmd.Flags().IntVarP(&siftDrawLevel, "level", "l", 0, "level to visualize") 42 | siftDrawCmd.Flags().BoolVar(&siftDraw3D, "3d", false, "draw 3D visualization") 43 | } 44 | 45 | var siftCmd = &cobra.Command{ 46 | Use: "sift", 47 | Short: "evaluate HNSW algorithm using SIFT dataset.", 48 | Long: ` 49 | Evaluate HNSW algorithm using SIFT dataset. Obtain dataset copy for evaluation 50 | from http://corpus-texmex.irisa.fr. 51 | `, 52 | SilenceUsage: true, 53 | Run: root, 54 | } 55 | 56 | var ( 57 | siftDataset string 58 | siftDrawHTML string 59 | siftDrawLevel int 60 | siftDraw3D bool 61 | ) 62 | 63 | //------------------------------------------------------------------------------ 64 | 65 | var siftCreateCmd = &cobra.Command{ 66 | Use: "create", 67 | Short: "create HNSW index for SIFT dataset.", 68 | Long: ` 69 | Create persistent HNSW index using SIFT dataset. Obtain dataset copy for 70 | evaluation from http://corpus-texmex.irisa.fr. 71 | `, 72 | SilenceUsage: true, 73 | RunE: siftCreate, 74 | } 75 | 76 | func siftCreate(cmd *cobra.Command, args []string) (err error) { 77 | if siftDataset == "" { 78 | return errors.New("undefined SIFT dataset") 79 | } 80 | 81 | if hnswDataset == "" { 82 | return errors.New("undefined output HNSW index") 83 | } 84 | 85 | db, err := pogreb.Open(hnswDataset, nil) 86 | if err != nil { 87 | panic(err) 88 | } 89 | defer func() { 90 | err = db.Close() 91 | }() 92 | 93 | h := sift.New(hnswM, hnswM0, hnswEfConn, sysSeed) 94 | if err := sift.Create(h, sysThreads, siftDataset); err != nil { 95 | return err 96 | } 97 | 98 | if err := h.Write(db); err != nil { 99 | return err 100 | } 101 | 102 | os.Stderr.WriteString(fmt.Sprintf("==> created %s\n", siftDataset)) 103 | os.Stderr.WriteString(fmt.Sprintf(" %s\n", h)) 104 | 105 | return nil 106 | } 107 | 108 | //------------------------------------------------------------------------------ 109 | 110 | var siftQueryCmd = &cobra.Command{ 111 | Use: "query", 112 | Short: "query HNSW index for SIFT dataset.", 113 | Long: ` 114 | Query existing HNSW index using SIFT dataset. It uses ground truth dataset for 115 | validation. 116 | `, 117 | SilenceUsage: true, 118 | RunE: siftQuery, 119 | } 120 | 121 | func siftQuery(cmd *cobra.Command, args []string) (err error) { 122 | if hnswDataset == "" { 123 | return errors.New("undefined output HNSW index") 124 | } 125 | 126 | db, err := pogreb.Open(hnswDataset, nil) 127 | if err != nil { 128 | panic(err) 129 | } 130 | defer func() { 131 | err = db.Close() 132 | }() 133 | 134 | h := sift.New(hnswM, hnswM0, hnswEfConn, sysSeed) 135 | if err := h.Read(db); err != nil { 136 | return err 137 | } 138 | 139 | if err := sift.Query(h, siftDataset); err != nil { 140 | return err 141 | } 142 | 143 | return nil 144 | } 145 | 146 | //------------------------------------------------------------------------------ 147 | 148 | var siftDrawCmd = &cobra.Command{ 149 | Use: "draw", 150 | Short: "visualize HNSW index for SIFT dataset.", 151 | Long: ` 152 | Visualize existing HNSW index using SIFT dataset. 153 | `, 154 | SilenceUsage: true, 155 | RunE: siftDraw, 156 | } 157 | 158 | func siftDraw(cmd *cobra.Command, args []string) (err error) { 159 | if hnswDataset == "" { 160 | return errors.New("undefined output HNSW index") 161 | } 162 | 163 | db, err := pogreb.Open(hnswDataset, nil) 164 | if err != nil { 165 | panic(err) 166 | } 167 | defer func() { 168 | err = db.Close() 169 | }() 170 | 171 | h := sift.New(hnswM, hnswM0, hnswEfConn, sysSeed) 172 | if err := h.Read(db); err != nil { 173 | return err 174 | } 175 | 176 | os.Stderr.WriteString( 177 | fmt.Sprintf("==> draw %s\n", hnswDataset), 178 | ) 179 | 180 | if gloveDrawLevel > h.Level() { 181 | return fmt.Errorf("level must be in range of [0, %d]", h.Level()) 182 | } 183 | 184 | if siftDraw3D { 185 | if err := drawSiftLevel3D(siftDrawLevel, h); err != nil { 186 | return err 187 | } 188 | } else { 189 | if err := drawSiftLevel(siftDrawLevel, h); err != nil { 190 | return err 191 | } 192 | } 193 | 194 | return nil 195 | } 196 | 197 | func drawSiftLevel(level int, h *hnsw.HNSW[kv.VF32]) error { 198 | min, max := num.MinMaxDistance(level, h) 199 | upScaleD := func(d float32) float32 { return ((d - min) * 0.6) / (max - min) } 200 | vec2text := func(v kv.VF32) string { return strconv.Itoa(int(v.Key)) } 201 | 202 | nodes, links := viz.Visualize(level, h, upScaleD, vec2text) 203 | if len(nodes) == 0 || len(links) == 0 { 204 | return fmt.Errorf("level is empty") 205 | } 206 | 207 | f, err := os.Create(siftDrawHTML) 208 | if err != nil { 209 | return err 210 | } 211 | defer f.Close() 212 | 213 | page := viz.NewGraph(nodes, links) 214 | 215 | if err := page.Render(io.MultiWriter(f)); err != nil { 216 | return err 217 | } 218 | 219 | return nil 220 | } 221 | 222 | func drawSiftLevel3D(level int, h *hnsw.HNSW[kv.VF32]) error { 223 | vec2text := func(v kv.VF32) string { return strconv.Itoa(int(v.Key)) } 224 | nodes := viz.Visualize3D(level, h, vec2text) 225 | 226 | if len(nodes) == 0 { 227 | return fmt.Errorf("level is empty") 228 | } 229 | 230 | f, err := os.Create(siftDrawHTML) 231 | if err != nil { 232 | return err 233 | } 234 | defer f.Close() 235 | 236 | page := viz.NewScatter3D(nodes) 237 | 238 | if err := page.Render(io.MultiWriter(f)); err != nil { 239 | return err 240 | } 241 | 242 | return nil 243 | } 244 | -------------------------------------------------------------------------------- /cmd/hnsw/viz/visualize.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package viz 10 | 11 | import ( 12 | "math" 13 | 14 | "github.com/fogfish/hnsw" 15 | "github.com/fogfish/hnsw/cmd/hnsw/num" 16 | kv "github.com/fogfish/hnsw/vector" 17 | "github.com/go-echarts/go-echarts/v2/charts" 18 | "github.com/go-echarts/go-echarts/v2/components" 19 | "github.com/go-echarts/go-echarts/v2/opts" 20 | ) 21 | 22 | var ( 23 | schemaColor = []string{"#1F4B99", "#3A77A3", "#60A2B3", "#95CACB", "#D8EEEC", "#FDE7D7", "#F0B790", "#D98955", "#BD5C29", "#9E2B0E", "#DCE0E5"} 24 | schemaLabel = []string{"0.05", "0.1", "0.15", "0.2", "0.25", "0.3", "0.35", "0.4", "0.45", "0.5", "high"} 25 | 26 | schemaScatter3D = []string{"#1F4B99", "#2B5E9C", "#38709E", "#48819F", "#5B92A1", "#71A3A2", "#8AB3A2", "#A7C3A2", "#C7D1A1", "#EBDDA0", "#FCD993", "#F5C57D", "#EDB269", "#E49F57", "#DA8C46", "#CF7937", "#C4662A", "#B8541E", "#AB4015", "#9E2B0E"} 27 | ) 28 | 29 | func Categories() []*opts.GraphCategory { 30 | kinds := []*opts.GraphCategory{} 31 | 32 | for i, c := range schemaLabel { 33 | kinds = append(kinds, 34 | &opts.GraphCategory{ 35 | Name: c, 36 | ItemStyle: &opts.ItemStyle{ 37 | Color: schemaColor[i], 38 | }, 39 | }, 40 | ) 41 | } 42 | 43 | return kinds 44 | } 45 | 46 | //------------------------------------------------------------------------------ 47 | 48 | // Visualize layer of HNSW as graph 49 | func Visualize(level int, h *hnsw.HNSW[kv.VF32], upScaleD func(float32) float32, stringify func(kv.VF32) string) ([]opts.GraphNode, []opts.GraphLink) { 50 | xy := num.Text2D(num.ToMatrix(level, h)) 51 | minmax := num.MinMax(xy) 52 | spanX := minmax.At(0, 1) - minmax.At(0, 0) 53 | spanY := minmax.At(1, 1) - minmax.At(1, 0) 54 | 55 | upScaleX := func(row int) float32 { 56 | return float32(((xy.At(row, 0) - minmax.At(0, 0)) * 1024.0) / spanX) 57 | } 58 | 59 | upScaleY := func(row int) float32 { 60 | return float32(((xy.At(row, 1) - minmax.At(1, 0)) * 1024.0) / spanY) 61 | } 62 | 63 | nodes := []opts.GraphNode{} 64 | links := []opts.GraphLink{} 65 | 66 | row := 0 67 | 68 | h.ForAll(level, func(rank int, vector kv.VF32, vertex []kv.VF32) error { 69 | weight := float32(0.0) 70 | 71 | for _, dst := range vertex { 72 | d := upScaleD(h.Distance(vector, dst)) 73 | weight += d 74 | 75 | links = append(links, 76 | opts.GraphLink{ 77 | Source: stringify(vector), 78 | Target: stringify(dst), 79 | Value: d, 80 | LineStyle: &opts.LineStyle{Color: colorOf(d)}, 81 | }, 82 | ) 83 | } 84 | 85 | weight = weight / float32(len(vertex)) 86 | 87 | nodes = append(nodes, 88 | opts.GraphNode{ 89 | Name: stringify(vector), 90 | X: upScaleX(row), 91 | Y: upScaleY(row), 92 | Category: categoryOf(weight), 93 | SymbolSize: []int{4, 4}, 94 | }, 95 | ) 96 | row++ 97 | 98 | return nil 99 | }) 100 | 101 | return nodes, links 102 | } 103 | 104 | //------------------------------------------------------------------------------ 105 | 106 | // Visualize layer of HNSW as scattered points 107 | func Visualize3D(level int, h *hnsw.HNSW[kv.VF32], stringify func(kv.VF32) string) []opts.Chart3DData { 108 | xy := num.Text3D(num.ToMatrix(level, h)) 109 | minmax := num.MinMax(xy) 110 | spanX := minmax.At(0, 1) - minmax.At(0, 0) 111 | spanY := minmax.At(1, 1) - minmax.At(1, 0) 112 | spanZ := minmax.At(2, 1) - minmax.At(2, 0) 113 | 114 | upScaleX := func(row int) float32 { 115 | return float32(((xy.At(row, 0)-minmax.At(0, 0))*200.0)/spanX - 100.0) 116 | } 117 | 118 | upScaleY := func(row int) float32 { 119 | return float32(((xy.At(row, 1)-minmax.At(1, 0))*200.0)/spanY - 100.0) 120 | } 121 | 122 | upScaleZ := func(row int) float32 { 123 | return float32(((xy.At(row, 2)-minmax.At(2, 0))*200.0)/spanZ - 100.0) 124 | } 125 | 126 | row := 0 127 | nodes := []opts.Chart3DData{} 128 | h.ForAll(level, func(rank int, vector kv.VF32, vertex []kv.VF32) error { 129 | nodes = append(nodes, opts.Chart3DData{ 130 | Name: stringify(vector), 131 | Value: []any{ 132 | upScaleX(row), 133 | upScaleY(row), 134 | upScaleZ(row), 135 | }, 136 | }) 137 | 138 | row++ 139 | return nil 140 | }) 141 | 142 | return nodes 143 | } 144 | 145 | //------------------------------------------------------------------------------ 146 | 147 | func NewGraph(nodes []opts.GraphNode, links []opts.GraphLink) *components.Page { 148 | graph := charts.NewGraph() 149 | 150 | graph.AddSeries("graph", nodes, links). 151 | SetGlobalOptions( 152 | charts.WithInitializationOpts(opts.Initialization{ 153 | Width: "100%", 154 | Height: "100%", 155 | }), 156 | ). 157 | SetSeriesOptions( 158 | charts.WithGraphChartOpts(opts.GraphChart{ 159 | Layout: "force", 160 | Roam: opts.Bool(true), 161 | FocusNodeAdjacency: opts.Bool(true), 162 | Force: &opts.GraphForce{ 163 | Repulsion: 100.0, 164 | }, 165 | Categories: Categories(), 166 | }), 167 | charts.WithEmphasisOpts(opts.Emphasis{ 168 | Label: &opts.Label{ 169 | Show: opts.Bool(true), 170 | Color: "black", 171 | Position: "left", 172 | }, 173 | }), 174 | charts.WithLineStyleOpts(opts.LineStyle{ 175 | Curveness: 0.3, 176 | Color: "source", 177 | }), 178 | ) 179 | 180 | page := components.NewPage() 181 | page.SetLayout(components.PageFullLayout) 182 | page.AddCharts(graph) 183 | 184 | return page 185 | } 186 | 187 | //------------------------------------------------------------------------------ 188 | 189 | func NewScatter3D(points []opts.Chart3DData) *components.Page { 190 | 191 | graph := charts.NewScatter3D() 192 | graph.AddSeries("graph", points) 193 | graph.SetGlobalOptions( 194 | charts.WithInitializationOpts(opts.Initialization{ 195 | Width: "100%", 196 | Height: "100%", 197 | }), 198 | 199 | charts.WithVisualMapOpts( 200 | opts.VisualMap{ 201 | Calculable: opts.Bool(true), 202 | Min: -100, 203 | Max: 100, 204 | InRange: &opts.VisualMapInRange{Color: schemaScatter3D}, 205 | }, 206 | ), 207 | ) 208 | 209 | page := components.NewPage() 210 | page.SetLayout(components.PageFullLayout) 211 | page.AddCharts(graph) 212 | 213 | return page 214 | } 215 | 216 | //------------------------------------------------------------------------------ 217 | 218 | func colorOf(distance float32) string { 219 | // 0.5 distance corresponds to orthogonal vectors 220 | if distance > 0.5 { 221 | return "#DCE0E5" 222 | } 223 | 224 | norm := distance * float32(len(schemaColor)-2) / 0.5 225 | return schemaColor[int(math.Trunc(float64(norm)))] 226 | } 227 | 228 | func categoryOf(distance float32) int { 229 | if distance > 0.5 { 230 | return len(schemaLabel) - 1 231 | } 232 | 233 | norm := distance * float32(len(schemaColor)-2) / 0.5 234 | return int(math.Trunc(float64(norm))) 235 | } 236 | -------------------------------------------------------------------------------- /cmd/hnsw/opt/glove.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package opt 10 | 11 | import ( 12 | "errors" 13 | "fmt" 14 | "io" 15 | "os" 16 | 17 | "github.com/akrylysov/pogreb" 18 | "github.com/fogfish/hnsw" 19 | "github.com/fogfish/hnsw/cmd/hnsw/glove" 20 | "github.com/fogfish/hnsw/cmd/hnsw/viz" 21 | kv "github.com/fogfish/hnsw/vector" 22 | "github.com/kshard/atom" 23 | "github.com/spf13/cobra" 24 | ) 25 | 26 | func init() { 27 | rootCmd.AddCommand(gloveCmd) 28 | 29 | gloveCmd.AddCommand(gloveCreateCmd) 30 | gloveCreateCmd.Flags().StringVarP(&gloveDataset, "glove", "g", "", "path to GLoVe dataset") 31 | gloveCreateCmd.Flags().IntVarP(&hnswEfConn, "efficiency-factor", "e", 200, "Construction Efficiency Factor") 32 | gloveCreateCmd.Flags().IntVarP(&hnswM, "max-connections", "m", 16, "Maximum Connections") 33 | gloveCreateCmd.Flags().IntVarP(&hnswM0, "max-connections-0", "0", 32, "Maximum Connections at Layer 0") 34 | 35 | gloveCmd.AddCommand(gloveQueryCmd) 36 | gloveQueryCmd.Flags().StringVarP(&gloveDataset, "glove", "g", "", "path to GLoVe dataset") 37 | 38 | gloveCmd.AddCommand(gloveDrawCmd) 39 | gloveDrawCmd.Flags().StringVar(&gloveDrawHTML, "html", "hnsw.html", "visualized dataset") 40 | gloveDrawCmd.Flags().IntVarP(&gloveDrawLevel, "level", "l", 0, "level to visualize") 41 | gloveDrawCmd.Flags().BoolVar(&gloveDraw3D, "3d", false, "draw 3D visualization") 42 | } 43 | 44 | var gloveCmd = &cobra.Command{ 45 | Use: "glove", 46 | Short: "evaluate HNSW using GLoVe-like datasets", 47 | Long: ` 48 | The command-line utility support the creation and optimization of HNSW indices, 49 | using GloVe-like datasets. You can "create" an HNSW index tailored to your dataset, 50 | evaluate the index quality by "query" the same indexed words, and "draw" 51 | the graph layers to gain insights into the structure and connectivity of your data. 52 | 53 | Obtain dataset copy for evaluation from https://nlp.stanford.edu/projects/glove/, 54 | or use any textual representation following the format: 55 | 56 | word -0.37604 0.24116 ... -0.26098 -0.0079604 57 | `, 58 | SilenceUsage: true, 59 | Run: root, 60 | } 61 | 62 | var ( 63 | gloveDataset string 64 | gloveDrawHTML string 65 | gloveDrawLevel int 66 | gloveDraw3D bool 67 | ) 68 | 69 | //------------------------------------------------------------------------------ 70 | 71 | var gloveCreateCmd = &cobra.Command{ 72 | Use: "create", 73 | Short: "create HNSW index for using GLoVe-like datasets.", 74 | Long: ` 75 | Create persistent HNSW index using GLoVe-like dataset. 76 | 77 | Obtain dataset copy for evaluation from https://nlp.stanford.edu/projects/glove/, 78 | or use any textual representation following the format: 79 | 80 | word -0.37604 0.24116 ... -0.26098 -0.0079604 81 | `, 82 | SilenceUsage: true, 83 | RunE: gloveCreate, 84 | } 85 | 86 | func gloveCreate(cmd *cobra.Command, args []string) (err error) { 87 | if gloveDataset == "" { 88 | return errors.New("undefined GLoVe dataset") 89 | } 90 | 91 | if hnswDataset == "" { 92 | return errors.New("undefined output HNSW index") 93 | } 94 | 95 | db, err := pogreb.Open(hnswDataset, nil) 96 | if err != nil { 97 | panic(err) 98 | } 99 | defer func() { 100 | err = db.Close() 101 | }() 102 | 103 | atoms := atom.New(atom.NewPermanentMap(db)) 104 | 105 | h := glove.New(hnswM, hnswM0, hnswEfConn, sysSeed) 106 | if err := glove.Create(atoms, h, sysThreads, gloveDataset); err != nil { 107 | return err 108 | } 109 | 110 | if err := h.Write(db); err != nil { 111 | return err 112 | } 113 | 114 | os.Stderr.WriteString(fmt.Sprintf("==> created %s\n", hnswDataset)) 115 | os.Stderr.WriteString(fmt.Sprintf(" %s\n", h)) 116 | 117 | return nil 118 | } 119 | 120 | //------------------------------------------------------------------------------ 121 | 122 | var gloveQueryCmd = &cobra.Command{ 123 | Use: "query", 124 | Short: "evaluate the index quality by 'query' the same indexed words", 125 | Long: ` 126 | Evaluate the index quality by "query" the same indexed words. It considers 127 | query successful if result include it. 128 | `, 129 | SilenceUsage: true, 130 | RunE: gloveQuery, 131 | } 132 | 133 | func gloveQuery(cmd *cobra.Command, args []string) (err error) { 134 | if hnswDataset == "" { 135 | return errors.New("undefined output HNSW index") 136 | } 137 | 138 | db, err := pogreb.Open(hnswDataset, nil) 139 | if err != nil { 140 | panic(err) 141 | } 142 | defer func() { 143 | err = db.Close() 144 | }() 145 | 146 | atoms := atom.New(atom.NewPermanentMap(db)) 147 | 148 | h := glove.New(hnswM, hnswM0, hnswEfConn, sysSeed) 149 | if err := h.Read(db); err != nil { 150 | return err 151 | } 152 | 153 | os.Stderr.WriteString(fmt.Sprintf("==> reading %s\n", hnswDataset)) 154 | os.Stderr.WriteString(fmt.Sprintf(" %s\n", h)) 155 | 156 | if err := glove.Query(atoms, h, gloveDataset); err != nil { 157 | return err 158 | } 159 | 160 | return nil 161 | } 162 | 163 | //------------------------------------------------------------------------------ 164 | 165 | var gloveDrawCmd = &cobra.Command{ 166 | Use: "draw", 167 | Short: "visualize HNSW index.", 168 | Long: ` 169 | Visualize existing HNSW index using GloVe-like dataset. 170 | `, 171 | SilenceUsage: true, 172 | RunE: gloveDraw, 173 | } 174 | 175 | func gloveDraw(cmd *cobra.Command, args []string) (err error) { 176 | if hnswDataset == "" { 177 | return errors.New("undefined output HNSW index") 178 | } 179 | 180 | db, err := pogreb.Open(hnswDataset, nil) 181 | if err != nil { 182 | panic(err) 183 | } 184 | defer func() { 185 | err = db.Close() 186 | }() 187 | 188 | atoms := atom.New(atom.NewPermanentMap(db)) 189 | 190 | h := glove.New(hnswM, hnswM0, hnswEfConn, sysSeed) 191 | if err := h.Read(db); err != nil { 192 | return err 193 | } 194 | 195 | os.Stderr.WriteString(fmt.Sprintf("==> drawing %s\n", hnswDataset)) 196 | os.Stderr.WriteString(fmt.Sprintf(" %s\n", h)) 197 | 198 | if gloveDrawLevel > h.Level() { 199 | return fmt.Errorf("level must be in range of [0, %d]", h.Level()) 200 | } 201 | 202 | if gloveDraw3D { 203 | if err := drawGloveLevel3D(atoms, h, gloveDrawLevel); err != nil { 204 | return err 205 | } 206 | } else { 207 | if err := drawGloveLevel(atoms, h, gloveDrawLevel); err != nil { 208 | return err 209 | } 210 | } 211 | 212 | return nil 213 | } 214 | 215 | func drawGloveLevel(atoms *atom.Pool, h *hnsw.HNSW[kv.VF32], level int) error { 216 | upScaleD := func(d float32) float32 { return d } 217 | vec2text := func(v kv.VF32) string { return atoms.String(v.Key) } 218 | 219 | nodes, links := viz.Visualize(level, h, upScaleD, vec2text) 220 | if len(nodes) == 0 || len(links) == 0 { 221 | return fmt.Errorf("level is empty") 222 | } 223 | 224 | f, err := os.Create(gloveDrawHTML) 225 | if err != nil { 226 | return err 227 | } 228 | defer f.Close() 229 | 230 | page := viz.NewGraph(nodes, links) 231 | 232 | if err := page.Render(io.MultiWriter(f)); err != nil { 233 | return err 234 | } 235 | 236 | return nil 237 | } 238 | 239 | func drawGloveLevel3D(atoms *atom.Pool, h *hnsw.HNSW[kv.VF32], level int) error { 240 | vec2text := func(v kv.VF32) string { return atoms.String(v.Key) } 241 | nodes := viz.Visualize3D(level, h, vec2text) 242 | 243 | if len(nodes) == 0 { 244 | return fmt.Errorf("level is empty") 245 | } 246 | 247 | f, err := os.Create(gloveDrawHTML) 248 | if err != nil { 249 | return err 250 | } 251 | defer f.Close() 252 | 253 | page := viz.NewScatter3D(nodes) 254 | 255 | if err := page.Render(io.MultiWriter(f)); err != nil { 256 | return err 257 | } 258 | 259 | return nil 260 | } 261 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

Hierarchical Navigable Small World Graphs

4 |

in-memory data structure for approximate nearest neighbor search in high-dimensional spaces

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 | The HNSW algorithm is an efficient and scalable method for approximate nearest neighbor search in high-dimensional spaces. This Golang library provides a generic implementation of the HNSW algorithm, allowing users to build, search, and manage HNSW graphs for their data. See the original publication: [Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs](https://arxiv.org/pdf/1603.09320.pdf). 37 | 38 | ## Features 39 | 40 | - Fast and scalable nearest neighbor search. 41 | - Efficient indexing and querying of high-dimensional data. 42 | - Thread-safe and concurrent I/O. 43 | - Customizable parameters for tuning performance. 44 | - Easy-to-use API for building and querying HNSW graphs. 45 | - Generics for building and querying domain objects. 46 | - Command-line utility for index analysis. 47 | 48 | 49 | ## Getting Started 50 | 51 | - [Features](#features) 52 | - [Getting Started](#getting-started) 53 | - [Quick example](#quick-example) 54 | - [Key abstraction](#key-abstraction) 55 | - [Creating an Index](#creating-an-index) 56 | - [Insert vectors](#insert-vectors) 57 | - [Batch insert](#batch-insert) 58 | - [Searching for Nearest Neighbors](#searching-for-nearest-neighbors) 59 | - [Breadth-first search](#breadth-first-search) 60 | - [Example](#example) 61 | - [Command line utility](#command-line-utility) 62 | - [GLoVe](#glove) 63 | - [SIFT](#sift) 64 | - [How To Contribute](#how-to-contribute) 65 | - [commit message](#commit-message) 66 | - [bugs](#bugs) 67 | - [License](#license) 68 | - [References](#references) 69 | 70 | 71 | The latest version of the module is available at `main` branch. All development, including new features and bug fixes, take place on the `main` branch using forking and pull requests as described in contribution guidelines. The stable version is available via Golang modules. 72 | 73 | Use `go get` to retrieve the library and add it as dependency to your application. 74 | 75 | ```bash 76 | go get -u github.com/fogfish/hnsw 77 | ``` 78 | 79 | ### Quick example 80 | 81 | Here is [a simple example](./examples/basic/main.go) to get you started with this HNSW library: 82 | 83 | ```go 84 | package main 85 | 86 | import ( 87 | "fmt" 88 | 89 | "github.com/fogfish/hnsw" 90 | "github.com/fogfish/hnsw/vector" 91 | surface "github.com/kshard/vector" 92 | ) 93 | 94 | func main() { 95 | // Create new HNSW index 96 | index := hnsw.New(vector.SurfaceVF32(surface.Cosine())) 97 | 98 | // Add some data points to the index 99 | index.Insert(vector.VF32{Key: 1, Vec: []float32{0.1, 0.2, /* ... */ 0.128}}) 100 | index.Insert(vector.VF32{Key: 2, Vec: []float32{0.4, 0.5, /* ... */ 0.128}}) 101 | 102 | // Perform a nearest neighbor search 103 | query := vector.VF32{Vec: []float32{0.15, 0.25, /* ... */ 0.128} 104 | neighbors := index.Search(query, 10, 100) 105 | 106 | // Print the results 107 | fmt.Println("Nearest neighbors:", neighbors) 108 | } 109 | ``` 110 | 111 | The full documentation is available on [GoDoc](https://godoc.org/github.com/fogfish/hnsw). 112 | 113 | 114 | ### Key abstraction 115 | 116 | Data types definition is an essential part of development with the library. Golang structs declares domain of your application. 117 | 118 | The HNSW data structure utilizes Golang generics, allowing library clients to define their own types. This design decision, while potentially complicating initial adoption, makes the structure highly versatile and usable in any context. The library assumes nothing about the type it stores; instead, the client is only required to define the distance function against own types as 119 | 120 | ```go 121 | type Surface[Vector any] interface { 122 | Distance(Vector, Vector) float32 123 | } 124 | ``` 125 | 126 | To assist with implementation, the library provides a reference implementation at `github.com/fogfish/hnsw/vector` for float32 vector traits annotated with unique IDs (see `vector.VF32` and `vector.KF32`). Additionally, the companion library [vector](https://github.com/kshard/vector) helps implement efficient vector algebra. 127 | 128 | Here is [a example](./examples/attributes/main.go) to implement HNSW index for data type with custom attributes: 129 | 130 | ```go 131 | import ( 132 | "github.com/kshard/vector" 133 | ) 134 | 135 | // Custom type 136 | type Embedding struct { 137 | Vec surface.F32 138 | Text string 139 | /* ... add more attributes ... */ 140 | } 141 | 142 | // Declare surface distance function for Embedding. 143 | var ( 144 | surface = vector.ContraMap[vector.F32, Embedding]{ 145 | Surface: vector.Cosine(), 146 | ContraMap: func(e Embedding) vector.F32 { return e.Vec }, 147 | } 148 | ) 149 | 150 | // Create index for Embedding type 151 | index := hnsw.New(surface) 152 | ``` 153 | 154 | ### Creating an Index 155 | 156 | To create a new HNSW index, you need to specify the configuration parameters such as the distance function and the construction parameter: 157 | 158 | ```go 159 | hnsw.New(vector.SurfaceVF32(surface.Cosine()), 160 | // Construction Efficiency Factor (efConstruction) 161 | hnsw.WithEfConstruction(200), 162 | // Maximum number of connections per node (M) 163 | hnsw.WithM(16), 164 | // Maximum number of connections per node at level 0 (M0) 165 | hnsw.WithM0(32), 166 | ) 167 | ``` 168 | 169 | Optimization of given algorithm parameters is key to achieving the best performance for your specific use case. The primary parameters to focus on includes `M`, `M` and `efConstruction`. `M` and `M0` controls the maximum number of connections per node, balancing between memory usage and search efficiency. `efConstruction` determines the number of candidate nodes evaluated during graph construction, influencing both the construction time and the accuracy of the graph. Additionally, the `mL` parameter, or maximum level, dictates the hierarchical structure's depth, affecting both connectivity and search efficiency. You can optimize the balance between accuracy, speed, and resource usage, tailoring the HNSW algorithm to the demands of your dataset and application. The command line utility supports the hyper optimization process. 170 | 171 | **Be aware** that managing disconnected nodes is crucial in Hierarchical Navigable Small World (HNSW) Graphs to maintain the algorithm's efficiency and robustness. Disconnected nodes can occur when connections are pruned during the insertion of new nodes, leading to isolated nodes that degrade the performance of nearest neighbor searches. To mitigate this issue tune `M0`. This approach minimizes the risk of disconnections, ensuring reliable and efficient graph traversal during search operations. 172 | 173 | ### Insert vectors 174 | 175 | To insert vector to the index, use the `Insert` method passing appropriate data type: 176 | 177 | ```go 178 | index.Insert(vector.VF32{Key: 1, Vec: []float32{0.1, 0.2, /* ... */ 0.128}}) 179 | ``` 180 | 181 | ### Batch insert 182 | 183 | The HNSW library supports batch insert operations, making it efficient to add large datasets. It leverages Golang channels to handle parallel writes, ensuring that multiple data points can be inserted concurrently. This design maximizes performance and minimizes the time required to build the HNSW graph, making the library suitable for handling high-throughput data insertion scenarios. 184 | 185 | ```go 186 | // create channel for parallel writes 187 | ch := index.Pipe(runtime.NumCPU()) 188 | 189 | // insert vector to the index 190 | ch <- vector.VF32{Key: 1, Vec: []float32{0.1, 0.2, /* ... */ 0.128}} 191 | ``` 192 | 193 | ### Searching for Nearest Neighbors 194 | 195 | Searching for nearest neighbors in the HNSW library is performed using the `Search` function. This method requires a query vector parameter, which represents the point in the high-dimensional space for which you want to find the nearest neighbors. You have to wrap the vector to same data type as index support. The `efSearch` parameter controls the number of candidate nodes to evaluate during the search process, directly affecting the trade-off between search speed and accuracy. A higher `efSearch` value typically results in more accurate results at the expense of increased computation. The `k` parameter specifies the number of nearest neighbors to return. By tuning `efSearch` and `k`, you can balance performance and precision according to your specific needs. 196 | 197 | ```go 198 | query := vector.VF32{Vec: []float32{0.15, 0.25, /* ... */ 0.128}} 199 | neighbors := index.Search(query, 10, 100) 200 | ``` 201 | 202 | Use `Distance` function to fine-tune neighbors results, filtering non relevant values. 203 | 204 | ```go 205 | for _, vector := range neighbors { 206 | if index.Distance(query, vector) < 0.2 { 207 | // do something 208 | } 209 | } 210 | ``` 211 | 212 | ### Breadth-first search 213 | 214 | The HNSW library includes a breadth-first search functionality through the `ForAll` method. This method performs a full scan, iterating over all nodes linked at a specific level of the graph. It takes a visitor function as an argument, defined as `func(rank int, vector Vector, vertex []Vector) error`, where rank is the level of the node, vector is the node's vector, and vertex represents all outgoing edges. By performing a full scan, the `ForAll` method ensures comprehensive exploration of the graph's nodes, making it useful for applications that require a complete overview of the graph structure at a given level. 215 | 216 | ```go 217 | // Scan all nodes at level 0 218 | index.ForAll(0, 219 | func(rank int, vector Vector, vertex []Vector) error { 220 | // 221 | return nil 222 | }, 223 | ) 224 | ``` 225 | 226 | ### Example 227 | 228 | The following visualization illustrates a Hierarchical Navigable Small World (HNSW) graph constructed from 4,000 vectors representing the top English words. This graph showcases the hierarchical structure and navigability of the small-world network built using these word vectors. 229 | 230 | | | | 231 | | ------------------ | ------------------------------------------------------ | 232 | | HNSW Layer 2 | ![HNSW at Layer 2](./doc/hnsw-viz-words-4K-layer2.png) | 233 | | HNSW Layer 1 | ![HNSW at Layer 1](./doc/hnsw-viz-words-4K-layer1.png) | 234 | | HNSW Layer 0 | ![HNSW at Layer 0](./doc/hnsw-viz-words-4K-layer0.png) | 235 | | Vector point cloud | ![Vector point cloud](./doc/hnsw-viz-words-4K-3d.png) | 236 | 237 | 238 | ## Command line utility 239 | 240 | The HNSW library includes a command-line utility designed for hyper-optimizing the parameters of your HNSW graphs. This tool allows you to efficiently explore various configurations, such as `M`, `M0`, `efConstruction`, and others, to find the optimal settings for your specific dataset and use case. 241 | 242 | You can install the utility from source code. 243 | 244 | ```bash 245 | go install github.com/fogfish/hnsw/cmd/hnsw@latest 246 | ``` 247 | 248 | The command line utility is tailored for working with [GLoVe](https://nlp.stanford.edu/projects/glove/), [SIFT](http://corpus-texmex.irisa.fr) or your own dataset in the textual (GLoVe format). 249 | 250 | 251 | ### GLoVe 252 | 253 | The command-line utility support the creation and optimization of HNSW indices, using GloVe-like datasets. You can `create` an HNSW index tailored to your dataset, evaluate the index quality by `query` the same indexed words, and `draw` the graph layers to gain insights into the structure and connectivity of your data. The dataset assumes usage of cosine distance between words. 254 | 255 | Obtain GLoVe dataset copy for evaluation from https://nlp.stanford.edu/projects/glove/, or use any textual representation following the format: 256 | 257 | ``` 258 | word -0.37604 0.24116 ... -0.26098 -0.0079604 259 | ``` 260 | 261 | ```bash 262 | hnsw help glove 263 | 264 | hnsw glove create \ 265 | -i path/to/hnsw/index \ 266 | -g path/to/glove/dataset.txt \ 267 | -e 200 -m 16 -0 32 268 | 269 | hnsw glove query \ 270 | -i path/to/hnsw/index \ 271 | -g path/to/glove/dataset.txt 272 | 273 | hnsw glove draw \ 274 | -i path/to/hnsw/index \ 275 | --html path/to/graph.html 276 | -l 2 277 | ``` 278 | 279 | ### SIFT 280 | 281 | The command-line utility support the creation and validation of HNSW indices, using SIFT datasets that provides vectors dataset together with ground truth matches. You can `create` an HNSW index tailored to your dataset, evaluate the index quality by `query` the ground truth data , and `draw` the graph layers to gain insights into the structure and connectivity of your data. The dataset assumes usage of euclidean distance between indexed vectors. 282 | 283 | Obtain GLoVe dataset copy for evaluation from http://corpus-texmex.irisa.fr 284 | 285 | ```bash 286 | hnsw help sift 287 | 288 | hnsw sift create \ 289 | -i path/to/hnsw/index \ 290 | -g path/to/sift/dataset.txt \ 291 | -e 200 -m 16 -0 32 292 | 293 | hnsw sift query \ 294 | -i path/to/hnsw/index \ 295 | -g path/to/sift/dataset.txt 296 | 297 | hnsw sift draw \ 298 | -i path/to/hnsw/index \ 299 | --html path/to/graph.html 300 | -l 2 301 | ``` 302 | 303 | ## How To Contribute 304 | 305 | The library is [MIT](LICENSE) licensed and accepts contributions via GitHub pull requests: 306 | 307 | 1. Fork it 308 | 2. Create your feature branch (`git checkout -b my-new-feature`) 309 | 3. Commit your changes (`git commit -am 'Added some feature'`) 310 | 4. Push to the branch (`git push origin my-new-feature`) 311 | 5. Create new Pull Request 312 | 313 | The build and testing process requires [Go](https://golang.org) version 1.21 or later. 314 | 315 | 316 | ### commit message 317 | 318 | The commit message helps us to write a good release note, speed-up review process. The message should address two question what changed and why. The project follows the template defined by chapter [Contributing to a Project](http://git-scm.com/book/ch5-2.html) of Git book. 319 | 320 | ### bugs 321 | 322 | If you experience any issues with the library, please let us know via [GitHub issues](https://github.com/fogfish/hnsw/issue). We appreciate detailed and accurate reports that help us to identity and replicate the issue. 323 | 324 | 325 | ## License 326 | 327 | [![See LICENSE](https://img.shields.io/github/license/fogfish/hnsw.svg?style=for-the-badge)](LICENSE) 328 | 329 | 330 | ## References 331 | 332 | 1. [Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs](https://arxiv.org/pdf/1603.09320) 333 | 2. [GloVe: Global Vectors for Word Representation](https://nlp.stanford.edu/projects/glove/) 334 | 3. [Datasets for approximate nearest neighbor search](http://corpus-texmex.irisa.fr) 335 | 4. [t-SNE: t-distributed stochastic neighbor embedding](https://en.wikipedia.org/wiki/T-distributed_stochastic_neighbor_embedding) 336 | 5. [How to Use t-SNE Effectively](https://distill.pub/2016/misread-tsne/) 337 | 6. https://github.com/danaugrs/go-tsne 338 | 7. https://github.com/dwyl/english-words 339 | 8. https://echarts.apache.org/examples/en/index.html#chart-type-graph 340 | -------------------------------------------------------------------------------- /examples/basic/main.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package main 10 | 11 | import ( 12 | "fmt" 13 | "time" 14 | 15 | "github.com/fogfish/hnsw" 16 | "github.com/fogfish/hnsw/vector" 17 | surface "github.com/kshard/vector" 18 | ) 19 | 20 | var ( 21 | Jan = vector.VF32{Key: 1, Vec: []float32{1.086148, 0.980377, 1.071345, 1.544523, 2.065881, 2.157415, 0.454303, -1.033736, 0.905185, -0.194171, 1.859588, 0.343453, -0.003968, 1.806738, -0.038112, -0.555388, 0.997678, 0.126616, 1.010657, 0.586423, 0.573646, 0.886638, -0.201437, -1.136351, 0.842182, -1.955736, -0.430720, 0.650387, 0.480141, 0.746583, 1.323336, 0.775509, -1.495530, -0.660015, 0.161144, -0.494570, -0.511690, -1.296281, 0.045897, -0.089638, 0.399675, 1.090670, 0.825883, 0.810098, -1.258456, -1.189124, 0.689887, -0.404152, -1.324289, -0.847084, 1.143412, -1.010808, -0.187708, -0.624147, -1.113180, -1.629236, -0.180108, 0.669056, -0.758205, -0.448864, -0.949295, 0.606799, 2.010494, -1.152272, -2.859973, -0.002375, -1.261795, -0.417256, -1.650129, 0.551458, 1.243721, 0.510421, -1.377052, 0.134479, 1.285836, -1.390088, -0.402196, 0.888515, -0.305741, -1.079884, 0.439349, 0.372619, 1.994654, -0.478902, -1.598553, 1.308691, 0.302009, -0.278768, -1.239261, 0.337863, 1.270028, -1.067799, -0.315578, 0.434161, -1.702327, 0.893069, -0.262683, -0.267134, -0.040754, -0.078352, 0.069745, 0.631980, 1.478813, 0.812454, -0.569294, 0.694728, 1.125386, -0.030749, 0.034099, -1.186033, -0.431279, -0.153683, 0.179714, -0.765746, 0.543388, -0.289645, 0.787614, -1.099530, 1.668221, 0.584822, -0.497755, -0.141708, 1.613281, 0.468616, -0.676649, 1.826349, -0.038224, -0.125984, 0.978238, 0.013257, -0.790858, -0.549507, 0.419847, 0.489768, -0.284288, 0.014772, -0.724216, 0.666071, -0.129178, 0.127392, -0.760378, 0.345167, -1.240361, -0.528636, -0.614882, 0.253457, -1.231061, -1.242486, -1.253776, 0.342700, -0.686833, -0.130610, -0.493314, -0.762326, -0.928763, 0.196312, 0.106338, 1.006737, 0.714737, -0.506298, -1.020424, -0.531522, -1.261684, -0.376761, -0.475821, 0.695053, -1.743665, -0.103578, 0.343031, 0.859036, 0.916840, 0.563349, 1.556920, 0.284126, -0.847237, 1.270618, -2.772213, -1.209474, -0.344699, 0.733655, 0.553019, -0.019791, 1.085788, 1.657075, -0.323854, 0.641069, 1.181185, -1.179225, 1.111938, -0.026360, -1.451540, -0.743103, -0.503777, 0.180287, -1.792218, 2.239577, 1.341525, 1.088364, -0.506837, -1.037046, 0.159791, 0.756301, -2.204125, 0.694692, 0.428386, -0.726236, 1.123547, 1.092102, -1.260130, 1.922151, 0.652946, -0.417734, -0.338227, 0.825723, 1.181619, 0.837869, 1.607801, 1.186520, 0.317319, -0.164176, 0.414272, -0.640842, 1.095129, 0.556614, -0.625260, -0.030710, -2.278642, 0.284396, -1.572590, -0.639729, 0.307321, -0.490756, -0.346488, 1.443267, 0.341902, -0.510708, -0.161124, -2.146504, 0.505791, 1.165881, -1.658561, -2.134284, -1.380689, -0.121205, 0.018432, 0.318355, 0.527610, 0.095948, 1.864381, -1.169070, 0.314526, 1.130626, 0.366122, -1.336751, -0.771868, -1.760797, 0.509088, 0.600089, 0.253928, 0.960579, 0.087707, -0.795826, -0.193189, 2.625580, -0.164605, -0.191895, -1.189766, 0.518188, 0.989566, 0.336568, 0.132944, -1.171439, -2.960803, -1.156261, 0.512935, -0.393506, 1.461197, -2.971865, -0.706429, 1.292507, 1.253855, 0.162427, 0.266442, 0.426753, 1.099721, 1.607205, 0.655825, 0.369450, 0.049228, 0.791865, -0.358443, 0.679537, -0.483806, -0.969876, -0.577250, -0.840348, 1.309811, -0.385929, 0.378577, 0.417275}} 22 | Feb = vector.VF32{Key: 2, Vec: []float32{0.863843, 0.834412, 0.767967, 1.441759, 1.979645, 2.119818, -0.152409, -0.925577, 0.255454, 0.088092, 1.167256, 0.427990, -0.444017, 1.557952, -0.218379, -0.741931, 1.337525, -0.068751, 0.176268, 0.662023, 0.328259, 0.679177, -0.631597, -1.444511, 1.070807, -2.020582, -0.477180, 0.328347, -0.413543, 1.045343, 2.050766, 0.840585, -1.481687, -1.121763, -0.612197, -0.416140, -0.902469, -0.948633, -0.533500, -0.920458, 0.582824, 1.158915, 1.398063, 0.677171, -0.394278, -1.137193, 0.612642, 0.174038, -0.992636, -0.208506, 1.629065, -0.899818, 0.337043, -1.068766, -1.106952, -1.870604, 0.222933, -0.240857, -0.713956, -0.774561, -1.103365, 0.191678, 1.608780, -1.118621, -2.557125, -0.463295, -0.775955, -0.334767, -1.450772, 0.782128, 0.999984, 0.206194, -1.145143, -0.789347, 0.890442, -0.908306, -0.396356, 0.392883, -0.308325, -0.709919, 0.588891, 0.410281, 2.361948, -0.082487, -2.035475, 1.531478, 0.216232, -0.164408, -1.735564, -0.707018, 1.263637, -0.877970, -0.162191, 1.478629, -1.649958, 0.692522, -0.243004, -0.547843, -0.158000, -0.086265, 0.199225, -0.383671, 1.510256, 0.277312, -0.636759, 0.651880, 1.097998, 0.293551, 0.004639, -1.364130, -0.719183, 0.148478, 0.267185, -0.959793, 0.846114, -0.938919, 0.272693, -0.439031, 1.501335, 0.313972, -0.457307, -0.183739, 1.067966, 0.525256, -1.065531, 1.487073, -0.373041, -0.242663, 1.279020, -0.169860, -0.494803, -0.608964, 0.540460, 0.539295, 0.403507, 0.126699, 0.182753, 0.799895, -0.732601, -0.222616, -0.035708, -0.123696, -1.382190, -0.257442, 0.431286, -0.066622, -1.374102, -0.260221, -1.725099, 0.627368, -0.513460, 0.895435, -0.806397, -0.886610, -0.536780, 0.325561, -0.017678, 1.286493, 0.943032, -1.030374, -1.116311, -0.478834, -0.990620, 0.237227, -0.036306, 0.973816, -1.690858, -0.270290, 0.164928, 1.194907, 0.690722, 0.510960, 1.540581, 0.335098, -0.952401, 1.367250, -2.734142, -1.664903, -0.362587, 1.052118, 0.170769, 0.141752, 1.210011, 1.913445, -0.357750, 0.397618, 0.964370, -1.106375, 0.706907, 0.058149, -1.775667, -0.807866, -0.280380, 0.080289, -0.775017, 1.781382, 1.523313, 0.698079, -0.585351, -0.965756, 0.343741, 0.900078, -1.975462, -0.037753, 0.401768, -0.897169, 1.187217, 1.701761, -1.036627, 2.078473, 0.692022, -0.629359, -1.073511, 0.982222, 1.199937, 0.968442, 1.253772, 0.495507, 0.195453, 0.273791, 0.815910, -0.786922, 1.306433, 0.446073, -0.925321, 0.248089, -2.528068, 0.778926, -1.418931, -0.317748, 0.825230, -0.863813, -0.171744, 1.200187, 0.077496, -1.073315, -0.040422, -1.715621, 0.207671, 0.957527, -1.070138, -2.079015, -1.899029, 0.049671, 0.379471, 0.227733, 0.170514, -0.435170, 1.915718, -0.789699, 0.135722, 0.606490, 0.779467, -0.480242, -0.659674, -1.651008, -0.138721, 0.452251, -0.258198, 0.434695, 0.041625, -0.273274, -0.505310, 2.912049, 0.039981, 0.165387, -1.747939, 0.885967, 0.980371, 0.465048, 0.130152, -1.256838, -2.564538, -1.352994, -0.206697, 0.322895, 1.760243, -2.333582, -0.657256, 1.296127, 1.355597, -0.390070, 0.800925, 0.928465, 0.629793, 1.864801, 1.271766, 0.323438, 0.495335, 0.940038, -0.287337, 0.724428, -0.420535, -1.393595, -0.088316, -0.802756, 1.671690, -0.305128, 0.313227, 0.451491}} 23 | Mar = vector.VF32{Key: 3, Vec: []float32{1.320395, 0.848528, 0.704421, 1.423122, 1.925830, 2.264947, 0.305817, -0.344170, -0.304653, 0.339275, 0.861341, 0.598434, 0.115942, 1.893419, 0.347116, -0.410508, 0.858695, -0.465234, 0.176406, 1.361156, -0.032105, 0.293770, -0.142674, -1.738622, 0.895677, -1.726089, -0.160320, 0.433331, -0.327188, 0.935088, 2.005640, 1.222845, -1.913726, -1.382722, -0.254853, -1.293203, -1.042308, -1.040702, -0.195514, -1.064200, 0.502490, 1.005676, 1.314858, 1.063727, 0.240671, -0.951861, 0.856411, 0.470810, -0.722048, -0.388575, 1.428116, -0.622312, 0.402563, -0.164345, -1.160401, -1.600752, 0.745722, 0.257587, -0.128991, -0.236142, -1.111861, -0.208283, 1.675631, -1.609689, -2.225040, -0.685392, -0.888058, -1.039457, -1.315974, 0.983658, 0.803106, 0.656526, -1.320289, -0.269896, 0.285642, -1.289004, -0.367522, 0.482059, 0.050950, -1.096899, 0.410171, 0.668005, 1.910987, -0.232351, -1.389734, 1.749195, 0.773647, -0.148164, -1.663736, -0.939839, 0.670158, -0.591140, -0.429618, 1.421001, -2.018159, 0.829756, -0.258516, -0.751333, -0.626013, -0.455041, -0.407524, -0.200833, 1.848797, 0.230392, -0.313479, 0.420008, 0.554813, 0.254758, -0.094077, -1.255889, -0.048290, 0.537468, -0.072036, -0.613983, 0.728068, -0.662861, 0.166225, -0.310689, 2.186502, 0.669082, -0.504409, 0.011212, 1.512129, 1.110640, -1.142577, 1.384355, -0.188313, -0.100203, 1.205011, -0.251342, -0.911722, -0.540738, 0.228294, 0.709907, 1.013594, 0.324900, -0.146337, 0.644103, -0.083229, -0.244335, 0.093592, 0.027596, -1.271179, -0.858105, 0.302756, -0.192842, -1.582592, -0.331267, -1.953504, 0.135636, -0.459141, 0.521030, -1.074115, -0.450643, -0.623794, 0.521083, -0.290532, 1.240419, 0.921032, -0.738373, -0.785081, -0.413102, -1.202347, 0.085647, 0.272996, 0.910936, -1.353536, -0.017207, -0.067627, 1.014471, 0.486180, 0.554923, 1.524420, 0.363201, -1.007632, 1.320969, -2.914411, -1.882532, -0.560343, 0.704276, 0.318686, -0.490492, 1.540093, 1.578905, -0.615803, 0.537423, 1.132374, -0.831606, 0.743541, 0.225530, -1.312965, -1.252651, -0.204747, 0.355962, -0.976505, 1.897576, 1.835031, 1.506927, -0.286618, -0.597685, 0.952475, 0.175615, -1.904108, -0.260357, 0.506206, -0.953668, 1.646633, 1.611063, -0.812283, 1.827847, 0.306678, -0.253673, -0.305113, 0.529505, 1.492202, 0.640940, 1.655517, 0.022800, -0.269071, 0.087833, 0.727152, -0.480812, 0.898927, 0.026657, -0.453094, 0.272977, -2.313351, 0.464524, -1.148658, -0.504678, 0.858572, -0.665205, 0.290333, 1.136463, -0.013706, -0.833448, -0.319156, -1.832496, 0.613189, 0.853094, -1.631312, -2.263570, -1.204134, -0.188827, 0.123913, 0.179924, 0.208717, -0.805608, 1.837492, -0.642940, 0.136217, 0.860895, 0.761989, -0.720712, -0.653274, -1.607307, 0.091833, 0.880150, -0.096851, 0.485980, -0.272285, -0.842101, -0.296788, 2.926239, -0.061680, 0.041489, -1.925525, 0.927647, 1.284915, 0.451289, 0.415674, -1.663582, -2.689622, -1.277330, -0.033117, 0.293511, 1.283250, -2.251521, -0.937326, 1.563402, 0.311000, -0.875986, 0.216013, 1.125768, 0.752567, 1.498770, 0.915869, 0.662268, 0.392064, 0.873420, -0.596787, 0.429586, -0.283244, -1.467683, -0.234297, -0.647331, 1.275938, -0.232804, 0.597012, -0.022341}} 24 | Apr = vector.VF32{Key: 4, Vec: []float32{0.889234, 0.850274, 0.874889, 1.704348, 2.418694, 2.017295, 0.245924, -1.062022, 0.169842, 0.085362, 1.448353, 0.617088, -0.337177, 1.500970, -0.004566, -0.682291, 0.963418, -0.429490, 0.538826, 1.106818, 0.688008, 0.494462, -0.383412, -1.503660, 0.810763, -2.079937, -0.531183, 0.555345, -0.101067, 0.910118, 1.478240, 1.080644, -1.873836, -1.095774, -0.591963, -0.966131, -1.157680, -0.799843, 0.015950, -0.626820, 0.399315, 1.004897, 1.315348, 0.549850, 0.193941, -0.851153, 0.863186, 0.152940, -1.182206, -0.338813, 1.539671, -0.758084, 0.274242, -0.536658, -0.933949, -1.430804, 0.371569, 0.165304, -0.694454, -0.579532, -1.221094, -0.285913, 1.995314, -1.161382, -2.176816, -0.605719, -0.915929, -0.636219, -1.172193, 0.658554, 0.980474, 0.384841, -1.213187, -0.308638, 0.534761, -0.891433, -0.403050, 0.341551, -0.010667, -1.011724, 0.358064, 0.288373, 2.231461, -0.277990, -1.553067, 1.279105, 0.243052, -0.221418, -1.608192, -0.579980, 1.027069, -0.597810, -0.034130, 1.090712, -1.826084, 0.784525, 0.129640, -0.505121, -0.493802, -0.074793, -0.778566, -0.565970, 2.076428, 0.325651, -0.437679, 0.604429, 0.963960, 0.283912, 0.144850, -1.434682, -0.418146, 0.422626, 0.589343, -0.713689, 0.482611, -0.851913, 0.337479, -0.192025, 2.114732, 0.247890, -0.656879, -0.227433, 1.170673, 0.823480, -0.991431, 1.396380, -0.365972, -0.302597, 1.138377, -0.262685, -0.764862, -0.101200, 0.718027, 0.713953, 0.800762, 0.303217, -0.151558, 0.747138, -0.452142, -0.322497, -0.013809, -0.376913, -1.622386, -0.340648, 0.108092, 0.305132, -1.126016, -0.405195, -2.029316, 0.633802, -0.822035, 0.704594, -0.689308, -1.178872, -0.263945, -0.073298, -0.245987, 1.380323, 0.841403, -0.884681, -0.604581, -0.602082, -0.917923, -0.181644, -0.150408, 1.000710, -1.588809, 0.310616, 0.306349, 1.343197, 0.742409, 0.853787, 1.642857, 0.421971, -0.983606, 1.094037, -2.920673, -1.610627, -0.471835, 0.987661, 0.484488, -0.651407, 1.478175, 2.003170, -0.057947, 0.417251, 0.747966, -1.140194, 1.126976, 0.274967, -1.849598, -1.111743, -0.302162, 0.063235, -1.156401, 1.353594, 1.555844, 1.193506, -0.003208, -0.656334, 0.303128, 0.551664, -1.608392, -0.181028, 0.323090, -0.732299, 1.370045, 1.542002, -0.919291, 1.992092, 0.535234, 0.266810, -0.483004, 1.113044, 1.368998, 0.917721, 1.431987, 0.374176, -0.155113, 0.142180, 1.051985, -0.287175, 1.022032, 0.055056, -0.351141, 0.162697, -2.204322, 0.789971, -1.367697, -0.080956, 0.689354, -0.361272, -0.476382, 1.218314, 0.041879, -0.989796, -0.151225, -2.223488, 0.261868, 1.172489, -1.223110, -2.278040, -1.780869, -0.159160, 0.143638, 0.324550, 0.691479, -0.523870, 1.657111, -1.066579, 0.167808, 0.715926, 1.417295, -0.758445, -0.449851, -1.755778, -0.044620, 0.090462, -0.262309, 0.076480, 0.039296, -0.546645, -0.263545, 2.779835, -0.055745, -0.084523, -1.447093, 1.085526, 0.835604, 0.578110, 0.086655, -1.700222, -2.737127, -1.239529, -0.609708, 0.419031, 1.619995, -2.368754, -0.596594, 1.428266, 1.313068, -0.741654, 0.290380, 1.010022, 0.695741, 1.646288, 0.821885, 0.087528, 0.030776, 1.013950, 0.069064, 0.744366, -0.199043, -1.480556, -0.249497, -1.006421, 1.721708, -0.533348, 0.373670, 0.658661}} 25 | May = vector.VF32{Key: 5, Vec: []float32{-0.37604, 0.24116, -0.26098, -0.0079604, 0.2198, 0.098515, 0.23458, 0.13797, 0.11026, -1.7503, 0.15728, 0.50099, -0.070068, 0.023731, 0.39848, 0.34406, 0.2725, -0.31173, -0.083764, -0.22098, -0.27032, -0.061412, 0.23487, -0.10898, -0.50068, -0.19188, -0.081558, -0.49529, -0.11206, 0.055647, 0.34762, 0.38117, 0.25134, 0.22155, -0.60474, 0.14916, 0.034044, 0.080041, -0.025968, -0.024241, -0.25607, 0.15805, 0.059879, 0.35204, -0.33104, -0.21203, -0.11276, 0.21901, -0.42762, -0.073376, 0.2087, -0.19191, 0.10252, 0.13545, 0.034747, 0.2744, -0.14779, 0.031078, 0.25385, 0.31864, 0.28914, 0.076552, 0.38445, 0.13276, -0.023181, -0.80946, 0.21977, 0.38286, -0.0099079, 0.1311, 0.033017, 0.062568, 0.1304, -0.055305, -0.43903, -0.071552, 0.24424, 0.029362, -0.09076, -0.091094, 0.19034, -0.28601, -0.092019, -0.018266, -0.046318, -0.22229, -0.0035013, 0.37954, 0.042987, 0.24319, -0.61973, 0.17455, -0.010297, -0.19769, -0.028611, 0.25263, -0.42774, 0.18326, 0.042894, -0.45469, 0.024955, -0.19844, -0.22603, 0.5447, -0.078387, -0.19611, -0.036302, -0.35798, 0.098273, 0.35702, 0.033349, -0.041258, -0.088868, -0.37277, 0.16962, -0.0018967, -0.11081, 0.11871, 0.32646, -0.54318, -0.0060212, -0.42852, 0.11824, 0.13754, 0.15223, 0.013127, 0.29583, -0.17568, 0.32801, -0.34822, -0.39004, 0.53055, 0.27993, 0.34217, 0.10086, -0.1984, -0.23966, -0.088367, -0.2531, -0.085551, -0.31834, -0.0095886, -0.14605, 0.20637, -0.21729, -0.10325, -0.12783, 0.30865, -0.46587, 0.28135, 0.077259, 0.024987, 0.07764, -0.1971, 0.10445, -0.017228, -0.045139, -0.047205, -0.19365, 0.12006, -0.11591, -0.064879, -0.13913, 0.13766, 0.16368, 0.47388, -0.003217, -0.15248, 0.16059, 0.42005, 0.37255, 0.45046, -0.39264, 0.2167, -0.24217, -0.27105, 0.21422, 0.37381, -0.28921, 0.67957, -0.09934, 0.14129, 0.13669, 0.18308, -0.04637, 0.18081, -0.20207, 0.11194, 0.40635, 0.041006, -0.26205, 0.24239, 0.10954, -0.0025109, -0.31055, -0.39472, 0.46873, -0.26605, 0.0003155, -0.2781, 0.77845, -0.081538, -0.17148, 0.17038, -0.032289, 0.36118, 0.07083, 0.31458, -0.50364, -0.41388, 0.19972, -0.34238, 0.37245, -0.049874, -0.039695, 0.11291, 0.44979, 0.29775, -0.14373, -0.11168, 0.0086446, -0.14489, -0.2899, -0.19745, -0.085559, -0.29691, 0.2741, -0.071754, 0.23885, -0.17967, 0.045782, 0.19417, 0.0017401, -0.36253, -0.047268, 0.60928, 0.14532, -0.015873, -0.15849, -0.3826, -0.11274, -0.37488, 0.76094, -0.11912, -0.77917, 0.20749, 0.29988, -0.56498, 0.017913, -0.13273, 0.15938, -0.23032, -0.27924, 0.15282, -0.049281, 0.047475, 0.17481, -0.15886, 0.28165, 0.053054, 0.005466, -0.51198, -0.080661, 0.069866, -0.16794, -0.51912, 0.15684, -0.00071678, 0.10139, 0.16274, 0.18913, 0.15799, 0.55748, -0.051792, -0.14222, 0.084011, -1.8705, -0.2938, 0.42032, 0.0918, -0.26313, 0.12525, 0.44998, 0.36353, -0.19611, 0.1276, -0.3045, -0.061133, -0.027884, -0.011002, -0.083795, -0.1581, 0.32567, -0.4293, 0.11057, 0.3123, -0.25579, -0.75731, 0.097391, -0.08183}} 26 | Jun = vector.VF32{Key: 6, Vec: []float32{1.036540, 0.546969, 0.682225, 1.619027, 1.857694, 2.280705, 0.462707, -0.603202, 0.049518, 0.109536, 1.745253, 0.255977, -0.168170, 1.558392, 0.263142, -0.660832, 1.116244, 0.067872, 0.991019, 1.099545, 0.657584, 0.727799, -0.601647, -1.598989, 0.926662, -2.260845, -0.467635, 0.081023, 0.076706, 1.344466, 1.706524, 0.649527, -1.679096, -0.730862, -0.823532, -0.948478, -0.873514, -0.903392, -0.295259, -0.347673, 0.665391, 0.990738, 1.212980, 0.514580, -0.423756, -1.452311, 0.860289, 0.188581, -1.175361, -0.381487, 1.072647, -0.472692, 0.144981, -0.734162, -1.110243, -1.159058, 0.141118, 0.206652, -0.094864, -0.821367, -1.403696, -0.203194, 2.041277, -1.152582, -2.370972, -0.278623, -0.745128, -0.775113, -1.730716, 0.460334, 1.322744, 0.417837, -1.187664, -0.558460, 0.522802, -0.653232, -0.203764, 0.044597, 0.297716, -0.533234, 0.314883, 0.686437, 2.363522, -0.259957, -1.985401, 1.517309, 0.211923, 0.265879, -1.440608, -0.279308, 0.411235, -1.365269, -0.432263, 1.014367, -1.935541, 0.552363, 0.266799, -0.571557, -0.579142, -0.356888, -0.056538, 0.324536, 1.739126, 0.356806, -0.504803, 0.513064, 1.383744, 0.332912, 0.109297, -0.942169, -0.307139, 0.411564, 0.330522, -0.571179, 0.524751, -0.630205, 0.458416, -0.317862, 1.983600, 0.615994, -0.835104, -0.086852, 1.388516, 1.048700, -0.812822, 1.597238, -0.038695, -0.098320, 1.369465, -0.064687, -0.527911, -0.192985, 0.804706, 0.689003, 0.839296, 0.066297, -0.480740, 0.719132, -0.212911, -0.145413, 0.105600, -0.121319, -1.286524, -0.640703, -0.168864, 0.399286, -1.231946, -0.807043, -1.756248, 0.757814, -0.752825, 1.132907, -1.080017, -0.985473, -0.647810, 0.494041, -0.125647, 1.396656, 0.790061, -0.918778, -0.408365, -1.017052, -1.058472, -0.124559, -0.385773, 1.317527, -1.575095, 0.095171, 0.503692, 1.703586, 0.970864, 1.057869, 1.409394, 0.157485, -0.602411, 1.240161, -2.978426, -0.969381, -0.701221, 0.673723, 0.416678, -0.068766, 1.001517, 1.833978, -0.216807, 0.196628, 0.724457, -1.236636, 0.885444, -0.434618, -1.785954, -1.295137, -0.400275, -0.308485, -1.099225, 1.876500, 1.893056, 0.545735, -0.235084, -0.550314, -0.263440, 0.271569, -2.003980, -0.032058, 0.254051, -0.775235, 1.594377, 1.282338, -1.187373, 2.106279, 0.737230, 0.228264, -0.220703, 0.863467, 1.790426, 0.451643, 1.365718, 0.778219, 0.141991, 1.077456, 0.664807, -0.224345, 1.252004, 0.096293, -0.078906, -0.114109, -2.167131, 0.897457, -1.215864, -0.349698, 0.681056, -0.551970, -0.077094, 1.598078, -0.002608, -0.864052, 0.237962, -2.055780, 0.011823, 1.136935, -0.930098, -1.998164, -1.990586, 0.368082, -0.181903, 0.217795, 0.206548, -0.506491, 1.418166, -0.611350, -0.100018, 0.672583, 1.191272, -1.341299, -0.425044, -1.982306, -0.530068, 0.273478, -0.130283, 0.184311, 0.157988, -0.678781, -0.712540, 2.272594, -0.287060, -0.070493, -1.264626, 1.160303, 0.268237, 0.705274, 0.164905, -1.435192, -2.699068, -1.290640, -0.104979, 0.440403, 1.669127, -2.691568, -0.961174, 0.878749, 1.159540, -0.259053, 0.465110, 0.588688, 1.312046, 1.777309, 0.956853, 0.597408, 0.007668, 0.271935, -0.179231, 0.646022, 0.001665, -1.172982, -0.083007, -0.956250, 1.261846, -0.072911, 0.393786, 0.245709}} 27 | Jul = vector.VF32{Key: 7, Vec: []float32{1.138271, 0.790593, 0.988634, 1.729306, 1.886875, 1.967648, -0.157556, -0.876982, 0.450545, 0.026977, 1.577323, 0.353218, -0.495040, 1.906863, 0.091444, -0.368458, 1.129238, -0.368361, 1.199798, 0.804840, 0.648151, 0.828091, -0.293887, -1.455547, 0.867944, -1.967912, -0.535779, 0.392205, -0.476648, 0.933586, 1.048640, 0.954908, -1.641251, -0.244135, -0.571074, -0.841517, -1.259406, -1.615447, -0.420757, -0.115084, 0.384331, 1.116191, 1.045647, 0.755925, -0.405124, -1.524020, 0.991367, -0.148226, -0.989243, -0.208606, 0.842985, -0.779207, 0.019453, -0.962132, -1.080064, -1.037277, -0.146641, 0.053057, -0.342300, -0.230606, -1.191770, 0.190107, 2.168518, -1.058119, -2.513550, -0.326502, -0.868132, -0.666673, -1.928643, 0.640266, 1.536754, 0.274456, -1.284815, -0.570932, 0.788092, -1.285053, -0.286308, 0.213928, 0.217690, -0.903204, 0.044244, 0.685908, 2.514129, -0.425186, -1.951683, 1.164671, 0.478086, 0.078633, -1.415431, -0.583380, 1.491450, -0.855399, -0.014535, 0.702505, -1.685143, 0.289857, 0.137451, -0.654170, -0.253289, -0.062705, -0.028650, 0.295153, 1.522754, 0.272928, -0.559312, 0.462845, 1.036449, 0.200446, 0.192529, -0.951793, -0.495174, -0.077213, 1.032960, -0.678964, 0.575119, -0.446675, 0.423770, -0.372890, 1.694313, 0.717929, -0.668641, 0.304761, 1.576035, 0.576164, -0.523488, 1.611880, -0.199664, -0.171586, 1.114140, -0.288768, -1.136209, 0.166317, 0.334959, 0.261725, 0.684927, 0.076527, -0.657697, 0.774720, -0.369026, 0.106780, 0.054052, -0.149635, -1.237101, -0.525032, 0.093665, 0.169911, -0.946435, -0.722021, -1.640050, 0.441190, -1.441454, 0.604225, -0.888969, -0.881575, -0.607427, 0.870209, -0.002016, 1.254662, 1.209216, -0.678927, -0.686509, -1.462612, -1.240944, 0.050033, -0.333461, 1.071059, -1.559879, 0.148454, 0.436936, 1.544271, 0.509421, 0.891890, 1.934450, 0.971477, -0.698805, 0.932790, -2.929860, -1.270368, -0.707287, 0.608710, 0.285007, -0.083925, 1.259068, 1.975407, -0.325491, 0.192746, 0.493369, -1.233861, 0.841210, -0.557954, -1.987419, -1.026524, -0.653557, -0.074514, -0.894527, 1.537106, 1.918728, 0.769538, -0.270091, -0.841949, -0.465037, 0.580329, -2.068741, -0.122669, 0.292804, -0.909491, 1.304980, 1.399283, -0.925365, 2.073050, 0.545720, 0.550380, -0.592549, 0.969717, 1.543133, 0.304340, 1.027979, 1.123738, -0.003943, 0.215501, 0.383079, -0.651258, 1.309091, 0.452836, 0.075356, -0.050422, -1.958724, 0.922330, -1.139794, -0.519272, 0.848986, -0.566963, -0.296832, 1.579726, 0.408311, -0.725003, 0.131820, -2.195414, -0.194259, 1.763461, -0.759866, -1.789942, -1.495166, 0.100403, -0.092975, 0.380394, 0.122669, -0.149844, 1.512750, -0.840042, -0.254883, 0.827037, 1.022277, -1.370214, -0.899545, -1.927375, -0.410887, 0.253221, 0.245714, 0.246460, 0.152955, -0.499900, -0.621109, 2.290947, -0.408114, 0.091413, -0.638072, 0.658117, 0.784157, 0.460105, 0.287038, -1.276879, -2.979789, -1.193214, 0.097813, 0.056069, 1.635260, -2.966547, -1.168345, 1.343097, 1.103852, 0.154114, 0.185596, 1.000005, 1.622388, 1.549412, 0.999575, 0.080787, 0.319168, 0.402780, 0.024646, 0.268490, -0.161432, -1.075785, -0.252553, -0.568115, 1.742402, -0.209874, 0.172900, -0.091711}} 28 | Aug = vector.VF32{Key: 8, Vec: []float32{0.753161, 0.824540, 1.304168, 2.072078, 1.649770, 2.204801, 0.061900, -0.897834, 0.388520, 0.233962, 1.541334, 0.022902, -0.063645, 1.726802, 0.089865, -0.431522, 1.120028, -0.292199, 0.603916, 0.422666, 0.228498, 0.768959, -0.468556, -1.409723, 0.776028, -2.439296, -0.874932, 0.517775, -0.040845, 1.359686, 1.269337, 0.210657, -1.854549, -0.527441, -1.459861, -0.994862, -1.186039, -1.005998, -0.620294, -0.261878, 0.673203, 0.911934, 1.080646, 0.545303, -0.380365, -1.437847, 0.141567, 0.118669, -1.229097, -0.366628, 1.224054, -0.336193, 0.205707, -0.642887, -0.888582, -1.270341, -0.282331, -0.001197, -0.467017, -0.150279, -1.139023, 0.094384, 1.610536, -1.294465, -2.224392, -0.555331, -0.613603, -0.399405, -1.554743, 0.325007, 1.288658, 0.644599, -1.687755, -0.402004, 0.650363, -1.121222, -0.118030, 0.607330, -0.166060, -1.053141, 0.573228, 0.959713, 2.305299, -0.304336, -1.746179, 1.477704, -0.199773, -0.120546, -1.255780, 0.121619, 1.123847, -1.296754, -0.810319, 0.805498, -1.665586, 0.589273, -0.055181, -0.686366, -0.177269, -0.282747, -0.229692, 0.366484, 1.268690, 0.368359, -0.465370, 0.346332, 0.571858, 0.276601, 0.150649, -1.063796, -0.397741, 0.099016, 0.558685, -0.791456, 0.408927, -0.365396, 0.285176, -0.783072, 1.700216, 0.370696, -0.323039, -0.258371, 1.248749, 1.040216, -1.034388, 1.618377, 0.141774, 0.003399, 1.674031, -0.192216, -1.147713, 0.413472, 0.002731, 0.496930, 0.398924, 0.053157, -0.080184, 0.588071, -0.331939, 0.400746, 0.570036, -0.268020, -0.874638, -0.459201, -0.717082, 0.375344, -1.525334, -0.503384, -1.763705, 0.955836, -0.836891, 0.046853, -1.052187, -0.898326, -0.150933, 0.902011, 0.459602, 1.285144, 1.609229, -0.836625, -0.590890, -0.883092, -0.726335, 0.114623, -0.342129, 0.967737, -1.751887, 0.041439, 0.451989, 1.396286, 0.705914, 0.699196, 1.532908, 0.899492, -0.987337, 1.262287, -2.676498, -1.196118, -0.583551, 0.764237, 0.261182, -0.126748, 1.200307, 1.946906, 0.021585, -0.288617, 1.059781, -1.008460, 1.296634, -0.518995, -2.120522, -0.898835, -1.029742, -0.066275, -0.755774, 2.049367, 2.528767, 0.860848, -0.411432, -0.622639, 0.031207, 0.233964, -2.434027, -0.166239, -0.030919, -0.731711, 1.645132, 0.600596, -1.020656, 2.436428, 0.272516, -0.268090, -0.627346, 0.626113, 1.594928, 0.054994, 0.851936, 0.870577, -0.087906, -0.058532, 0.368700, -0.307587, 1.430340, 0.116062, -0.133267, 0.217955, -1.985750, 0.669883, -1.227346, -0.556752, 0.696564, -0.664859, -0.238578, 1.932757, 0.151552, -0.836068, 0.034602, -1.885036, -0.349187, 1.138504, -0.575988, -1.745634, -1.777409, -0.155213, 0.139314, 0.455721, 0.345292, -0.550225, 1.452698, -0.871069, 0.462558, 0.497654, 0.836290, -1.037311, -0.820052, -1.786674, -0.334440, 0.602844, 0.006813, 0.291239, 0.104170, -0.346915, -0.929671, 2.141440, -0.379104, -0.103116, -0.618924, 0.428997, 0.338213, 0.652783, 0.094976, -1.224856, -3.121531, -1.245731, -0.183851, -0.054263, 1.656274, -2.550768, -1.282667, 1.047254, 1.602950, -0.282667, 0.384888, 1.045288, 1.153609, 2.293012, 0.793314, 0.097246, -0.058909, 0.970623, -0.221538, 0.600926, 0.167278, -1.591010, -0.743303, -0.695675, 1.459276, -0.075769, 0.463689, 0.086957}} 29 | Sep = vector.VF32{Key: 9, Vec: []float32{0.928828, 0.837040, 1.494655, 2.681417, 2.115978, 1.951111, 0.811192, -0.576957, 0.047925, 0.686825, 1.534467, 0.479443, -0.611337, 1.621165, -0.044489, -0.390630, 1.167143, 0.233869, 0.756626, 0.678049, 0.712545, 0.670204, 0.077535, -1.914908, 0.514728, -1.469982, -0.264834, 0.688077, -0.532407, 1.335688, 0.898673, 0.994597, -1.125107, -0.701077, -0.589751, -1.072882, -0.430592, -0.750903, -0.333456, -0.205002, 1.031544, 1.332222, 0.973973, 0.658240, -0.824605, -1.533349, 0.190492, -0.100541, -0.622735, -0.075542, 1.733947, -0.719851, -0.023264, -0.771274, -0.281773, -0.901194, -0.254762, -0.526011, -1.076057, -0.940354, -1.633062, 0.058363, 1.645818, -1.532136, -1.709380, -0.628678, -1.304713, -0.868311, -1.370906, 0.667785, 0.881815, 0.232492, -1.198115, -0.303544, 1.278983, -1.059054, -0.269035, 0.950929, 0.951481, -0.407579, 0.341318, -0.258480, 2.131851, -0.078623, -1.664012, 1.170218, -0.647416, 0.216287, -1.187374, -0.420741, 0.820358, -0.221835, -0.723672, 1.602623, -1.242218, 0.001962, 0.848574, -0.392820, -0.988233, -0.819622, -0.877391, 0.973384, 0.776615, 0.649838, -1.138333, 0.356401, 0.630388, 0.160110, -0.546868, -2.186409, -0.056376, 0.705200, -0.029237, -0.877553, 0.079693, -0.395057, 0.375491, -0.519743, 1.443392, 0.511987, -0.312232, -0.222846, 0.668404, 1.135347, -0.831466, 0.681260, -0.390885, 0.642171, 1.334537, -0.225753, -0.773329, 0.485188, -0.102809, 0.423262, 1.010884, 0.243330, -0.800906, 0.894710, 0.893149, 0.022595, 0.329711, -0.557091, -0.770679, -0.568306, 0.421875, 0.423297, -1.528339, -0.405066, -1.682354, 0.291759, -1.043337, 0.817629, -0.573269, -0.834006, 0.126450, 1.048152, -0.054269, 1.281308, 1.318511, -0.222915, -1.112334, -0.863887, -1.016916, -0.221830, 0.155246, 0.200044, -1.049691, 0.722300, 0.257256, 1.271650, 0.890705, -0.434520, 2.002707, 0.816326, -1.110410, 1.634459, -3.173790, -1.501410, 0.356377, 1.092579, 0.143152, 0.030132, 2.009844, 0.820081, -0.736724, -0.293086, 0.870851, -1.277399, 1.171440, -0.976975, -1.308255, -1.127723, -0.614424, 0.018842, -0.740485, 1.144098, 1.486515, 1.892945, -1.226476, -0.868051, 0.067352, 0.504634, -2.195112, -0.243133, 0.064533, -0.603542, 0.945932, 0.629471, -0.535324, 1.640998, 0.202090, 0.312343, -0.372759, 1.467969, 1.858152, 0.162911, 1.029802, 1.818347, -0.550815, 0.652485, 0.364559, -0.494514, 1.265764, 0.134262, 0.253554, 0.799490, -1.104792, -0.244356, -1.264832, -0.106380, 1.264250, -0.488088, -0.042922, 2.015291, -0.218569, -0.751328, 0.427565, -2.006389, -0.114421, 0.937808, -0.499052, -1.719308, -1.805919, -0.237758, 1.232163, 0.591246, -0.305329, -0.870205, 2.025639, -1.094558, 0.327749, 0.484629, 0.919910, -1.020168, -0.613019, -1.146455, 0.158565, 1.233643, 0.043145, 0.189507, 0.025602, -0.759581, -0.634543, 2.551889, -0.452547, -0.613135, -0.991353, 0.514999, 0.213134, 0.797381, -0.623999, -1.535793, -2.589316, -0.249431, -0.926386, -0.343984, 1.411382, -2.723860, -0.593055, 1.544543, 1.212761, 0.067222, 0.058338, 1.206506, 1.180401, 1.606814, 0.751550, 0.219015, -0.152110, 0.397568, -1.037159, 0.173795, 0.107895, -2.554391, -0.486694, -0.153280, 0.948083, -0.065067, 0.166050, -0.528983}} 30 | Oct = vector.VF32{Key: 10, Vec: []float32{0.896631, 0.574059, 0.985133, 1.290381, 2.282539, 1.864313, 0.091285, -0.788875, -0.116391, 0.116152, 1.664592, 0.586430, -0.354152, 2.121424, -0.132330, -0.650966, 0.910001, -0.428986, 0.394308, 0.521307, 0.311872, 0.678981, -0.258633, -1.209742, 0.699804, -2.101928, -0.289037, 0.510552, -0.446043, 1.295726, 1.769778, 0.964034, -0.992386, -0.790810, -0.434200, -0.737733, -0.627101, -0.816642, -0.229958, -0.632180, 0.561077, 1.626637, 1.026408, 0.884880, -0.731248, -1.557147, 0.313920, 0.187354, -1.150882, -0.261974, 1.464956, -0.970204, 0.097560, -0.833674, -0.851136, -1.551795, 0.181221, 0.255811, -0.879176, -0.788031, -1.217514, 0.009750, 2.075838, -1.092303, -2.812796, -0.350740, -0.962449, -0.242590, -1.168047, 0.533040, 1.114859, 0.486209, -1.489259, -0.405658, 1.153933, -0.773520, -0.435089, 0.704746, 0.107172, -0.754606, 0.583220, 0.826110, 2.285204, -0.352799, -2.112486, 1.523213, 0.059354, -0.073335, -1.176074, -0.524631, 1.056487, -0.870188, -0.266737, 1.181577, -1.975721, 0.791264, -0.351526, -0.425400, -0.382686, -0.713166, -0.626293, 0.318644, 1.496684, 0.591665, -0.433389, 0.339369, 1.300947, 0.163238, 0.272983, -1.622946, -0.263858, 0.149642, 0.178996, -0.815562, 0.329791, -0.465754, 0.401430, -0.681462, 1.727155, 0.618211, -0.667169, -0.025289, 1.163249, 0.692103, -0.958648, 1.240124, -0.434985, 0.066836, 1.254213, -0.122835, -0.909431, -0.216608, 0.690486, 0.447384, 0.311505, -0.033128, -0.451825, 1.127409, -0.205064, -0.225234, -0.056907, -0.222833, -1.294710, -0.406023, 0.107165, -0.071826, -1.290261, -0.710823, -1.323377, 0.680686, -0.913024, 0.314792, -1.152450, -1.153069, -0.556802, 0.692705, 0.130114, 0.809305, 1.143095, -0.931108, -0.740333, -0.515570, -1.010459, -0.039572, -0.138251, 0.854936, -1.577708, 0.353976, 0.308078, 1.488662, 0.990833, 0.730427, 1.539674, 0.147637, -0.739888, 2.032614, -2.980475, -1.411303, -0.583442, 1.077935, 0.416802, 0.159250, 1.340654, 1.636340, -0.426212, 0.310374, 1.007942, -1.319392, 1.069175, -0.049891, -1.584508, -0.918178, 0.009177, 0.071614, -1.495711, 1.767261, 1.680810, 1.007019, -0.294968, -0.571687, 0.154274, 0.918954, -2.008813, 0.117977, 0.230581, -1.026253, 1.033107, 1.524203, -0.834418, 1.973403, 0.417828, -0.287771, -0.570380, 1.366131, 1.561906, 0.804180, 1.206851, 1.115733, 0.311851, 0.120407, 0.445437, -0.555797, 1.160518, 0.515992, -0.379906, 0.222595, -2.331864, 0.210109, -1.133994, -0.254776, 0.951957, -0.375825, -0.100025, 1.388659, 0.212675, -0.761851, -0.138826, -2.081374, -0.110836, 0.821651, -1.095011, -1.864224, -1.362557, -0.188285, 0.057672, 0.661963, 0.155750, -0.460759, 1.716798, -0.430392, 0.218443, 0.792897, 0.799775, -1.194088, -0.535680, -1.877095, 0.195888, 0.152313, -0.053610, 0.306665, 0.067878, -0.560163, -0.167933, 2.715863, -0.119845, -0.248015, -1.523783, 0.994329, 0.582453, 0.435903, 0.405751, -1.593695, -2.981629, -0.954885, -0.218288, 0.021649, 1.361940, -2.777892, -0.923162, 1.040957, 1.234828, 0.034734, 0.062382, 1.038385, 1.216842, 1.957865, 0.835649, 0.232532, -0.100283, 0.591957, -0.468010, 0.433417, -0.093980, -1.554613, -0.456898, -0.610799, 1.423866, -0.234109, 0.270246, 0.221128}} 31 | Nov = vector.VF32{Key: 11, Vec: []float32{1.552784, 0.234909, 0.833301, 1.432548, 1.887535, 2.054744, 0.009577, -0.764545, 0.092928, 0.158707, 1.540414, 0.542565, -0.456425, 1.775316, -0.268277, -0.496655, 1.081146, -0.293071, 0.173379, 1.234983, 0.618056, 0.565870, -0.420651, -1.585694, 0.706375, -1.561055, -0.032818, 0.364179, -0.239536, 1.138187, 1.764075, 1.434770, -1.394661, -0.733384, -0.533691, -0.326737, -0.478836, -0.888870, 0.408021, -0.652230, 0.638346, 1.384378, 0.907798, 0.710771, -0.340725, -1.375956, 0.280929, -0.001299, -0.997194, -0.447184, 1.794140, -0.712183, -0.047347, -0.480115, -0.743999, -1.847548, 0.038295, 0.141588, -0.822165, -0.662221, -0.965184, 0.258673, 1.744067, -1.268843, -2.251340, -0.897953, -0.966650, -0.143249, -1.454151, 0.170325, 1.690550, 0.577277, -1.303150, -0.045567, 0.715106, -0.906530, -0.806287, 0.228792, -0.498795, -0.592351, 0.635471, 0.810368, 1.576562, -0.341389, -1.859890, 1.501199, -0.014942, 0.067403, -1.733897, -0.312669, 0.921309, -0.659927, -0.427671, 0.762853, -1.997790, 0.965888, -0.079347, -0.383398, -0.523629, -0.422543, -0.237876, 0.455742, 1.495538, 0.057173, -0.607550, 0.285517, 1.112501, -0.145560, -0.170535, -1.223435, -0.592185, -0.254475, 0.083810, -0.795277, 0.616993, -0.868388, 0.339684, -0.616870, 1.807046, 0.072082, -0.123306, 0.233368, 1.292741, 0.248814, -0.618376, 1.701510, -0.220804, 0.011145, 0.747475, -0.005711, -0.514722, -0.779274, 0.386098, 0.331450, 0.787334, 0.380634, -0.047525, 0.697571, -0.232281, -0.377023, 0.073442, 0.148321, -1.638625, -0.257583, 0.299738, -0.049519, -1.440448, -0.398339, -1.377980, 0.362421, -0.777294, 0.581803, -1.140005, -1.073073, -0.284751, 0.448668, -0.151998, 1.018317, 0.923271, -0.894725, -0.934299, -0.384337, -1.005506, -0.565558, -0.304012, 0.502816, -1.587681, -0.008546, -0.644076, 1.438860, 0.495641, 0.284909, 1.479103, 0.383033, -0.568919, 1.665029, -2.874860, -1.379865, -0.573829, 1.364403, 0.460532, -0.121143, 1.590910, 1.576110, 0.101393, 0.376829, 0.492303, -0.890150, 1.388015, 0.169982, -1.854746, -1.304162, -0.294290, 0.345775, -1.396977, 2.023813, 1.378826, 0.603200, -0.309071, -0.470444, 0.524604, 0.974777, -2.427895, -0.108515, 0.687115, -0.634404, 1.220422, 1.629232, -0.770025, 1.615286, 0.649902, 0.030373, -0.871988, 1.164702, 1.135780, 1.181501, 1.591095, 0.530738, 0.442659, 0.212578, 0.900376, -0.535429, 0.845533, -0.053791, -0.183079, 0.279835, -2.319010, -0.002984, -0.483761, -0.251882, 1.105897, -0.064611, -0.095157, 1.230950, 0.611193, -0.835591, 0.313964, -2.636047, 0.788963, 1.018772, -1.421488, -2.183756, -1.638448, -0.371296, 0.078623, 0.492290, 0.718065, -0.604552, 1.837681, -0.519078, 0.042267, 0.919441, 0.702266, -0.565138, -0.818529, -2.038031, -0.535447, 0.630429, -0.152708, 0.260813, 0.379979, -0.882069, -0.212806, 2.905588, 0.167695, -0.069409, -1.904061, 1.074043, 0.024579, 0.224978, 0.058840, -1.313718, -3.115757, -0.936365, -0.517020, 0.193234, 1.492894, -2.852687, -1.092341, 0.787722, 1.646946, -0.197500, 0.167218, 0.737742, 1.284849, 1.587947, 1.105394, 0.910356, 0.268055, 0.795931, -0.304624, 0.076709, -0.686387, -1.330076, -0.270121, -0.984328, 1.175404, -0.468477, 0.157626, 0.361895}} 32 | Dec = vector.VF32{Key: 12, Vec: []float32{0.780196, 0.507232, 1.285944, 1.613457, 2.006964, 1.618672, -0.320557, -1.006814, 0.269186, 0.467003, 1.819223, 0.470314, 0.291860, 2.353535, 0.036314, -0.664950, 0.830636, 0.125940, 0.502603, 1.369000, 0.282775, 0.570218, -0.275454, -1.679255, 0.485021, -2.130311, -0.619342, 0.216399, 0.124624, 0.817926, 1.682879, 0.849968, -1.396515, -0.601343, -0.528688, -0.246170, -0.680244, -0.910868, -0.128067, -0.511704, 0.655172, 1.381803, 0.972187, 0.822452, -0.937808, -1.117587, 0.152204, -0.286311, -0.944773, -0.492900, 1.447301, -1.017788, 0.115949, -0.852749, -0.927450, -1.745919, 0.417203, 0.170444, -0.686900, -0.445477, -1.217932, 0.406253, 1.961226, -1.161149, -2.868615, -0.200919, -1.507313, -0.637126, -1.044585, 0.455027, 1.452780, 0.660915, -1.250904, -0.365666, 1.048643, -1.360480, -0.446252, 0.415591, -0.065971, -0.676923, 0.075766, 0.932323, 2.007266, -0.141931, -1.998020, 1.319749, -0.311776, 0.167114, -1.015875, 0.372929, 1.286436, -0.635351, -0.187219, 0.859761, -1.977351, 0.601494, -0.281689, -0.700927, 0.086068, -0.388189, -0.507568, -0.036216, 1.643847, 0.352389, -0.509759, 0.977365, 1.221249, 0.436237, -0.547496, -1.055669, -0.310327, 0.026958, -0.204649, -1.015648, 0.372257, -0.805511, 0.307590, -0.769139, 1.506868, 0.440100, -0.330835, 0.237396, 2.081768, 0.549478, -0.402428, 1.481248, -0.095721, 0.060710, 1.290213, 0.045674, -1.016840, 0.065289, 0.463198, 0.265798, 0.246669, -0.266639, -0.649158, 0.742964, -0.485351, -0.212885, -0.311347, 0.013151, -0.913932, -0.229842, 0.334864, -0.021666, -1.450850, -0.417973, -1.249468, 0.296236, -0.625463, 0.403324, -0.908980, -1.018191, -0.645521, 0.705993, -0.159875, 1.388947, 1.013585, -1.076968, -1.104561, -0.723339, -1.117930, -0.068116, -0.822497, 0.348899, -1.552619, 0.238379, 0.196021, 1.184427, 0.836768, 0.297414, 1.718771, 0.158100, -0.691557, 1.757581, -3.423676, -1.249274, -0.617900, 0.805008, 0.230652, 0.415942, 1.436905, 1.748475, -0.024358, 0.501911, 0.581794, -1.019697, 1.213504, -0.581038, -1.675553, -0.864398, -0.449698, -0.087892, -1.430753, 1.909566, 1.433445, 1.581034, -0.562044, -0.534114, 0.344430, 0.439409, -2.305215, 0.341785, 0.559323, -0.975828, 1.071002, 1.671933, -1.262723, 2.222085, 0.684303, 0.218922, -0.615871, 1.061166, 1.725094, 0.917358, 1.550171, 1.179185, 0.312174, 0.046493, 0.557141, -0.461427, 1.123044, 0.519660, -0.425013, 0.423071, -2.639513, 0.828577, -1.143704, -0.366518, 0.768534, -0.373582, -0.104605, 1.148778, -0.294748, -0.565945, -0.499653, -2.107118, 0.217813, 0.814243, -1.281752, -1.996123, -1.516509, 0.138119, -0.157314, 0.422229, 0.102897, -0.007165, 1.489775, -0.720845, 0.153490, 0.904458, 0.831421, -0.636072, -0.813685, -2.071020, 0.147369, 0.597215, -0.030640, 0.502881, 0.648433, -0.366105, -0.605905, 2.286685, 0.051297, -0.122451, -1.538121, 0.408203, 0.017917, -0.123368, 0.425323, -0.954065, -2.426932, -1.222303, -0.189528, -0.071001, 1.820854, -2.436119, -0.700276, 1.034907, 1.220073, -0.082425, 0.330473, 0.654583, 1.104870, 1.548900, 0.656931, 0.330621, -0.139214, 0.708975, -0.688021, 0.604314, -0.347526, -1.350699, -0.412788, -0.943952, 1.197654, -0.407878, 0.027994, 0.099575}} 33 | 34 | Months = []vector.VF32{Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec} 35 | 36 | Christmas = vector.VF32{Vec: []float32{-0.209016, 0.434797, -0.155127, 0.086002, 0.598741, -0.139531, -1.909488, 0.293320, -0.214915, 0.368660, -0.366137, -0.742939, -0.304377, 0.504232, -0.383092, 1.525702, -0.278151, -0.315151, 0.537849, 0.577351, 1.640101, 0.303719, -0.297862, -1.766292, -0.273031, 2.487681, 0.428093, 0.846962, 1.109783, -1.038001, 1.125772, 0.490305, -0.670751, -1.085316, 0.210215, -0.012950, 0.765576, 0.682026, -0.449221, 1.086627, -0.091988, -0.520762, 0.466700, 0.066206, -1.276486, 1.010965, 1.410050, -1.199433, 0.134431, -0.833988, 0.523051, -0.544849, -0.427074, -0.674839, -1.656076, -2.304844, 0.148368, 0.044901, 0.981263, 0.548130, -0.714386, -0.178053, 0.501228, -1.007172, -2.010711, -0.668633, -0.189200, 0.058303, 0.028029, 0.447228, 0.421205, 0.878413, -0.442566, 0.926193, 1.101349, -1.427848, 0.817664, 2.049378, 0.070001, -0.536283, -0.342135, 0.240960, 0.662489, 0.856692, -2.591750, 0.733539, 0.708130, 0.219159, -0.340287, 1.293612, 0.614186, 0.716944, -2.141844, 0.349955, 1.489918, 0.413672, -1.304254, -0.343044, -0.262604, 0.773450, 0.133864, 0.148585, -0.225460, -0.165042, -2.301628, 2.334977, 0.718725, -1.423429, -0.629671, 0.742097, -0.914973, 0.384532, 0.747056, 0.222333, -0.182877, -1.394127, 0.253321, -0.677654, 0.573328, 0.741951, 0.127921, 0.863739, 1.419150, -2.036680, 0.443149, 0.063591, 0.227753, -0.356599, 3.065109, -0.805144, -0.935748, -1.541767, 0.645854, 0.294415, 0.565440, 0.163482, -0.431766, 0.783717, 0.516942, -0.028900, 0.970974, 0.445883, -0.033659, -0.241648, 2.833747, 0.691267, -0.480866, -1.910635, 0.626888, -0.119726, -1.125649, -0.526860, -0.924293, 1.114092, -0.273101, -0.453284, -0.463944, -0.124675, 1.809158, -1.152274, -0.865625, 0.107882, 0.561182, -0.142997, 0.412177, -0.473228, -0.145199, 0.688790, -0.705476, -0.782309, 1.488894, 0.678416, 0.679210, -1.718372, -0.954092, -0.078845, -1.620271, 0.188262, -0.627845, 1.965591, -0.564504, 0.485700, -0.088610, 2.921208, 0.773682, 0.360999, -0.309693, 0.507062, 0.428854, -0.092732, -0.724044, -0.715895, -1.927486, -0.643403, -1.155712, 1.190797, -1.263283, 0.449919, 0.961958, 1.330375, 0.250255, 0.035109, -1.866754, -0.706562, 0.433980, -0.487803, 0.273084, 0.174824, -0.744762, 0.233845, -0.982623, -0.677421, 0.320436, 0.860189, 2.460057, -0.541592, -0.775176, 0.006862, 2.043353, -0.908565, 0.157837, 0.943946, -1.202310, 1.261587, 0.529850, -0.599403, -1.254276, 1.402671, 1.812692, -0.332487, 0.200225, -0.596109, 0.223149, 1.208706, -2.031547, -1.705361, 0.050245, 1.254973, -1.061572, -0.722426, -0.166876, 0.911956, -0.841918, -1.001650, -0.210015, 0.254115, -1.625456, -0.978473, -0.390514, -0.250300, -0.726864, -0.324008, 0.493679, 0.309185, -0.251625, -0.300675, -0.511900, 0.573206, 1.090748, -0.331232, 1.039174, -1.055146, 0.726641, 0.093969, -0.079845, -1.410322, -1.724702, 1.485069, 0.156548, -1.247263, 3.002874, -1.187372, -0.971209, -0.224263, -1.558336, -1.254072, 1.743188, -3.432752, 0.324932, 0.131431, -1.505237, 1.079492, 0.660066, -0.367430, 1.459871, -0.549117, 0.015898, -0.562645, -0.913430, -0.713015, 1.796388, 0.755228, 0.868081, -0.659487, 0.057457, 0.388428, 0.174085, -0.368089, -1.254423, 0.016557}} 37 | ) 38 | 39 | func main() { 40 | // Create new HNSW index 41 | index := hnsw.New(vector.SurfaceVF32(surface.Cosine())) 42 | 43 | // Add some data points to the index 44 | for _, vector := range Months { 45 | index.Insert(vector) 46 | } 47 | 48 | // Perform a nearest neighbor search 49 | neighbors := index.Search(Christmas, 4, 100) 50 | 51 | fmt.Print("Nearest Months to Christmas:") 52 | for _, v := range neighbors { 53 | fmt.Printf(" %s", time.Month(v.Key)) 54 | } 55 | fmt.Println() 56 | } 57 | -------------------------------------------------------------------------------- /examples/attributes/main.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2024 Dmitry Kolesnikov 3 | // 4 | // This file may be modified and distributed under the terms 5 | // of the MIT license. See the LICENSE file for details. 6 | // https://github.com/fogfish/hnsw 7 | // 8 | 9 | package main 10 | 11 | import ( 12 | "fmt" 13 | 14 | "github.com/fogfish/hnsw" 15 | "github.com/kshard/vector" 16 | ) 17 | 18 | // The data structure carries vector and attributes 19 | type Embedding struct { 20 | Vec vector.F32 21 | Text string 22 | } 23 | 24 | func (e Embedding) String() string { return e.Text } 25 | 26 | // Declare custom surface distance function 27 | var surface = vector.ContraMap[vector.F32, Embedding]{ 28 | Surface: vector.Cosine(), 29 | ContraMap: func(e Embedding) vector.F32 { return e.Vec }, 30 | } 31 | 32 | var ( 33 | Jan = Embedding{Text: "January", Vec: []float32{1.086148, 0.980377, 1.071345, 1.544523, 2.065881, 2.157415, 0.454303, -1.033736, 0.905185, -0.194171, 1.859588, 0.343453, -0.003968, 1.806738, -0.038112, -0.555388, 0.997678, 0.126616, 1.010657, 0.586423, 0.573646, 0.886638, -0.201437, -1.136351, 0.842182, -1.955736, -0.430720, 0.650387, 0.480141, 0.746583, 1.323336, 0.775509, -1.495530, -0.660015, 0.161144, -0.494570, -0.511690, -1.296281, 0.045897, -0.089638, 0.399675, 1.090670, 0.825883, 0.810098, -1.258456, -1.189124, 0.689887, -0.404152, -1.324289, -0.847084, 1.143412, -1.010808, -0.187708, -0.624147, -1.113180, -1.629236, -0.180108, 0.669056, -0.758205, -0.448864, -0.949295, 0.606799, 2.010494, -1.152272, -2.859973, -0.002375, -1.261795, -0.417256, -1.650129, 0.551458, 1.243721, 0.510421, -1.377052, 0.134479, 1.285836, -1.390088, -0.402196, 0.888515, -0.305741, -1.079884, 0.439349, 0.372619, 1.994654, -0.478902, -1.598553, 1.308691, 0.302009, -0.278768, -1.239261, 0.337863, 1.270028, -1.067799, -0.315578, 0.434161, -1.702327, 0.893069, -0.262683, -0.267134, -0.040754, -0.078352, 0.069745, 0.631980, 1.478813, 0.812454, -0.569294, 0.694728, 1.125386, -0.030749, 0.034099, -1.186033, -0.431279, -0.153683, 0.179714, -0.765746, 0.543388, -0.289645, 0.787614, -1.099530, 1.668221, 0.584822, -0.497755, -0.141708, 1.613281, 0.468616, -0.676649, 1.826349, -0.038224, -0.125984, 0.978238, 0.013257, -0.790858, -0.549507, 0.419847, 0.489768, -0.284288, 0.014772, -0.724216, 0.666071, -0.129178, 0.127392, -0.760378, 0.345167, -1.240361, -0.528636, -0.614882, 0.253457, -1.231061, -1.242486, -1.253776, 0.342700, -0.686833, -0.130610, -0.493314, -0.762326, -0.928763, 0.196312, 0.106338, 1.006737, 0.714737, -0.506298, -1.020424, -0.531522, -1.261684, -0.376761, -0.475821, 0.695053, -1.743665, -0.103578, 0.343031, 0.859036, 0.916840, 0.563349, 1.556920, 0.284126, -0.847237, 1.270618, -2.772213, -1.209474, -0.344699, 0.733655, 0.553019, -0.019791, 1.085788, 1.657075, -0.323854, 0.641069, 1.181185, -1.179225, 1.111938, -0.026360, -1.451540, -0.743103, -0.503777, 0.180287, -1.792218, 2.239577, 1.341525, 1.088364, -0.506837, -1.037046, 0.159791, 0.756301, -2.204125, 0.694692, 0.428386, -0.726236, 1.123547, 1.092102, -1.260130, 1.922151, 0.652946, -0.417734, -0.338227, 0.825723, 1.181619, 0.837869, 1.607801, 1.186520, 0.317319, -0.164176, 0.414272, -0.640842, 1.095129, 0.556614, -0.625260, -0.030710, -2.278642, 0.284396, -1.572590, -0.639729, 0.307321, -0.490756, -0.346488, 1.443267, 0.341902, -0.510708, -0.161124, -2.146504, 0.505791, 1.165881, -1.658561, -2.134284, -1.380689, -0.121205, 0.018432, 0.318355, 0.527610, 0.095948, 1.864381, -1.169070, 0.314526, 1.130626, 0.366122, -1.336751, -0.771868, -1.760797, 0.509088, 0.600089, 0.253928, 0.960579, 0.087707, -0.795826, -0.193189, 2.625580, -0.164605, -0.191895, -1.189766, 0.518188, 0.989566, 0.336568, 0.132944, -1.171439, -2.960803, -1.156261, 0.512935, -0.393506, 1.461197, -2.971865, -0.706429, 1.292507, 1.253855, 0.162427, 0.266442, 0.426753, 1.099721, 1.607205, 0.655825, 0.369450, 0.049228, 0.791865, -0.358443, 0.679537, -0.483806, -0.969876, -0.577250, -0.840348, 1.309811, -0.385929, 0.378577, 0.417275}} 34 | Feb = Embedding{Text: "February", Vec: []float32{0.863843, 0.834412, 0.767967, 1.441759, 1.979645, 2.119818, -0.152409, -0.925577, 0.255454, 0.088092, 1.167256, 0.427990, -0.444017, 1.557952, -0.218379, -0.741931, 1.337525, -0.068751, 0.176268, 0.662023, 0.328259, 0.679177, -0.631597, -1.444511, 1.070807, -2.020582, -0.477180, 0.328347, -0.413543, 1.045343, 2.050766, 0.840585, -1.481687, -1.121763, -0.612197, -0.416140, -0.902469, -0.948633, -0.533500, -0.920458, 0.582824, 1.158915, 1.398063, 0.677171, -0.394278, -1.137193, 0.612642, 0.174038, -0.992636, -0.208506, 1.629065, -0.899818, 0.337043, -1.068766, -1.106952, -1.870604, 0.222933, -0.240857, -0.713956, -0.774561, -1.103365, 0.191678, 1.608780, -1.118621, -2.557125, -0.463295, -0.775955, -0.334767, -1.450772, 0.782128, 0.999984, 0.206194, -1.145143, -0.789347, 0.890442, -0.908306, -0.396356, 0.392883, -0.308325, -0.709919, 0.588891, 0.410281, 2.361948, -0.082487, -2.035475, 1.531478, 0.216232, -0.164408, -1.735564, -0.707018, 1.263637, -0.877970, -0.162191, 1.478629, -1.649958, 0.692522, -0.243004, -0.547843, -0.158000, -0.086265, 0.199225, -0.383671, 1.510256, 0.277312, -0.636759, 0.651880, 1.097998, 0.293551, 0.004639, -1.364130, -0.719183, 0.148478, 0.267185, -0.959793, 0.846114, -0.938919, 0.272693, -0.439031, 1.501335, 0.313972, -0.457307, -0.183739, 1.067966, 0.525256, -1.065531, 1.487073, -0.373041, -0.242663, 1.279020, -0.169860, -0.494803, -0.608964, 0.540460, 0.539295, 0.403507, 0.126699, 0.182753, 0.799895, -0.732601, -0.222616, -0.035708, -0.123696, -1.382190, -0.257442, 0.431286, -0.066622, -1.374102, -0.260221, -1.725099, 0.627368, -0.513460, 0.895435, -0.806397, -0.886610, -0.536780, 0.325561, -0.017678, 1.286493, 0.943032, -1.030374, -1.116311, -0.478834, -0.990620, 0.237227, -0.036306, 0.973816, -1.690858, -0.270290, 0.164928, 1.194907, 0.690722, 0.510960, 1.540581, 0.335098, -0.952401, 1.367250, -2.734142, -1.664903, -0.362587, 1.052118, 0.170769, 0.141752, 1.210011, 1.913445, -0.357750, 0.397618, 0.964370, -1.106375, 0.706907, 0.058149, -1.775667, -0.807866, -0.280380, 0.080289, -0.775017, 1.781382, 1.523313, 0.698079, -0.585351, -0.965756, 0.343741, 0.900078, -1.975462, -0.037753, 0.401768, -0.897169, 1.187217, 1.701761, -1.036627, 2.078473, 0.692022, -0.629359, -1.073511, 0.982222, 1.199937, 0.968442, 1.253772, 0.495507, 0.195453, 0.273791, 0.815910, -0.786922, 1.306433, 0.446073, -0.925321, 0.248089, -2.528068, 0.778926, -1.418931, -0.317748, 0.825230, -0.863813, -0.171744, 1.200187, 0.077496, -1.073315, -0.040422, -1.715621, 0.207671, 0.957527, -1.070138, -2.079015, -1.899029, 0.049671, 0.379471, 0.227733, 0.170514, -0.435170, 1.915718, -0.789699, 0.135722, 0.606490, 0.779467, -0.480242, -0.659674, -1.651008, -0.138721, 0.452251, -0.258198, 0.434695, 0.041625, -0.273274, -0.505310, 2.912049, 0.039981, 0.165387, -1.747939, 0.885967, 0.980371, 0.465048, 0.130152, -1.256838, -2.564538, -1.352994, -0.206697, 0.322895, 1.760243, -2.333582, -0.657256, 1.296127, 1.355597, -0.390070, 0.800925, 0.928465, 0.629793, 1.864801, 1.271766, 0.323438, 0.495335, 0.940038, -0.287337, 0.724428, -0.420535, -1.393595, -0.088316, -0.802756, 1.671690, -0.305128, 0.313227, 0.451491}} 35 | Mar = Embedding{Text: "March", Vec: []float32{1.320395, 0.848528, 0.704421, 1.423122, 1.925830, 2.264947, 0.305817, -0.344170, -0.304653, 0.339275, 0.861341, 0.598434, 0.115942, 1.893419, 0.347116, -0.410508, 0.858695, -0.465234, 0.176406, 1.361156, -0.032105, 0.293770, -0.142674, -1.738622, 0.895677, -1.726089, -0.160320, 0.433331, -0.327188, 0.935088, 2.005640, 1.222845, -1.913726, -1.382722, -0.254853, -1.293203, -1.042308, -1.040702, -0.195514, -1.064200, 0.502490, 1.005676, 1.314858, 1.063727, 0.240671, -0.951861, 0.856411, 0.470810, -0.722048, -0.388575, 1.428116, -0.622312, 0.402563, -0.164345, -1.160401, -1.600752, 0.745722, 0.257587, -0.128991, -0.236142, -1.111861, -0.208283, 1.675631, -1.609689, -2.225040, -0.685392, -0.888058, -1.039457, -1.315974, 0.983658, 0.803106, 0.656526, -1.320289, -0.269896, 0.285642, -1.289004, -0.367522, 0.482059, 0.050950, -1.096899, 0.410171, 0.668005, 1.910987, -0.232351, -1.389734, 1.749195, 0.773647, -0.148164, -1.663736, -0.939839, 0.670158, -0.591140, -0.429618, 1.421001, -2.018159, 0.829756, -0.258516, -0.751333, -0.626013, -0.455041, -0.407524, -0.200833, 1.848797, 0.230392, -0.313479, 0.420008, 0.554813, 0.254758, -0.094077, -1.255889, -0.048290, 0.537468, -0.072036, -0.613983, 0.728068, -0.662861, 0.166225, -0.310689, 2.186502, 0.669082, -0.504409, 0.011212, 1.512129, 1.110640, -1.142577, 1.384355, -0.188313, -0.100203, 1.205011, -0.251342, -0.911722, -0.540738, 0.228294, 0.709907, 1.013594, 0.324900, -0.146337, 0.644103, -0.083229, -0.244335, 0.093592, 0.027596, -1.271179, -0.858105, 0.302756, -0.192842, -1.582592, -0.331267, -1.953504, 0.135636, -0.459141, 0.521030, -1.074115, -0.450643, -0.623794, 0.521083, -0.290532, 1.240419, 0.921032, -0.738373, -0.785081, -0.413102, -1.202347, 0.085647, 0.272996, 0.910936, -1.353536, -0.017207, -0.067627, 1.014471, 0.486180, 0.554923, 1.524420, 0.363201, -1.007632, 1.320969, -2.914411, -1.882532, -0.560343, 0.704276, 0.318686, -0.490492, 1.540093, 1.578905, -0.615803, 0.537423, 1.132374, -0.831606, 0.743541, 0.225530, -1.312965, -1.252651, -0.204747, 0.355962, -0.976505, 1.897576, 1.835031, 1.506927, -0.286618, -0.597685, 0.952475, 0.175615, -1.904108, -0.260357, 0.506206, -0.953668, 1.646633, 1.611063, -0.812283, 1.827847, 0.306678, -0.253673, -0.305113, 0.529505, 1.492202, 0.640940, 1.655517, 0.022800, -0.269071, 0.087833, 0.727152, -0.480812, 0.898927, 0.026657, -0.453094, 0.272977, -2.313351, 0.464524, -1.148658, -0.504678, 0.858572, -0.665205, 0.290333, 1.136463, -0.013706, -0.833448, -0.319156, -1.832496, 0.613189, 0.853094, -1.631312, -2.263570, -1.204134, -0.188827, 0.123913, 0.179924, 0.208717, -0.805608, 1.837492, -0.642940, 0.136217, 0.860895, 0.761989, -0.720712, -0.653274, -1.607307, 0.091833, 0.880150, -0.096851, 0.485980, -0.272285, -0.842101, -0.296788, 2.926239, -0.061680, 0.041489, -1.925525, 0.927647, 1.284915, 0.451289, 0.415674, -1.663582, -2.689622, -1.277330, -0.033117, 0.293511, 1.283250, -2.251521, -0.937326, 1.563402, 0.311000, -0.875986, 0.216013, 1.125768, 0.752567, 1.498770, 0.915869, 0.662268, 0.392064, 0.873420, -0.596787, 0.429586, -0.283244, -1.467683, -0.234297, -0.647331, 1.275938, -0.232804, 0.597012, -0.022341}} 36 | Apr = Embedding{Text: "Apr", Vec: []float32{0.889234, 0.850274, 0.874889, 1.704348, 2.418694, 2.017295, 0.245924, -1.062022, 0.169842, 0.085362, 1.448353, 0.617088, -0.337177, 1.500970, -0.004566, -0.682291, 0.963418, -0.429490, 0.538826, 1.106818, 0.688008, 0.494462, -0.383412, -1.503660, 0.810763, -2.079937, -0.531183, 0.555345, -0.101067, 0.910118, 1.478240, 1.080644, -1.873836, -1.095774, -0.591963, -0.966131, -1.157680, -0.799843, 0.015950, -0.626820, 0.399315, 1.004897, 1.315348, 0.549850, 0.193941, -0.851153, 0.863186, 0.152940, -1.182206, -0.338813, 1.539671, -0.758084, 0.274242, -0.536658, -0.933949, -1.430804, 0.371569, 0.165304, -0.694454, -0.579532, -1.221094, -0.285913, 1.995314, -1.161382, -2.176816, -0.605719, -0.915929, -0.636219, -1.172193, 0.658554, 0.980474, 0.384841, -1.213187, -0.308638, 0.534761, -0.891433, -0.403050, 0.341551, -0.010667, -1.011724, 0.358064, 0.288373, 2.231461, -0.277990, -1.553067, 1.279105, 0.243052, -0.221418, -1.608192, -0.579980, 1.027069, -0.597810, -0.034130, 1.090712, -1.826084, 0.784525, 0.129640, -0.505121, -0.493802, -0.074793, -0.778566, -0.565970, 2.076428, 0.325651, -0.437679, 0.604429, 0.963960, 0.283912, 0.144850, -1.434682, -0.418146, 0.422626, 0.589343, -0.713689, 0.482611, -0.851913, 0.337479, -0.192025, 2.114732, 0.247890, -0.656879, -0.227433, 1.170673, 0.823480, -0.991431, 1.396380, -0.365972, -0.302597, 1.138377, -0.262685, -0.764862, -0.101200, 0.718027, 0.713953, 0.800762, 0.303217, -0.151558, 0.747138, -0.452142, -0.322497, -0.013809, -0.376913, -1.622386, -0.340648, 0.108092, 0.305132, -1.126016, -0.405195, -2.029316, 0.633802, -0.822035, 0.704594, -0.689308, -1.178872, -0.263945, -0.073298, -0.245987, 1.380323, 0.841403, -0.884681, -0.604581, -0.602082, -0.917923, -0.181644, -0.150408, 1.000710, -1.588809, 0.310616, 0.306349, 1.343197, 0.742409, 0.853787, 1.642857, 0.421971, -0.983606, 1.094037, -2.920673, -1.610627, -0.471835, 0.987661, 0.484488, -0.651407, 1.478175, 2.003170, -0.057947, 0.417251, 0.747966, -1.140194, 1.126976, 0.274967, -1.849598, -1.111743, -0.302162, 0.063235, -1.156401, 1.353594, 1.555844, 1.193506, -0.003208, -0.656334, 0.303128, 0.551664, -1.608392, -0.181028, 0.323090, -0.732299, 1.370045, 1.542002, -0.919291, 1.992092, 0.535234, 0.266810, -0.483004, 1.113044, 1.368998, 0.917721, 1.431987, 0.374176, -0.155113, 0.142180, 1.051985, -0.287175, 1.022032, 0.055056, -0.351141, 0.162697, -2.204322, 0.789971, -1.367697, -0.080956, 0.689354, -0.361272, -0.476382, 1.218314, 0.041879, -0.989796, -0.151225, -2.223488, 0.261868, 1.172489, -1.223110, -2.278040, -1.780869, -0.159160, 0.143638, 0.324550, 0.691479, -0.523870, 1.657111, -1.066579, 0.167808, 0.715926, 1.417295, -0.758445, -0.449851, -1.755778, -0.044620, 0.090462, -0.262309, 0.076480, 0.039296, -0.546645, -0.263545, 2.779835, -0.055745, -0.084523, -1.447093, 1.085526, 0.835604, 0.578110, 0.086655, -1.700222, -2.737127, -1.239529, -0.609708, 0.419031, 1.619995, -2.368754, -0.596594, 1.428266, 1.313068, -0.741654, 0.290380, 1.010022, 0.695741, 1.646288, 0.821885, 0.087528, 0.030776, 1.013950, 0.069064, 0.744366, -0.199043, -1.480556, -0.249497, -1.006421, 1.721708, -0.533348, 0.373670, 0.658661}} 37 | May = Embedding{Text: "May", Vec: []float32{-0.37604, 0.24116, -0.26098, -0.0079604, 0.2198, 0.098515, 0.23458, 0.13797, 0.11026, -1.7503, 0.15728, 0.50099, -0.070068, 0.023731, 0.39848, 0.34406, 0.2725, -0.31173, -0.083764, -0.22098, -0.27032, -0.061412, 0.23487, -0.10898, -0.50068, -0.19188, -0.081558, -0.49529, -0.11206, 0.055647, 0.34762, 0.38117, 0.25134, 0.22155, -0.60474, 0.14916, 0.034044, 0.080041, -0.025968, -0.024241, -0.25607, 0.15805, 0.059879, 0.35204, -0.33104, -0.21203, -0.11276, 0.21901, -0.42762, -0.073376, 0.2087, -0.19191, 0.10252, 0.13545, 0.034747, 0.2744, -0.14779, 0.031078, 0.25385, 0.31864, 0.28914, 0.076552, 0.38445, 0.13276, -0.023181, -0.80946, 0.21977, 0.38286, -0.0099079, 0.1311, 0.033017, 0.062568, 0.1304, -0.055305, -0.43903, -0.071552, 0.24424, 0.029362, -0.09076, -0.091094, 0.19034, -0.28601, -0.092019, -0.018266, -0.046318, -0.22229, -0.0035013, 0.37954, 0.042987, 0.24319, -0.61973, 0.17455, -0.010297, -0.19769, -0.028611, 0.25263, -0.42774, 0.18326, 0.042894, -0.45469, 0.024955, -0.19844, -0.22603, 0.5447, -0.078387, -0.19611, -0.036302, -0.35798, 0.098273, 0.35702, 0.033349, -0.041258, -0.088868, -0.37277, 0.16962, -0.0018967, -0.11081, 0.11871, 0.32646, -0.54318, -0.0060212, -0.42852, 0.11824, 0.13754, 0.15223, 0.013127, 0.29583, -0.17568, 0.32801, -0.34822, -0.39004, 0.53055, 0.27993, 0.34217, 0.10086, -0.1984, -0.23966, -0.088367, -0.2531, -0.085551, -0.31834, -0.0095886, -0.14605, 0.20637, -0.21729, -0.10325, -0.12783, 0.30865, -0.46587, 0.28135, 0.077259, 0.024987, 0.07764, -0.1971, 0.10445, -0.017228, -0.045139, -0.047205, -0.19365, 0.12006, -0.11591, -0.064879, -0.13913, 0.13766, 0.16368, 0.47388, -0.003217, -0.15248, 0.16059, 0.42005, 0.37255, 0.45046, -0.39264, 0.2167, -0.24217, -0.27105, 0.21422, 0.37381, -0.28921, 0.67957, -0.09934, 0.14129, 0.13669, 0.18308, -0.04637, 0.18081, -0.20207, 0.11194, 0.40635, 0.041006, -0.26205, 0.24239, 0.10954, -0.0025109, -0.31055, -0.39472, 0.46873, -0.26605, 0.0003155, -0.2781, 0.77845, -0.081538, -0.17148, 0.17038, -0.032289, 0.36118, 0.07083, 0.31458, -0.50364, -0.41388, 0.19972, -0.34238, 0.37245, -0.049874, -0.039695, 0.11291, 0.44979, 0.29775, -0.14373, -0.11168, 0.0086446, -0.14489, -0.2899, -0.19745, -0.085559, -0.29691, 0.2741, -0.071754, 0.23885, -0.17967, 0.045782, 0.19417, 0.0017401, -0.36253, -0.047268, 0.60928, 0.14532, -0.015873, -0.15849, -0.3826, -0.11274, -0.37488, 0.76094, -0.11912, -0.77917, 0.20749, 0.29988, -0.56498, 0.017913, -0.13273, 0.15938, -0.23032, -0.27924, 0.15282, -0.049281, 0.047475, 0.17481, -0.15886, 0.28165, 0.053054, 0.005466, -0.51198, -0.080661, 0.069866, -0.16794, -0.51912, 0.15684, -0.00071678, 0.10139, 0.16274, 0.18913, 0.15799, 0.55748, -0.051792, -0.14222, 0.084011, -1.8705, -0.2938, 0.42032, 0.0918, -0.26313, 0.12525, 0.44998, 0.36353, -0.19611, 0.1276, -0.3045, -0.061133, -0.027884, -0.011002, -0.083795, -0.1581, 0.32567, -0.4293, 0.11057, 0.3123, -0.25579, -0.75731, 0.097391, -0.08183}} 38 | Jun = Embedding{Text: "June", Vec: []float32{1.036540, 0.546969, 0.682225, 1.619027, 1.857694, 2.280705, 0.462707, -0.603202, 0.049518, 0.109536, 1.745253, 0.255977, -0.168170, 1.558392, 0.263142, -0.660832, 1.116244, 0.067872, 0.991019, 1.099545, 0.657584, 0.727799, -0.601647, -1.598989, 0.926662, -2.260845, -0.467635, 0.081023, 0.076706, 1.344466, 1.706524, 0.649527, -1.679096, -0.730862, -0.823532, -0.948478, -0.873514, -0.903392, -0.295259, -0.347673, 0.665391, 0.990738, 1.212980, 0.514580, -0.423756, -1.452311, 0.860289, 0.188581, -1.175361, -0.381487, 1.072647, -0.472692, 0.144981, -0.734162, -1.110243, -1.159058, 0.141118, 0.206652, -0.094864, -0.821367, -1.403696, -0.203194, 2.041277, -1.152582, -2.370972, -0.278623, -0.745128, -0.775113, -1.730716, 0.460334, 1.322744, 0.417837, -1.187664, -0.558460, 0.522802, -0.653232, -0.203764, 0.044597, 0.297716, -0.533234, 0.314883, 0.686437, 2.363522, -0.259957, -1.985401, 1.517309, 0.211923, 0.265879, -1.440608, -0.279308, 0.411235, -1.365269, -0.432263, 1.014367, -1.935541, 0.552363, 0.266799, -0.571557, -0.579142, -0.356888, -0.056538, 0.324536, 1.739126, 0.356806, -0.504803, 0.513064, 1.383744, 0.332912, 0.109297, -0.942169, -0.307139, 0.411564, 0.330522, -0.571179, 0.524751, -0.630205, 0.458416, -0.317862, 1.983600, 0.615994, -0.835104, -0.086852, 1.388516, 1.048700, -0.812822, 1.597238, -0.038695, -0.098320, 1.369465, -0.064687, -0.527911, -0.192985, 0.804706, 0.689003, 0.839296, 0.066297, -0.480740, 0.719132, -0.212911, -0.145413, 0.105600, -0.121319, -1.286524, -0.640703, -0.168864, 0.399286, -1.231946, -0.807043, -1.756248, 0.757814, -0.752825, 1.132907, -1.080017, -0.985473, -0.647810, 0.494041, -0.125647, 1.396656, 0.790061, -0.918778, -0.408365, -1.017052, -1.058472, -0.124559, -0.385773, 1.317527, -1.575095, 0.095171, 0.503692, 1.703586, 0.970864, 1.057869, 1.409394, 0.157485, -0.602411, 1.240161, -2.978426, -0.969381, -0.701221, 0.673723, 0.416678, -0.068766, 1.001517, 1.833978, -0.216807, 0.196628, 0.724457, -1.236636, 0.885444, -0.434618, -1.785954, -1.295137, -0.400275, -0.308485, -1.099225, 1.876500, 1.893056, 0.545735, -0.235084, -0.550314, -0.263440, 0.271569, -2.003980, -0.032058, 0.254051, -0.775235, 1.594377, 1.282338, -1.187373, 2.106279, 0.737230, 0.228264, -0.220703, 0.863467, 1.790426, 0.451643, 1.365718, 0.778219, 0.141991, 1.077456, 0.664807, -0.224345, 1.252004, 0.096293, -0.078906, -0.114109, -2.167131, 0.897457, -1.215864, -0.349698, 0.681056, -0.551970, -0.077094, 1.598078, -0.002608, -0.864052, 0.237962, -2.055780, 0.011823, 1.136935, -0.930098, -1.998164, -1.990586, 0.368082, -0.181903, 0.217795, 0.206548, -0.506491, 1.418166, -0.611350, -0.100018, 0.672583, 1.191272, -1.341299, -0.425044, -1.982306, -0.530068, 0.273478, -0.130283, 0.184311, 0.157988, -0.678781, -0.712540, 2.272594, -0.287060, -0.070493, -1.264626, 1.160303, 0.268237, 0.705274, 0.164905, -1.435192, -2.699068, -1.290640, -0.104979, 0.440403, 1.669127, -2.691568, -0.961174, 0.878749, 1.159540, -0.259053, 0.465110, 0.588688, 1.312046, 1.777309, 0.956853, 0.597408, 0.007668, 0.271935, -0.179231, 0.646022, 0.001665, -1.172982, -0.083007, -0.956250, 1.261846, -0.072911, 0.393786, 0.245709}} 39 | Jul = Embedding{Text: "July", Vec: []float32{1.138271, 0.790593, 0.988634, 1.729306, 1.886875, 1.967648, -0.157556, -0.876982, 0.450545, 0.026977, 1.577323, 0.353218, -0.495040, 1.906863, 0.091444, -0.368458, 1.129238, -0.368361, 1.199798, 0.804840, 0.648151, 0.828091, -0.293887, -1.455547, 0.867944, -1.967912, -0.535779, 0.392205, -0.476648, 0.933586, 1.048640, 0.954908, -1.641251, -0.244135, -0.571074, -0.841517, -1.259406, -1.615447, -0.420757, -0.115084, 0.384331, 1.116191, 1.045647, 0.755925, -0.405124, -1.524020, 0.991367, -0.148226, -0.989243, -0.208606, 0.842985, -0.779207, 0.019453, -0.962132, -1.080064, -1.037277, -0.146641, 0.053057, -0.342300, -0.230606, -1.191770, 0.190107, 2.168518, -1.058119, -2.513550, -0.326502, -0.868132, -0.666673, -1.928643, 0.640266, 1.536754, 0.274456, -1.284815, -0.570932, 0.788092, -1.285053, -0.286308, 0.213928, 0.217690, -0.903204, 0.044244, 0.685908, 2.514129, -0.425186, -1.951683, 1.164671, 0.478086, 0.078633, -1.415431, -0.583380, 1.491450, -0.855399, -0.014535, 0.702505, -1.685143, 0.289857, 0.137451, -0.654170, -0.253289, -0.062705, -0.028650, 0.295153, 1.522754, 0.272928, -0.559312, 0.462845, 1.036449, 0.200446, 0.192529, -0.951793, -0.495174, -0.077213, 1.032960, -0.678964, 0.575119, -0.446675, 0.423770, -0.372890, 1.694313, 0.717929, -0.668641, 0.304761, 1.576035, 0.576164, -0.523488, 1.611880, -0.199664, -0.171586, 1.114140, -0.288768, -1.136209, 0.166317, 0.334959, 0.261725, 0.684927, 0.076527, -0.657697, 0.774720, -0.369026, 0.106780, 0.054052, -0.149635, -1.237101, -0.525032, 0.093665, 0.169911, -0.946435, -0.722021, -1.640050, 0.441190, -1.441454, 0.604225, -0.888969, -0.881575, -0.607427, 0.870209, -0.002016, 1.254662, 1.209216, -0.678927, -0.686509, -1.462612, -1.240944, 0.050033, -0.333461, 1.071059, -1.559879, 0.148454, 0.436936, 1.544271, 0.509421, 0.891890, 1.934450, 0.971477, -0.698805, 0.932790, -2.929860, -1.270368, -0.707287, 0.608710, 0.285007, -0.083925, 1.259068, 1.975407, -0.325491, 0.192746, 0.493369, -1.233861, 0.841210, -0.557954, -1.987419, -1.026524, -0.653557, -0.074514, -0.894527, 1.537106, 1.918728, 0.769538, -0.270091, -0.841949, -0.465037, 0.580329, -2.068741, -0.122669, 0.292804, -0.909491, 1.304980, 1.399283, -0.925365, 2.073050, 0.545720, 0.550380, -0.592549, 0.969717, 1.543133, 0.304340, 1.027979, 1.123738, -0.003943, 0.215501, 0.383079, -0.651258, 1.309091, 0.452836, 0.075356, -0.050422, -1.958724, 0.922330, -1.139794, -0.519272, 0.848986, -0.566963, -0.296832, 1.579726, 0.408311, -0.725003, 0.131820, -2.195414, -0.194259, 1.763461, -0.759866, -1.789942, -1.495166, 0.100403, -0.092975, 0.380394, 0.122669, -0.149844, 1.512750, -0.840042, -0.254883, 0.827037, 1.022277, -1.370214, -0.899545, -1.927375, -0.410887, 0.253221, 0.245714, 0.246460, 0.152955, -0.499900, -0.621109, 2.290947, -0.408114, 0.091413, -0.638072, 0.658117, 0.784157, 0.460105, 0.287038, -1.276879, -2.979789, -1.193214, 0.097813, 0.056069, 1.635260, -2.966547, -1.168345, 1.343097, 1.103852, 0.154114, 0.185596, 1.000005, 1.622388, 1.549412, 0.999575, 0.080787, 0.319168, 0.402780, 0.024646, 0.268490, -0.161432, -1.075785, -0.252553, -0.568115, 1.742402, -0.209874, 0.172900, -0.091711}} 40 | Aug = Embedding{Text: "August", Vec: []float32{0.753161, 0.824540, 1.304168, 2.072078, 1.649770, 2.204801, 0.061900, -0.897834, 0.388520, 0.233962, 1.541334, 0.022902, -0.063645, 1.726802, 0.089865, -0.431522, 1.120028, -0.292199, 0.603916, 0.422666, 0.228498, 0.768959, -0.468556, -1.409723, 0.776028, -2.439296, -0.874932, 0.517775, -0.040845, 1.359686, 1.269337, 0.210657, -1.854549, -0.527441, -1.459861, -0.994862, -1.186039, -1.005998, -0.620294, -0.261878, 0.673203, 0.911934, 1.080646, 0.545303, -0.380365, -1.437847, 0.141567, 0.118669, -1.229097, -0.366628, 1.224054, -0.336193, 0.205707, -0.642887, -0.888582, -1.270341, -0.282331, -0.001197, -0.467017, -0.150279, -1.139023, 0.094384, 1.610536, -1.294465, -2.224392, -0.555331, -0.613603, -0.399405, -1.554743, 0.325007, 1.288658, 0.644599, -1.687755, -0.402004, 0.650363, -1.121222, -0.118030, 0.607330, -0.166060, -1.053141, 0.573228, 0.959713, 2.305299, -0.304336, -1.746179, 1.477704, -0.199773, -0.120546, -1.255780, 0.121619, 1.123847, -1.296754, -0.810319, 0.805498, -1.665586, 0.589273, -0.055181, -0.686366, -0.177269, -0.282747, -0.229692, 0.366484, 1.268690, 0.368359, -0.465370, 0.346332, 0.571858, 0.276601, 0.150649, -1.063796, -0.397741, 0.099016, 0.558685, -0.791456, 0.408927, -0.365396, 0.285176, -0.783072, 1.700216, 0.370696, -0.323039, -0.258371, 1.248749, 1.040216, -1.034388, 1.618377, 0.141774, 0.003399, 1.674031, -0.192216, -1.147713, 0.413472, 0.002731, 0.496930, 0.398924, 0.053157, -0.080184, 0.588071, -0.331939, 0.400746, 0.570036, -0.268020, -0.874638, -0.459201, -0.717082, 0.375344, -1.525334, -0.503384, -1.763705, 0.955836, -0.836891, 0.046853, -1.052187, -0.898326, -0.150933, 0.902011, 0.459602, 1.285144, 1.609229, -0.836625, -0.590890, -0.883092, -0.726335, 0.114623, -0.342129, 0.967737, -1.751887, 0.041439, 0.451989, 1.396286, 0.705914, 0.699196, 1.532908, 0.899492, -0.987337, 1.262287, -2.676498, -1.196118, -0.583551, 0.764237, 0.261182, -0.126748, 1.200307, 1.946906, 0.021585, -0.288617, 1.059781, -1.008460, 1.296634, -0.518995, -2.120522, -0.898835, -1.029742, -0.066275, -0.755774, 2.049367, 2.528767, 0.860848, -0.411432, -0.622639, 0.031207, 0.233964, -2.434027, -0.166239, -0.030919, -0.731711, 1.645132, 0.600596, -1.020656, 2.436428, 0.272516, -0.268090, -0.627346, 0.626113, 1.594928, 0.054994, 0.851936, 0.870577, -0.087906, -0.058532, 0.368700, -0.307587, 1.430340, 0.116062, -0.133267, 0.217955, -1.985750, 0.669883, -1.227346, -0.556752, 0.696564, -0.664859, -0.238578, 1.932757, 0.151552, -0.836068, 0.034602, -1.885036, -0.349187, 1.138504, -0.575988, -1.745634, -1.777409, -0.155213, 0.139314, 0.455721, 0.345292, -0.550225, 1.452698, -0.871069, 0.462558, 0.497654, 0.836290, -1.037311, -0.820052, -1.786674, -0.334440, 0.602844, 0.006813, 0.291239, 0.104170, -0.346915, -0.929671, 2.141440, -0.379104, -0.103116, -0.618924, 0.428997, 0.338213, 0.652783, 0.094976, -1.224856, -3.121531, -1.245731, -0.183851, -0.054263, 1.656274, -2.550768, -1.282667, 1.047254, 1.602950, -0.282667, 0.384888, 1.045288, 1.153609, 2.293012, 0.793314, 0.097246, -0.058909, 0.970623, -0.221538, 0.600926, 0.167278, -1.591010, -0.743303, -0.695675, 1.459276, -0.075769, 0.463689, 0.086957}} 41 | Sep = Embedding{Text: "September", Vec: []float32{0.928828, 0.837040, 1.494655, 2.681417, 2.115978, 1.951111, 0.811192, -0.576957, 0.047925, 0.686825, 1.534467, 0.479443, -0.611337, 1.621165, -0.044489, -0.390630, 1.167143, 0.233869, 0.756626, 0.678049, 0.712545, 0.670204, 0.077535, -1.914908, 0.514728, -1.469982, -0.264834, 0.688077, -0.532407, 1.335688, 0.898673, 0.994597, -1.125107, -0.701077, -0.589751, -1.072882, -0.430592, -0.750903, -0.333456, -0.205002, 1.031544, 1.332222, 0.973973, 0.658240, -0.824605, -1.533349, 0.190492, -0.100541, -0.622735, -0.075542, 1.733947, -0.719851, -0.023264, -0.771274, -0.281773, -0.901194, -0.254762, -0.526011, -1.076057, -0.940354, -1.633062, 0.058363, 1.645818, -1.532136, -1.709380, -0.628678, -1.304713, -0.868311, -1.370906, 0.667785, 0.881815, 0.232492, -1.198115, -0.303544, 1.278983, -1.059054, -0.269035, 0.950929, 0.951481, -0.407579, 0.341318, -0.258480, 2.131851, -0.078623, -1.664012, 1.170218, -0.647416, 0.216287, -1.187374, -0.420741, 0.820358, -0.221835, -0.723672, 1.602623, -1.242218, 0.001962, 0.848574, -0.392820, -0.988233, -0.819622, -0.877391, 0.973384, 0.776615, 0.649838, -1.138333, 0.356401, 0.630388, 0.160110, -0.546868, -2.186409, -0.056376, 0.705200, -0.029237, -0.877553, 0.079693, -0.395057, 0.375491, -0.519743, 1.443392, 0.511987, -0.312232, -0.222846, 0.668404, 1.135347, -0.831466, 0.681260, -0.390885, 0.642171, 1.334537, -0.225753, -0.773329, 0.485188, -0.102809, 0.423262, 1.010884, 0.243330, -0.800906, 0.894710, 0.893149, 0.022595, 0.329711, -0.557091, -0.770679, -0.568306, 0.421875, 0.423297, -1.528339, -0.405066, -1.682354, 0.291759, -1.043337, 0.817629, -0.573269, -0.834006, 0.126450, 1.048152, -0.054269, 1.281308, 1.318511, -0.222915, -1.112334, -0.863887, -1.016916, -0.221830, 0.155246, 0.200044, -1.049691, 0.722300, 0.257256, 1.271650, 0.890705, -0.434520, 2.002707, 0.816326, -1.110410, 1.634459, -3.173790, -1.501410, 0.356377, 1.092579, 0.143152, 0.030132, 2.009844, 0.820081, -0.736724, -0.293086, 0.870851, -1.277399, 1.171440, -0.976975, -1.308255, -1.127723, -0.614424, 0.018842, -0.740485, 1.144098, 1.486515, 1.892945, -1.226476, -0.868051, 0.067352, 0.504634, -2.195112, -0.243133, 0.064533, -0.603542, 0.945932, 0.629471, -0.535324, 1.640998, 0.202090, 0.312343, -0.372759, 1.467969, 1.858152, 0.162911, 1.029802, 1.818347, -0.550815, 0.652485, 0.364559, -0.494514, 1.265764, 0.134262, 0.253554, 0.799490, -1.104792, -0.244356, -1.264832, -0.106380, 1.264250, -0.488088, -0.042922, 2.015291, -0.218569, -0.751328, 0.427565, -2.006389, -0.114421, 0.937808, -0.499052, -1.719308, -1.805919, -0.237758, 1.232163, 0.591246, -0.305329, -0.870205, 2.025639, -1.094558, 0.327749, 0.484629, 0.919910, -1.020168, -0.613019, -1.146455, 0.158565, 1.233643, 0.043145, 0.189507, 0.025602, -0.759581, -0.634543, 2.551889, -0.452547, -0.613135, -0.991353, 0.514999, 0.213134, 0.797381, -0.623999, -1.535793, -2.589316, -0.249431, -0.926386, -0.343984, 1.411382, -2.723860, -0.593055, 1.544543, 1.212761, 0.067222, 0.058338, 1.206506, 1.180401, 1.606814, 0.751550, 0.219015, -0.152110, 0.397568, -1.037159, 0.173795, 0.107895, -2.554391, -0.486694, -0.153280, 0.948083, -0.065067, 0.166050, -0.528983}} 42 | Oct = Embedding{Text: "October", Vec: []float32{0.896631, 0.574059, 0.985133, 1.290381, 2.282539, 1.864313, 0.091285, -0.788875, -0.116391, 0.116152, 1.664592, 0.586430, -0.354152, 2.121424, -0.132330, -0.650966, 0.910001, -0.428986, 0.394308, 0.521307, 0.311872, 0.678981, -0.258633, -1.209742, 0.699804, -2.101928, -0.289037, 0.510552, -0.446043, 1.295726, 1.769778, 0.964034, -0.992386, -0.790810, -0.434200, -0.737733, -0.627101, -0.816642, -0.229958, -0.632180, 0.561077, 1.626637, 1.026408, 0.884880, -0.731248, -1.557147, 0.313920, 0.187354, -1.150882, -0.261974, 1.464956, -0.970204, 0.097560, -0.833674, -0.851136, -1.551795, 0.181221, 0.255811, -0.879176, -0.788031, -1.217514, 0.009750, 2.075838, -1.092303, -2.812796, -0.350740, -0.962449, -0.242590, -1.168047, 0.533040, 1.114859, 0.486209, -1.489259, -0.405658, 1.153933, -0.773520, -0.435089, 0.704746, 0.107172, -0.754606, 0.583220, 0.826110, 2.285204, -0.352799, -2.112486, 1.523213, 0.059354, -0.073335, -1.176074, -0.524631, 1.056487, -0.870188, -0.266737, 1.181577, -1.975721, 0.791264, -0.351526, -0.425400, -0.382686, -0.713166, -0.626293, 0.318644, 1.496684, 0.591665, -0.433389, 0.339369, 1.300947, 0.163238, 0.272983, -1.622946, -0.263858, 0.149642, 0.178996, -0.815562, 0.329791, -0.465754, 0.401430, -0.681462, 1.727155, 0.618211, -0.667169, -0.025289, 1.163249, 0.692103, -0.958648, 1.240124, -0.434985, 0.066836, 1.254213, -0.122835, -0.909431, -0.216608, 0.690486, 0.447384, 0.311505, -0.033128, -0.451825, 1.127409, -0.205064, -0.225234, -0.056907, -0.222833, -1.294710, -0.406023, 0.107165, -0.071826, -1.290261, -0.710823, -1.323377, 0.680686, -0.913024, 0.314792, -1.152450, -1.153069, -0.556802, 0.692705, 0.130114, 0.809305, 1.143095, -0.931108, -0.740333, -0.515570, -1.010459, -0.039572, -0.138251, 0.854936, -1.577708, 0.353976, 0.308078, 1.488662, 0.990833, 0.730427, 1.539674, 0.147637, -0.739888, 2.032614, -2.980475, -1.411303, -0.583442, 1.077935, 0.416802, 0.159250, 1.340654, 1.636340, -0.426212, 0.310374, 1.007942, -1.319392, 1.069175, -0.049891, -1.584508, -0.918178, 0.009177, 0.071614, -1.495711, 1.767261, 1.680810, 1.007019, -0.294968, -0.571687, 0.154274, 0.918954, -2.008813, 0.117977, 0.230581, -1.026253, 1.033107, 1.524203, -0.834418, 1.973403, 0.417828, -0.287771, -0.570380, 1.366131, 1.561906, 0.804180, 1.206851, 1.115733, 0.311851, 0.120407, 0.445437, -0.555797, 1.160518, 0.515992, -0.379906, 0.222595, -2.331864, 0.210109, -1.133994, -0.254776, 0.951957, -0.375825, -0.100025, 1.388659, 0.212675, -0.761851, -0.138826, -2.081374, -0.110836, 0.821651, -1.095011, -1.864224, -1.362557, -0.188285, 0.057672, 0.661963, 0.155750, -0.460759, 1.716798, -0.430392, 0.218443, 0.792897, 0.799775, -1.194088, -0.535680, -1.877095, 0.195888, 0.152313, -0.053610, 0.306665, 0.067878, -0.560163, -0.167933, 2.715863, -0.119845, -0.248015, -1.523783, 0.994329, 0.582453, 0.435903, 0.405751, -1.593695, -2.981629, -0.954885, -0.218288, 0.021649, 1.361940, -2.777892, -0.923162, 1.040957, 1.234828, 0.034734, 0.062382, 1.038385, 1.216842, 1.957865, 0.835649, 0.232532, -0.100283, 0.591957, -0.468010, 0.433417, -0.093980, -1.554613, -0.456898, -0.610799, 1.423866, -0.234109, 0.270246, 0.221128}} 43 | Nov = Embedding{Text: "November", Vec: []float32{1.552784, 0.234909, 0.833301, 1.432548, 1.887535, 2.054744, 0.009577, -0.764545, 0.092928, 0.158707, 1.540414, 0.542565, -0.456425, 1.775316, -0.268277, -0.496655, 1.081146, -0.293071, 0.173379, 1.234983, 0.618056, 0.565870, -0.420651, -1.585694, 0.706375, -1.561055, -0.032818, 0.364179, -0.239536, 1.138187, 1.764075, 1.434770, -1.394661, -0.733384, -0.533691, -0.326737, -0.478836, -0.888870, 0.408021, -0.652230, 0.638346, 1.384378, 0.907798, 0.710771, -0.340725, -1.375956, 0.280929, -0.001299, -0.997194, -0.447184, 1.794140, -0.712183, -0.047347, -0.480115, -0.743999, -1.847548, 0.038295, 0.141588, -0.822165, -0.662221, -0.965184, 0.258673, 1.744067, -1.268843, -2.251340, -0.897953, -0.966650, -0.143249, -1.454151, 0.170325, 1.690550, 0.577277, -1.303150, -0.045567, 0.715106, -0.906530, -0.806287, 0.228792, -0.498795, -0.592351, 0.635471, 0.810368, 1.576562, -0.341389, -1.859890, 1.501199, -0.014942, 0.067403, -1.733897, -0.312669, 0.921309, -0.659927, -0.427671, 0.762853, -1.997790, 0.965888, -0.079347, -0.383398, -0.523629, -0.422543, -0.237876, 0.455742, 1.495538, 0.057173, -0.607550, 0.285517, 1.112501, -0.145560, -0.170535, -1.223435, -0.592185, -0.254475, 0.083810, -0.795277, 0.616993, -0.868388, 0.339684, -0.616870, 1.807046, 0.072082, -0.123306, 0.233368, 1.292741, 0.248814, -0.618376, 1.701510, -0.220804, 0.011145, 0.747475, -0.005711, -0.514722, -0.779274, 0.386098, 0.331450, 0.787334, 0.380634, -0.047525, 0.697571, -0.232281, -0.377023, 0.073442, 0.148321, -1.638625, -0.257583, 0.299738, -0.049519, -1.440448, -0.398339, -1.377980, 0.362421, -0.777294, 0.581803, -1.140005, -1.073073, -0.284751, 0.448668, -0.151998, 1.018317, 0.923271, -0.894725, -0.934299, -0.384337, -1.005506, -0.565558, -0.304012, 0.502816, -1.587681, -0.008546, -0.644076, 1.438860, 0.495641, 0.284909, 1.479103, 0.383033, -0.568919, 1.665029, -2.874860, -1.379865, -0.573829, 1.364403, 0.460532, -0.121143, 1.590910, 1.576110, 0.101393, 0.376829, 0.492303, -0.890150, 1.388015, 0.169982, -1.854746, -1.304162, -0.294290, 0.345775, -1.396977, 2.023813, 1.378826, 0.603200, -0.309071, -0.470444, 0.524604, 0.974777, -2.427895, -0.108515, 0.687115, -0.634404, 1.220422, 1.629232, -0.770025, 1.615286, 0.649902, 0.030373, -0.871988, 1.164702, 1.135780, 1.181501, 1.591095, 0.530738, 0.442659, 0.212578, 0.900376, -0.535429, 0.845533, -0.053791, -0.183079, 0.279835, -2.319010, -0.002984, -0.483761, -0.251882, 1.105897, -0.064611, -0.095157, 1.230950, 0.611193, -0.835591, 0.313964, -2.636047, 0.788963, 1.018772, -1.421488, -2.183756, -1.638448, -0.371296, 0.078623, 0.492290, 0.718065, -0.604552, 1.837681, -0.519078, 0.042267, 0.919441, 0.702266, -0.565138, -0.818529, -2.038031, -0.535447, 0.630429, -0.152708, 0.260813, 0.379979, -0.882069, -0.212806, 2.905588, 0.167695, -0.069409, -1.904061, 1.074043, 0.024579, 0.224978, 0.058840, -1.313718, -3.115757, -0.936365, -0.517020, 0.193234, 1.492894, -2.852687, -1.092341, 0.787722, 1.646946, -0.197500, 0.167218, 0.737742, 1.284849, 1.587947, 1.105394, 0.910356, 0.268055, 0.795931, -0.304624, 0.076709, -0.686387, -1.330076, -0.270121, -0.984328, 1.175404, -0.468477, 0.157626, 0.361895}} 44 | Dec = Embedding{Text: "December", Vec: []float32{0.780196, 0.507232, 1.285944, 1.613457, 2.006964, 1.618672, -0.320557, -1.006814, 0.269186, 0.467003, 1.819223, 0.470314, 0.291860, 2.353535, 0.036314, -0.664950, 0.830636, 0.125940, 0.502603, 1.369000, 0.282775, 0.570218, -0.275454, -1.679255, 0.485021, -2.130311, -0.619342, 0.216399, 0.124624, 0.817926, 1.682879, 0.849968, -1.396515, -0.601343, -0.528688, -0.246170, -0.680244, -0.910868, -0.128067, -0.511704, 0.655172, 1.381803, 0.972187, 0.822452, -0.937808, -1.117587, 0.152204, -0.286311, -0.944773, -0.492900, 1.447301, -1.017788, 0.115949, -0.852749, -0.927450, -1.745919, 0.417203, 0.170444, -0.686900, -0.445477, -1.217932, 0.406253, 1.961226, -1.161149, -2.868615, -0.200919, -1.507313, -0.637126, -1.044585, 0.455027, 1.452780, 0.660915, -1.250904, -0.365666, 1.048643, -1.360480, -0.446252, 0.415591, -0.065971, -0.676923, 0.075766, 0.932323, 2.007266, -0.141931, -1.998020, 1.319749, -0.311776, 0.167114, -1.015875, 0.372929, 1.286436, -0.635351, -0.187219, 0.859761, -1.977351, 0.601494, -0.281689, -0.700927, 0.086068, -0.388189, -0.507568, -0.036216, 1.643847, 0.352389, -0.509759, 0.977365, 1.221249, 0.436237, -0.547496, -1.055669, -0.310327, 0.026958, -0.204649, -1.015648, 0.372257, -0.805511, 0.307590, -0.769139, 1.506868, 0.440100, -0.330835, 0.237396, 2.081768, 0.549478, -0.402428, 1.481248, -0.095721, 0.060710, 1.290213, 0.045674, -1.016840, 0.065289, 0.463198, 0.265798, 0.246669, -0.266639, -0.649158, 0.742964, -0.485351, -0.212885, -0.311347, 0.013151, -0.913932, -0.229842, 0.334864, -0.021666, -1.450850, -0.417973, -1.249468, 0.296236, -0.625463, 0.403324, -0.908980, -1.018191, -0.645521, 0.705993, -0.159875, 1.388947, 1.013585, -1.076968, -1.104561, -0.723339, -1.117930, -0.068116, -0.822497, 0.348899, -1.552619, 0.238379, 0.196021, 1.184427, 0.836768, 0.297414, 1.718771, 0.158100, -0.691557, 1.757581, -3.423676, -1.249274, -0.617900, 0.805008, 0.230652, 0.415942, 1.436905, 1.748475, -0.024358, 0.501911, 0.581794, -1.019697, 1.213504, -0.581038, -1.675553, -0.864398, -0.449698, -0.087892, -1.430753, 1.909566, 1.433445, 1.581034, -0.562044, -0.534114, 0.344430, 0.439409, -2.305215, 0.341785, 0.559323, -0.975828, 1.071002, 1.671933, -1.262723, 2.222085, 0.684303, 0.218922, -0.615871, 1.061166, 1.725094, 0.917358, 1.550171, 1.179185, 0.312174, 0.046493, 0.557141, -0.461427, 1.123044, 0.519660, -0.425013, 0.423071, -2.639513, 0.828577, -1.143704, -0.366518, 0.768534, -0.373582, -0.104605, 1.148778, -0.294748, -0.565945, -0.499653, -2.107118, 0.217813, 0.814243, -1.281752, -1.996123, -1.516509, 0.138119, -0.157314, 0.422229, 0.102897, -0.007165, 1.489775, -0.720845, 0.153490, 0.904458, 0.831421, -0.636072, -0.813685, -2.071020, 0.147369, 0.597215, -0.030640, 0.502881, 0.648433, -0.366105, -0.605905, 2.286685, 0.051297, -0.122451, -1.538121, 0.408203, 0.017917, -0.123368, 0.425323, -0.954065, -2.426932, -1.222303, -0.189528, -0.071001, 1.820854, -2.436119, -0.700276, 1.034907, 1.220073, -0.082425, 0.330473, 0.654583, 1.104870, 1.548900, 0.656931, 0.330621, -0.139214, 0.708975, -0.688021, 0.604314, -0.347526, -1.350699, -0.412788, -0.943952, 1.197654, -0.407878, 0.027994, 0.099575}} 45 | 46 | Months = []Embedding{Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec} 47 | 48 | Christmas = Embedding{Vec: []float32{-0.209016, 0.434797, -0.155127, 0.086002, 0.598741, -0.139531, -1.909488, 0.293320, -0.214915, 0.368660, -0.366137, -0.742939, -0.304377, 0.504232, -0.383092, 1.525702, -0.278151, -0.315151, 0.537849, 0.577351, 1.640101, 0.303719, -0.297862, -1.766292, -0.273031, 2.487681, 0.428093, 0.846962, 1.109783, -1.038001, 1.125772, 0.490305, -0.670751, -1.085316, 0.210215, -0.012950, 0.765576, 0.682026, -0.449221, 1.086627, -0.091988, -0.520762, 0.466700, 0.066206, -1.276486, 1.010965, 1.410050, -1.199433, 0.134431, -0.833988, 0.523051, -0.544849, -0.427074, -0.674839, -1.656076, -2.304844, 0.148368, 0.044901, 0.981263, 0.548130, -0.714386, -0.178053, 0.501228, -1.007172, -2.010711, -0.668633, -0.189200, 0.058303, 0.028029, 0.447228, 0.421205, 0.878413, -0.442566, 0.926193, 1.101349, -1.427848, 0.817664, 2.049378, 0.070001, -0.536283, -0.342135, 0.240960, 0.662489, 0.856692, -2.591750, 0.733539, 0.708130, 0.219159, -0.340287, 1.293612, 0.614186, 0.716944, -2.141844, 0.349955, 1.489918, 0.413672, -1.304254, -0.343044, -0.262604, 0.773450, 0.133864, 0.148585, -0.225460, -0.165042, -2.301628, 2.334977, 0.718725, -1.423429, -0.629671, 0.742097, -0.914973, 0.384532, 0.747056, 0.222333, -0.182877, -1.394127, 0.253321, -0.677654, 0.573328, 0.741951, 0.127921, 0.863739, 1.419150, -2.036680, 0.443149, 0.063591, 0.227753, -0.356599, 3.065109, -0.805144, -0.935748, -1.541767, 0.645854, 0.294415, 0.565440, 0.163482, -0.431766, 0.783717, 0.516942, -0.028900, 0.970974, 0.445883, -0.033659, -0.241648, 2.833747, 0.691267, -0.480866, -1.910635, 0.626888, -0.119726, -1.125649, -0.526860, -0.924293, 1.114092, -0.273101, -0.453284, -0.463944, -0.124675, 1.809158, -1.152274, -0.865625, 0.107882, 0.561182, -0.142997, 0.412177, -0.473228, -0.145199, 0.688790, -0.705476, -0.782309, 1.488894, 0.678416, 0.679210, -1.718372, -0.954092, -0.078845, -1.620271, 0.188262, -0.627845, 1.965591, -0.564504, 0.485700, -0.088610, 2.921208, 0.773682, 0.360999, -0.309693, 0.507062, 0.428854, -0.092732, -0.724044, -0.715895, -1.927486, -0.643403, -1.155712, 1.190797, -1.263283, 0.449919, 0.961958, 1.330375, 0.250255, 0.035109, -1.866754, -0.706562, 0.433980, -0.487803, 0.273084, 0.174824, -0.744762, 0.233845, -0.982623, -0.677421, 0.320436, 0.860189, 2.460057, -0.541592, -0.775176, 0.006862, 2.043353, -0.908565, 0.157837, 0.943946, -1.202310, 1.261587, 0.529850, -0.599403, -1.254276, 1.402671, 1.812692, -0.332487, 0.200225, -0.596109, 0.223149, 1.208706, -2.031547, -1.705361, 0.050245, 1.254973, -1.061572, -0.722426, -0.166876, 0.911956, -0.841918, -1.001650, -0.210015, 0.254115, -1.625456, -0.978473, -0.390514, -0.250300, -0.726864, -0.324008, 0.493679, 0.309185, -0.251625, -0.300675, -0.511900, 0.573206, 1.090748, -0.331232, 1.039174, -1.055146, 0.726641, 0.093969, -0.079845, -1.410322, -1.724702, 1.485069, 0.156548, -1.247263, 3.002874, -1.187372, -0.971209, -0.224263, -1.558336, -1.254072, 1.743188, -3.432752, 0.324932, 0.131431, -1.505237, 1.079492, 0.660066, -0.367430, 1.459871, -0.549117, 0.015898, -0.562645, -0.913430, -0.713015, 1.796388, 0.755228, 0.868081, -0.659487, 0.057457, 0.388428, 0.174085, -0.368089, -1.254423, 0.016557}} 49 | ) 50 | 51 | func main() { 52 | // Create new HNSW index with custom surface distance function 53 | index := hnsw.New(surface) 54 | 55 | // Add some data points to the index 56 | for _, vector := range Months { 57 | index.Insert(vector) 58 | } 59 | 60 | // Perform a nearest neighbor search 61 | neighbors := index.Search(Christmas, 4, 100) 62 | fmt.Printf("Nearest Months to Christmas: %s\n", neighbors) 63 | } 64 | -------------------------------------------------------------------------------- /cmd/hnsw/go.sum: -------------------------------------------------------------------------------- 1 | bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= 2 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 4 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 5 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 6 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 7 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 8 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 9 | cloud.google.com/go v0.49.0/go.mod h1:hGvAdzcWNbyuxS3nWhD7H2cIJxjRRTRLQVB0bdputVY= 10 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 11 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 12 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 13 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 14 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 15 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 16 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 17 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 18 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 19 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 20 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 21 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 22 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 23 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 24 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 25 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 26 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 27 | github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= 28 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 29 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 30 | github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= 31 | github.com/DataDog/datadog-go v0.0.0-20180822151419-281ae9f2d895/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= 32 | github.com/DzananGanic/numericalgo v0.0.0-20170804125527-2b389385baf0/go.mod h1:uIo7VpFvBkDQoCyKqUL/mTNjpOlv1KdWaJyCsBSpCe4= 33 | github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= 34 | github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= 35 | github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= 36 | github.com/airbrake/gobrake v3.6.1+incompatible/go.mod h1:wM4gu3Cn0W0K7GUuVWnlXZU11AGBXMILnrdOU8Kn00o= 37 | github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= 38 | github.com/akrylysov/pogreb v0.10.2 h1:e6PxmeyEhWyi2AKOBIJzAEi4HkiC+lKyCocRGlnDi78= 39 | github.com/akrylysov/pogreb v0.10.2/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI= 40 | github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= 41 | github.com/apache/thrift v0.0.0-20181112125854-24918abba929/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= 42 | github.com/aws/aws-sdk-go v1.30.19/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= 43 | github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= 44 | github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= 45 | github.com/blend/go-sdk v1.1.1/go.mod h1:IP1XHXFveOXHRnojRJO7XvqWGqyzevtXND9AdSztAe8= 46 | github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= 47 | github.com/brianvoe/gofakeit/v4 v4.3.0/go.mod h1:GC/GhKWdGJ2eskBf4zGdjo3eHj8rX4E9hFLFg0bqK4s= 48 | github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= 49 | github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= 50 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 51 | github.com/chewxy/math32 v1.10.1 h1:LFpeY0SLJXeaiej/eIp2L40VYfscTvKh/FSEZ68uMkU= 52 | github.com/chewxy/math32 v1.10.1/go.mod h1:dOB2rcuFrCn6UHrze36WSLVPKtzPMRAQvBvUwkSsLqs= 53 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 54 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 55 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 56 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 57 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 58 | github.com/cnkei/gospline v0.0.0-20191204072713-842a72f86331/go.mod h1:DXXGDL64/wxXgBSgmGMEL0vYC0tdvpgNhkJrvavhqDM= 59 | github.com/colinmarc/hdfs/v2 v2.1.1/go.mod h1:M3x+k8UKKmxtFu++uAZ0OtDU8jR3jnaZIAc6yK4Ue0c= 60 | github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= 61 | github.com/containerd/continuity v0.0.0-20200413184840-d3ef23f19fbb/go.mod h1:Dq467ZllaHgAtVp4p1xUQWBrFXR9s/wyoTpG8zOJGkY= 62 | github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 63 | github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 64 | github.com/danaugrs/go-tsne/tsne v0.0.0-20220306155740-2250969e057f h1:5M3/cWnsF9o5+7/PkKJXtZ0i5XZDnoxBzI8531mXJUM= 65 | github.com/danaugrs/go-tsne/tsne v0.0.0-20220306155740-2250969e057f/go.mod h1:vQ+nFRPFDrDVbRneDNbXPObFFq4ZilZBhYdfNiqSr7k= 66 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 67 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 68 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 69 | github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= 70 | github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 71 | github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 72 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 73 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 74 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 75 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 76 | github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= 77 | github.com/fogfish/faults v0.2.0 h1:3KHvZN3cgv2omAGw0MCVH/AbrqxfNag+TFGpgUp6m1w= 78 | github.com/fogfish/faults v0.2.0/go.mod h1:PtvzLt9TP4IF/hRkwRp4dZub42oaMrLbxdS6vmSCJOs= 79 | github.com/fogfish/golem/pure v0.10.1 h1:0+cnvdaV9zF+0NN8SZMgR5bgFM6yNfBHU4rynYSDfmE= 80 | github.com/fogfish/golem/pure v0.10.1/go.mod h1:kLPfgu5uKP0CrwVap7jejisRwV7vo1q8Eyqnc/Z0qyw= 81 | github.com/fogfish/guid/v2 v2.0.4 h1:EZiPlM4UAghqf7DU5/nLEF+iRH7ODe0AiFuYOMRvITQ= 82 | github.com/fogfish/guid/v2 v2.0.4/go.mod h1:KkZ5T4EE3BqWQJFZBPLSHV/tBe23Xq4KvuPfwtNtepU= 83 | github.com/fogfish/hnsw v0.0.4 h1:WxsZ5NmNcQbqpP1MtiLlBQ63S9nlE916p8p6VgKj0jk= 84 | github.com/fogfish/hnsw v0.0.4/go.mod h1:yHc4YziCcO/PycP7vsye2HIM4bH8rYxCCCnFKzBs4Ro= 85 | github.com/fogfish/it v1.0.0 h1:kiwFHZcrkRLUydZoIoY0gTuMfj38trwvLo0YRyIkeG8= 86 | github.com/fogfish/it/v2 v2.0.1 h1:vu3kV2xzYDPHoMHMABxXeu5CoMcTfRc4gkWkzOUkRJY= 87 | github.com/fogfish/it/v2 v2.0.1/go.mod h1:h5FdKaEQT4sUEykiVkB8VV4jX27XabFVeWhoDZaRZtE= 88 | github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= 89 | github.com/frankban/quicktest v1.5.0/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= 90 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 91 | github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= 92 | github.com/go-echarts/go-echarts/v2 v2.4.1 h1:imBFGngJ9zv/2zJVjK3k0uLL+LzyPDgzeV7MWzxH0rs= 93 | github.com/go-echarts/go-echarts/v2 v2.4.1/go.mod h1:56YlvzhW/a+du15f3S2qUGNDfKnFOeJSThBIrVFHDtI= 94 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 95 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 96 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 97 | github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 98 | github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 99 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= 100 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 101 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 102 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 103 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 104 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 105 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 106 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 107 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 108 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 109 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 110 | github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 111 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 112 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 113 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 114 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 115 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 116 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 117 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 118 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 119 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 120 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 121 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 122 | github.com/gonum/blas v0.0.0-20181208220705-f22b278b28ac/go.mod h1:P32wAyui1PQ58Oce/KYkOqQv8cVw1zAapXOl+dRFGbc= 123 | github.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9/go.mod h1:XA3DeT6rxh2EAE789SSiSJNqxPaC0aE9J8NTOI0Jo/A= 124 | github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP0HCqCz+K4ts155PXIlUywf0wqN+GfPZw= 125 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 126 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 127 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 128 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 129 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 130 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 131 | github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= 132 | github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= 133 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 134 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 135 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 136 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 137 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 138 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 139 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 140 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 141 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 142 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 143 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= 144 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 145 | github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= 146 | github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= 147 | github.com/guptarohit/asciigraph v0.5.1/go.mod h1:9fYEfE5IGJGxlP1B+w8wHFy7sNZMhPtn59f0RLtpRFM= 148 | github.com/hashicorp/go-uuid v0.0.0-20180228145832-27454136f036/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 149 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 150 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 151 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 152 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 153 | github.com/icza/gox v0.0.0-20200320174535-a6ff52ab3d90/go.mod h1:VbcN86fRkkUMPX2ufM85Um8zFndLZswoIW1eYtpAcVk= 154 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 155 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 156 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 157 | github.com/jcmturner/gofork v0.0.0-20180107083740-2aebee971930/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= 158 | github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= 159 | github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= 160 | github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= 161 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 162 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 163 | github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= 164 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 165 | github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= 166 | github.com/kelindar/binary v1.0.19 h1:DNyQCtKjkLhBh9pnP49OWREddLB0Mho+1U/AOt/Qzxw= 167 | github.com/kelindar/binary v1.0.19/go.mod h1:/twdz8gRLNMffx0U4UOgqm1LywPs6nd9YK2TX52MDh8= 168 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 169 | github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 170 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 171 | github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 172 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 173 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 174 | github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 175 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 176 | github.com/kshard/atom v0.0.3 h1:8Z3bV65HFN6RYgsx0Z5/atfGSKm8ESaCYrRtV16OLcI= 177 | github.com/kshard/atom v0.0.3/go.mod h1:eZPpTT9FuXE85ioCDVzkc49JljrJBlnVtyZMwpjs4EU= 178 | github.com/kshard/fvecs v0.0.1 h1:4FIjuJaiWWv1Q2y20w/1l13WhNlErWXs4yYVLmotNGo= 179 | github.com/kshard/fvecs v0.0.1/go.mod h1:cehO9AfnF3Tb2vOwhOWmoaNUfYqmm4WQrUMyrPGqN6Q= 180 | github.com/kshard/vector v0.1.1 h1:4sz566fGYEyYdDBDLUJHBMrb7XKdR4UJVsxBEy+UpPM= 181 | github.com/kshard/vector v0.1.1/go.mod h1:gHkE5jmnnl1T7hX5rFHuY7lWbg35XzWieRl+qsnihXU= 182 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 183 | github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 184 | github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 185 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 186 | github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= 187 | github.com/ompluscator/dynamic-struct v1.2.0/go.mod h1:ADQ1+6Ox1D+ntuNwTHyl1NvpAqY2lBXPSPbcO4CJdeA= 188 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 189 | github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 190 | github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 191 | github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= 192 | github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= 193 | github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= 194 | github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 195 | github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= 196 | github.com/pborman/getopt v0.0.0-20180729010549-6fdd0a2c7117/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= 197 | github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= 198 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 199 | github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 200 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 201 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 202 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 203 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 204 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 205 | github.com/rocketlaunchr/dataframe-go v0.0.0-20201007021539-67b046771f0b/go.mod h1:FsS1JF7xpC3WIxMu8DtEyxCNXl1SbHLTlUNE7QcETpA= 206 | github.com/rocketlaunchr/dbq/v2 v2.5.0/go.mod h1:MckY8J697t+AGc0ENl968yDVnD5cP/FFOBSPPyJXY5A= 207 | github.com/rocketlaunchr/mysql-go v1.1.3/go.mod h1:SD/1bpRrmcdnBYRJq8eCerqqS1nTR9Y9WdW+LPzDLAQ= 208 | github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= 209 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 210 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 211 | github.com/sandertv/go-formula/v2 v2.0.0-alpha.7/go.mod h1:Ag4V2fiOHWXct3SraXNN3dFzFtyu9vqBfrjfYWMGLhE= 212 | github.com/shabbyrobe/xmlwriter v0.0.0-20200208144257-9fca06d00ffa/go.mod h1:Yjr3bdWaVWyME1kha7X0jsz3k2DgXNa1Pj3XGyUAbx8= 213 | github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= 214 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 215 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 216 | github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= 217 | github.com/sjwhitworth/golearn v0.0.0-20221228163002-74ae077eafb2 h1:wv0gCxjJAuQJDUlOLsjM/1QPq0VF3tR7n3cMkEf3q+I= 218 | github.com/sjwhitworth/golearn v0.0.0-20221228163002-74ae077eafb2/go.mod h1:rrvYclvrqwEsURE+k7VH2nhOT6BV+IutaIgBBQ9Wdeg= 219 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= 220 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 221 | github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= 222 | github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= 223 | github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= 224 | github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= 225 | github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= 226 | github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= 227 | github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 228 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 229 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 230 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 231 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 232 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 233 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 234 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 235 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 236 | github.com/stretchr/testify v1.6.0 h1:jlIyCplCJFULU/01vCkhKuTyc3OorI3bJFuw6obfgho= 237 | github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 238 | github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= 239 | github.com/tealeg/xlsx/v3 v3.0.0/go.mod h1:fSua0Owrk9yAMAFGZI7piq5UL2BcubuQuLNOEhr3X80= 240 | github.com/wcharczuk/go-chart v2.0.1+incompatible/go.mod h1:PF5tmL4EIx/7Wf+hEkpCqYi5He4u90sw+0+6FhrryuE= 241 | github.com/xitongsys/parquet-go v1.5.1/go.mod h1:xUxwM8ELydxh4edHGegYq1pA8NnMKDx0K/GyB0o2bww= 242 | github.com/xitongsys/parquet-go v1.5.2/go.mod h1:90swTgY6VkNM4MkMDsNxq8h30m6Yj1Arv9UMEl5V5DM= 243 | github.com/xitongsys/parquet-go-source v0.0.0-20190524061010-2b72cbee77d5/go.mod h1:xxCx7Wpym/3QCo6JhujJX51dzSXrwmb0oH6FQb39SEA= 244 | github.com/xitongsys/parquet-go-source v0.0.0-20200326031722-42b453e70c3b/go.mod h1:xxCx7Wpym/3QCo6JhujJX51dzSXrwmb0oH6FQb39SEA= 245 | github.com/xitongsys/parquet-go-source v0.0.0-20200509081216-8db33acb0acf/go.mod h1:EVm7J5W7X/BJsvlGnCaj81kYxgbNzssi/+LF16FoV2s= 246 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 247 | github.com/zserge/lorca v0.1.9/go.mod h1:bVmnIbIRlOcoV285KIRSe4bUABKi7R7384Ycuum6e4A= 248 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 249 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 250 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 251 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 252 | go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= 253 | golang.org/x/build v0.0.0-20200402160453-61705b562fc9/go.mod h1:BEpJH1kxLue/53k7XKPHBk7Qb3nvSlpB/rQWTi7bMdA= 254 | golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 255 | golang.org/x/crypto v0.0.0-20180723164146-c126467f60eb/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 256 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 257 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 258 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 259 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 260 | golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 261 | golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 262 | golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 263 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 264 | golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 265 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 266 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 267 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 268 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 269 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 270 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 271 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 272 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 273 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 274 | golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= 275 | golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= 276 | golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= 277 | golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= 278 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 279 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 280 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 281 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 282 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 283 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 284 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 285 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 286 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 287 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 288 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 289 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 290 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 291 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 292 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 293 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 294 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 295 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 296 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 297 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 298 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 299 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 300 | golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 301 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 302 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 303 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 304 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 305 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 306 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 307 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 308 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 309 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 310 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 311 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 312 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 313 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 314 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 315 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 316 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 317 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 318 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 319 | golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 320 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 321 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 322 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 323 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 324 | golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= 325 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 326 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 327 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 328 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 329 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 330 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 331 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 332 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 333 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 334 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 335 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 336 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 337 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 338 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 339 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 340 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 341 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 342 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 343 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 344 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 345 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 346 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 347 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 348 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 349 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 350 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 351 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 352 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 353 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 354 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 355 | golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= 356 | golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 357 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 358 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 359 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 360 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 361 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 362 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 363 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 364 | golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 365 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 366 | golang.org/x/tools v0.0.0-20181205014116-22934f0fdb62/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 367 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 368 | golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 369 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 370 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 371 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 372 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 373 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 374 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 375 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 376 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 377 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 378 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 379 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 380 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 381 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 382 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 383 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 384 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 385 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 386 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 387 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 388 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 389 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 390 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 391 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 392 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 393 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 394 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 395 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 396 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 397 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 398 | golang.org/x/tools v0.0.0-20200402223321-bcf690261a44/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 399 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 400 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 401 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 402 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 403 | gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= 404 | gonum.org/v1/gonum v0.7.0/go.mod h1:L02bwd0sqlsvRv41G7wGWFCsVNZFv/k1xzGIxeANHGM= 405 | gonum.org/v1/gonum v0.8.1/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= 406 | gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ= 407 | gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo= 408 | gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= 409 | gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= 410 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 411 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 412 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 413 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 414 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 415 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 416 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 417 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 418 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 419 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 420 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 421 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 422 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 423 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 424 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 425 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 426 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 427 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 428 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 429 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 430 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 431 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 432 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 433 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 434 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 435 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 436 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 437 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 438 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 439 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 440 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 441 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 442 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 443 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 444 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 445 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 446 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 447 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 448 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 449 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 450 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 451 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 452 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 453 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 454 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 455 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 456 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 457 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 458 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 459 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 460 | gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= 461 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 462 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 463 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 464 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 465 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 466 | gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= 467 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 468 | gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= 469 | gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= 470 | gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= 471 | gopkg.in/jcmturner/gokrb5.v7 v7.3.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= 472 | gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= 473 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 474 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 475 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 476 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 477 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 478 | gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= 479 | grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= 480 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 481 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 482 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 483 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 484 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 485 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 486 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 487 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 488 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 489 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 490 | --------------------------------------------------------------------------------