├── 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 |  |
233 | | HNSW Layer 1 |  |
234 | | HNSW Layer 0 |  |
235 | | Vector point cloud |  |
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 | [](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 |
--------------------------------------------------------------------------------