hongshibao/go-kdtree

View on GitHub
README.md

Summary

Maintainability
Test Coverage
# KDTree
[![Maintainability](https://api.codeclimate.com/v1/badges/68ed481fb60be91970b8/maintainability)](https://codeclimate.com/github/hongshibao/go-kdtree/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/68ed481fb60be91970b8/test_coverage)](https://codeclimate.com/github/hongshibao/go-kdtree/test_coverage)

Golang implementation of KD tree (https://en.wikipedia.org/wiki/K-d_tree) data structure

## Getting started

Use go tool to install the package in your packages tree:
```
go get github.com/hongshibao/go-kdtree
```
Then you can use it in import section of your Go programs:
```go
import "github.com/hongshibao/go-kdtree"
```
The package name is ```kdtree```.

## Basic example

First you need to implement the ```Point``` interface:
```go
type Point interface {
    // Return the total number of dimensions
    Dim() int
    // Return the value X_{dim}, dim is started from 0
    GetValue(dim int) float64
    // Return the distance between two points
    Distance(p Point) float64
    // Return the distance between the point and the plane X_{dim}=val
    PlaneDistance(val float64, dim int) float64
}
```
Here is an example of implementing ```Point``` interface with square of Euclidean distance as the ```Distance``` definition:
```go
type EuclideanPoint struct {
    Point
    Vec []float64
}

func (p *EuclideanPoint) Dim() int {
    return len(p.Vec)
}

func (p *EuclideanPoint) GetValue(dim int) float64 {
    return p.Vec[dim]
}

func (p *EuclideanPoint) Distance(other Point) float64 {
    var ret float64
    for i := 0; i < p.Dim(); i++ {
        tmp := p.GetValue(i) - other.GetValue(i)
        ret += tmp * tmp
    }
    return ret
}

func (p *EuclideanPoint) PlaneDistance(val float64, dim int) float64 {
    tmp := p.GetValue(dim) - val
    return tmp * tmp
}
```
Now you can create KD-tree from a list of points and get a list of k nearest neighbours for a target point:
```go
func NewEuclideanPoint(vals ...float64) *EuclideanPoint {
    ret := &EuclideanPoint{}
    for _, val := range vals {
        ret.Vec = append(ret.Vec, val)
    }
    return ret
}

func main() {
    p1 := NewEuclideanPoint(0.0, 0.0, 0.0)
    p2 := NewEuclideanPoint(0.0, 0.0, 1.0)
    p3 := NewEuclideanPoint(0.0, 1.0, 0.0)
    p4 := NewEuclideanPoint(1.0, 0.0, 0.0)
    points := make([]Point, 0)
    points = append(points, p1)
    points = append(points, p2)
    points = append(points, p3)
    points = append(points, p4)
    tree := NewKDTree(points)
    targetPoint := NewEuclideanPoint(0.0, 0.0, 0.1)
    neighbours := tree.KNN(targetPoint, 2)
    for idx, p := range neighbours {
        fmt.Printf("Point %d: (%f", idx, p.GetValue(0))
        for i := 1; i < p.Dim(); i++ {
            fmt.Printf(", %f", p.GetValue(i))
        }
        fmt.Println(")")
    }
}
```
The returned k nearest neighbours are sorted by their distance with the target point.