Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
##
## Build the main branch
##
name: build
on:
push:
branches:
- main
- /refs/heads/main

jobs:

build:
runs-on: ubuntu-latest
steps:

- uses: actions/setup-go@v5
with:
go-version: "1.21"

- uses: actions/[email protected]

- name: go build
run: |
go build ./...

- name: go test
run: |
go test -v -coverprofile=profile.cov $(go list ./... | grep -v /examples/)

- uses: shogo82148/actions-goveralls@v1
continue-on-error: true
with:
path-to-profile: profile.cov

- uses: reecetech/[email protected]
id: version
with:
scheme: semver
increment: patch

- name: publish
run: |
git config user.name "GitHub Actions"
git config user.email "[email protected]"
git tag ${{ steps.version.outputs.v-version }}
git push origin -u ${{ steps.version.outputs.v-version }}

34 changes: 34 additions & 0 deletions .github/workflows/check-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
##
## Unit Tests
##
name: test
on:
pull_request:
types:
- opened
- synchronize

jobs:

unit:
runs-on: ubuntu-latest
steps:

- uses: actions/setup-go@v5
with:
go-version: "1.21"

- uses: actions/[email protected]

- name: go build
run: |
go build ./...

- name: go test
run: |
go test -v -coverprofile=profile.cov $(go list ./... | grep -v /examples/)

- uses: shogo82148/actions-goveralls@v1
continue-on-error: true
with:
path-to-profile: profile.cov
130 changes: 128 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,128 @@
# vector
Vector Data Type for Golang
# Vector

The library implement fast (highly optimized) vector algebra for Golang.

[![Version](https://img.shields.io/github/v/tag/kshard/vector?label=version)](https://github.com/kshard/vector/releases)
[![Documentation](https://pkg.go.dev/badge/github.com/kshard/vector)](https://pkg.go.dev/github.com/kshard/vector)
[![Build Status](https://github.com/kshard/vector/workflows/build/badge.svg)](https://github.com/kshard/vector/actions/)
[![Git Hub](https://img.shields.io/github/last-commit/kshard/vector.svg)](https://github.com/kshard/vector)
[![Coverage Status](https://coveralls.io/repos/github/kshard/vector/badge.svg?branch=main)](https://coveralls.io/github/kshard/vector?branch=main)
[![Go Report Card](https://goreportcard.com/badge/github.com/kshard/vector)](https://goreportcard.com/report/github.com/kshard/vector)


## Inspiration

Hierarchical Navigable Small World (HNSW) algorithms are state-of-the-art techniques employed for approximate nearest neighbor searches. Vectors and the concept of distance are essential components of the algorithm. The algorithm requires large quantity of vector comparisons on the write path.

The specific count of vector operations performed by HNSW can vary, contingent on factors such as implementation details and the chosen parameters for the algorithm. We have observed a logarithmic progression, starting from 2.2K distance computations per write operation, with subsequent growth reaching 8K and beyond.

**In handling such extensive data, the significance of nanoseconds cannot be overstated!**


## Getting started

The latest version of the library is available at `main` branch of this repository. 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.

```go
import "github.com/kshard/vector"

// Our vectors
a := []float32{60.1699, 24.9384, 24.9384, 60.1699}
b := []float32{59.9311, 30.3609, 30.3609, 59.9311}

// instantiate Euclidean distance function
euclidean := vector.Euclidean()

euclidean.Distance(a, b) // 58.921078

// instantiate Cosine distance function
cosine := vector.Cosine()

cosine.Distance(a, b) // 0.001443
```

**Note**: One known limitation, the library requires vectors aligned to 4.

### Supported CPU architectures

The library provides two versions of vector algebra functions. The library automatically selects appropriate version depending on the architecture.

1. A Golang native version optimized for instruction pipelining.
2. A pure assembly implementation leveraging the SIMD ("Single Instruction Multiple Data") instruction set.

Internally each version is implemented by the package
1. [internal/noasm](internal/noasm/) - optimized Golang version.
2. [internal/simd](internal/simd/) - pure assembly implementation.
3. [internal/pure](internal/pure/) - reference implementation using idiomatic Golang.

The library provides `Info` function to determine configuration runtime

```go
config = vector.Info()

config[vector.CONFIG_XXX]
// XXX_WITH_PURE
// XXX_WITH_NOASM
// XXX_WITH_SIMD
```

## Performance

Instruction pipeline is 3.3x faster and SIMD is 3.8x faster (due to [bounds check elimination](https://go101.org/article/bounds-check-elimination.html))

```
go test -run=^$ -bench=. -cpu=1

BenchmarkPureEuclideanF32 4072329 270.5 ns/op
BenchmarkNoAsmEuclideanF32 14938154 81.59 ns/op
BenchmarkSIMDEuclideanF32 16888236 71.15 ns/op
BenchmarkPureCosineF32 3987426 299.8 ns/op
BenchmarkNoAsmCosineF32 11738499 102.2 ns/op
```


## How To Contribute

The library is [MIT](LICENSE) licensed and accepts contributions via GitHub pull requests:

1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Added some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request

The build and testing process requires [Go](https://golang.org) version 1.13 or later.

**build** and **test** library.

```bash
git clone https://github.com/kshard/vector
cd vector
go test
```

Checklist:
1. No new bounds check introduced: `go build -gcflags="-d=ssa/check_bce"`
2. No performance degradations: `go test -run=^$ -bench=. -cpu=1`


### commit message

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.

### bugs

If you experience any issues with the library, please let us know via [GitHub issues](https://github.com/kshard/vectors/issue). We appreciate detailed and accurate reports that help us to identity and replicate the issue.


## License

[![See LICENSE](https://img.shields.io/github/license/kshard/vector.svg?style=for-the-badge)](LICENSE)


## References
1. [A Quick Guide to Go's Assembler](https://go.dev/doc/asm)
2. https://github.com/below/HelloSilicon
3. https://github.com/hztools/go-sdr/tree/main/internal/simd
4. [Bounds Check Elimination](https://go101.org/article/bounds-check-elimination.html)

8 changes: 8 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module github.com/kshard/vector

go 1.22.0

require (
github.com/chewxy/math32 v1.10.1
golang.org/x/sys v0.17.0
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
github.com/chewxy/math32 v1.10.1 h1:LFpeY0SLJXeaiej/eIp2L40VYfscTvKh/FSEZ68uMkU=
github.com/chewxy/math32 v1.10.1/go.mod h1:dOB2rcuFrCn6UHrze36WSLVPKtzPMRAQvBvUwkSsLqs=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
67 changes: 67 additions & 0 deletions internal/noasm/cosine.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// Copyright (C) 2024 Dmitry Kolesnikov
//
// This file may be modified and distributed under the terms
// of the MIT license. See the LICENSE file for details.
// https://github.com/kshard/vector
//

package noasm

import "github.com/chewxy/math32"

const ENABLED_COSINE = true

// Cosine distance between two vectors
func CosineF32(a, b []float32) (d float32) {
if len(a) != len(b) {
panic("vectors must have equal lengths")
}

if len(a)%4 != 0 {
panic("vector length must be multiple of 4")
}

ab := float32(0.0)
aa := float32(0.0)
bb := float32(0.0)

for i := 0; i < len(a); i += 4 {
asl := a[i : i+4 : i+4]
bsl := b[i : i+4 : i+4]

ax0, ax1, ax2, ax3 := asl[0], asl[1], asl[2], asl[3]
bx0, bx1, bx2, bx3 := bsl[0], bsl[1], bsl[2], bsl[3]

ab0 := ax0 * bx0
ab1 := ax1 * bx1
ab2 := ax2 * bx2
ab3 := ax3 * bx3
ab += ab0 + ab1 + ab2 + ab3

aa0 := ax0 * ax0
aa1 := ax1 * ax1
aa2 := ax2 * ax2
aa3 := ax3 * ax3
aa += aa0 + aa1 + aa2 + aa3

bb0 := bx0 * bx0
bb1 := bx1 * bx1
bb2 := bx2 * bx2
bb3 := bx3 * bx3
bb += bb0 + bb1 + bb2 + bb3
}

s := math32.Sqrt(aa) * math32.Sqrt(bb)

d = (1 - ab/s) / 2

return
}

// Type Class for Cosine distance
type Cosine int

func (Cosine) Distance(a, b []float32) float32 {
return CosineF32(a, b)
}
47 changes: 47 additions & 0 deletions internal/noasm/euclidean.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//
// Copyright (C) 2024 Dmitry Kolesnikov
//
// This file may be modified and distributed under the terms
// of the MIT license. See the LICENSE file for details.
// https://github.com/kshard/vector
//

package noasm

const ENABLED_EUCLIDEAN = true

// Squared Euclidean distance between two vectors
func EuclideanF32(a, b []float32) (d float32) {
if len(a) != len(b) {
panic("vectors must have equal lengths")
}

if len(a)%4 != 0 {
panic("vectors length must be multiple of 4")
}

for i := 0; i < len(a); i += 4 {
av := a[i : i+4 : i+4]
bv := b[i : i+4 : i+4]
x1 := av[0] - bv[0]
x2 := av[1] - bv[1]
x3 := av[2] - bv[2]
x4 := av[3] - bv[3]

d1 := x1 * x1
d2 := x2 * x2
d3 := x3 * x3
d4 := x4 * x4

d += d1 + d2 + d3 + d4
}

return
}

// Type Class for Euclidean distance
type Euclidean int

func (Euclidean) Distance(a, b []float32) float32 {
return EuclideanF32(a, b)
}
45 changes: 45 additions & 0 deletions internal/pure/cosine.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// Copyright (C) 2024 Dmitry Kolesnikov
//
// This file may be modified and distributed under the terms
// of the MIT license. See the LICENSE file for details.
// https://github.com/kshard/vector
//

package pure

import (
"github.com/chewxy/math32"
)

const ENABLED_COSINE = false

// Cosine distance between two vectors
func CosineF32(a, b []float32) (d float32) {
if len(a) != len(b) {
panic("vectors must have equal lengths")
}

ab := float32(0.0)
aa := float32(0.0)
bb := float32(0.0)

for i := 0; i < len(a); i++ {
ab += a[i] * b[i]
aa += a[i] * a[i]
bb += b[i] * b[i]
}

s := math32.Sqrt(aa) * math32.Sqrt(bb)

d = (1 - ab/s) / 2

return
}

// Type Class for Cosine distance
type Cosine int

func (Cosine) Distance(a, b []float32) float32 {
return CosineF32(a, b)
}
Loading