201 lines
No EOL
7 KiB
Markdown
201 lines
No EOL
7 KiB
Markdown
# Poindexter
|
|
|
|
[](https://pkg.go.dev/github.com/Snider/Poindexter)
|
|
[](https://github.com/Snider/Poindexter/actions)
|
|
[](https://goreportcard.com/report/github.com/Snider/Poindexter)
|
|
[](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck)
|
|
[](https://codecov.io/gh/Snider/Poindexter)
|
|
[](https://github.com/Snider/Poindexter/releases)
|
|
|
|
A Go library package providing utility functions including sorting algorithms with custom comparators.
|
|
|
|
## Features
|
|
|
|
- 🔢 **Sorting Utilities**: Sort integers, strings, and floats in ascending or descending order
|
|
- 🎯 **Custom Sorting**: Sort any type with custom comparison functions or key extractors
|
|
- 🔍 **Binary Search**: Fast search on sorted data
|
|
- 🧭 **KDTree (NN Search)**: Build a KDTree over points with generic payloads; nearest, k-NN, and radius queries with Euclidean, Manhattan, Chebyshev, and Cosine metrics
|
|
- 📦 **Generic Functions**: Type-safe operations using Go generics
|
|
- ✅ **Well-Tested**: Comprehensive test coverage
|
|
- 📖 **Documentation**: Full documentation available at GitHub Pages
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
go get github.com/Snider/Poindexter
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
poindexter "github.com/Snider/Poindexter"
|
|
)
|
|
|
|
func main() {
|
|
// Basic sorting
|
|
numbers := []int{3, 1, 4, 1, 5, 9}
|
|
poindexter.SortInts(numbers)
|
|
fmt.Println(numbers) // [1 1 3 4 5 9]
|
|
|
|
// Custom sorting with key function
|
|
type Product struct {
|
|
Name string
|
|
Price float64
|
|
}
|
|
|
|
products := []Product{{"Apple", 1.50}, {"Banana", 0.75}, {"Cherry", 3.00}}
|
|
poindexter.SortByKey(products, func(p Product) float64 { return p.Price })
|
|
|
|
// KDTree quick demo
|
|
pts := []poindexter.KDPoint[string]{
|
|
{ID: "A", Coords: []float64{0, 0}, Value: "alpha"},
|
|
{ID: "B", Coords: []float64{1, 0}, Value: "bravo"},
|
|
{ID: "C", Coords: []float64{0, 1}, Value: "charlie"},
|
|
}
|
|
tree, _ := poindexter.NewKDTree(pts, poindexter.WithMetric(poindexter.EuclideanDistance{}))
|
|
nearest, dist, _ := tree.Nearest([]float64{0.9, 0.1})
|
|
fmt.Println(nearest.ID, nearest.Value, dist) // B bravo ~0.141...
|
|
}
|
|
```
|
|
|
|
## Documentation
|
|
|
|
Full documentation is available at [https://snider.github.io/Poindexter/](https://snider.github.io/Poindexter/)
|
|
|
|
Explore runnable examples in the repository:
|
|
- examples/dht_ping_1d
|
|
- examples/kdtree_2d_ping_hop
|
|
- examples/kdtree_3d_ping_hop_geo
|
|
- examples/kdtree_4d_ping_hop_geo_score
|
|
|
|
### KDTree performance and notes
|
|
- Current KDTree queries are O(n) linear scans, which are great for small-to-medium datasets or low-latency prototyping. For 1e5+ points and low/medium dimensions, consider swapping the internal engine to `gonum.org/v1/gonum/spatial/kdtree` (the API here is compatible by design).
|
|
- Insert is O(1) amortized; delete by ID is O(1) via swap-delete; order is not preserved.
|
|
- Concurrency: the KDTree type is not safe for concurrent mutation. Protect with a mutex or share immutable snapshots for read-mostly workloads.
|
|
- See multi-dimensional examples (ping/hops/geo/score) in docs and `examples/`.
|
|
- Performance guide: see docs/Performance for benchmark guidance and tips: [docs/perf.md](docs/perf.md) • Hosted: https://snider.github.io/Poindexter/perf/
|
|
|
|
#### Choosing a metric (quick tips)
|
|
- Euclidean (L2): smooth trade-offs across axes; solid default for blended preferences.
|
|
- Manhattan (L1): emphasizes per-axis absolute differences; good when each unit of ping/hop matters equally.
|
|
- Chebyshev (L∞): dominated by the worst axis; useful for strict thresholds (e.g., reject high hop count regardless of ping).
|
|
- Cosine: angle-based for vector similarity; pair it with normalized/weighted features when direction matters more than magnitude.
|
|
|
|
See the multi-dimensional KDTree docs for end-to-end examples and weighting/normalization helpers: [Multi-Dimensional KDTree (DHT)](docs/kdtree-multidimensional.md).
|
|
|
|
## Maintainer Makefile
|
|
|
|
The repository includes a maintainer-friendly `Makefile` that mirrors CI tasks and speeds up local workflows.
|
|
|
|
- help — list available targets
|
|
- tidy / tidy-check — run `go mod tidy`, optionally verify no diffs
|
|
- fmt — format code (`go fmt ./...`)
|
|
- vet — `go vet ./...`
|
|
- build — `go build ./...`
|
|
- examples — build all programs under `examples/` (if present)
|
|
- test — run unit tests
|
|
- race — run tests with the race detector
|
|
- cover — run tests with race + coverage (writes `coverage.out` and prints summary)
|
|
- coverhtml — render HTML coverage report to `coverage.html`
|
|
- coverfunc — print per-function coverage (from `coverage.out`)
|
|
- cover-kdtree — print coverage details filtered to `kdtree.go`
|
|
- fuzz — run Go fuzzing for a configurable time (default 10s) matching CI
|
|
- bench — run benchmarks with `-benchmem` (writes `bench.txt`)
|
|
- lint — run `golangci-lint` (if installed)
|
|
- vuln — run `govulncheck` (if installed)
|
|
- ci — CI-parity aggregate: tidy-check, build, vet, cover, examples, bench, lint, vuln
|
|
- release — run GoReleaser with the canonical `.goreleaser.yaml` (for tagged releases)
|
|
- snapshot — GoReleaser snapshot (no publish)
|
|
- docs-serve — serve MkDocs locally on 127.0.0.1:8000
|
|
- docs-build — build MkDocs site into `site/`
|
|
|
|
Quick usage:
|
|
|
|
- See all targets:
|
|
|
|
```bash
|
|
make help
|
|
```
|
|
|
|
- Fast local cycle:
|
|
|
|
```bash
|
|
make fmt
|
|
make vet
|
|
make test
|
|
```
|
|
|
|
- CI-parity run (what GitHub Actions does, locally):
|
|
|
|
```bash
|
|
make ci
|
|
```
|
|
|
|
- Coverage summary:
|
|
|
|
```bash
|
|
make cover
|
|
```
|
|
|
|
- Generate HTML coverage report (writes coverage.html):
|
|
|
|
```bash
|
|
make coverhtml
|
|
```
|
|
|
|
- Fuzz for 10 seconds (default):
|
|
|
|
```bash
|
|
make fuzz
|
|
```
|
|
|
|
- Fuzz with a custom time (e.g., 30s):
|
|
|
|
```bash
|
|
make fuzz FUZZTIME=30s
|
|
```
|
|
|
|
- Run benchmarks (writes bench.txt):
|
|
|
|
```bash
|
|
make bench
|
|
```
|
|
|
|
- Build examples (if any under ./examples):
|
|
|
|
```bash
|
|
make examples
|
|
```
|
|
|
|
- Serve docs locally (requires mkdocs-material):
|
|
|
|
```bash
|
|
make docs-serve
|
|
```
|
|
|
|
Configurable variables:
|
|
|
|
- `FUZZTIME` (default `10s`) — e.g. `make fuzz FUZZTIME=30s`
|
|
- `BENCHOUT` (default `bench.txt`), `COVEROUT` (default `coverage.out`), `COVERHTML` (default `coverage.html`)
|
|
- Tool commands are overridable via env: `GO`, `GOLANGCI_LINT`, `GORELEASER`, `MKDOCS`
|
|
|
|
Requirements for optional targets:
|
|
|
|
- `golangci-lint` for `make lint`
|
|
- `golang.org/x/vuln/cmd/govulncheck` for `make vuln`
|
|
- `goreleaser` for `make release` / `make snapshot`
|
|
- `mkdocs` + `mkdocs-material` for `make docs-serve` / `make docs-build`
|
|
|
|
See the full Makefile at the repo root for authoritative target definitions.
|
|
|
|
## License
|
|
|
|
This project is licensed under the European Union Public Licence v1.2 (EUPL-1.2). See [LICENSE](LICENSE) for details.
|
|
|
|
## Contributing
|
|
|
|
Contributions are welcome! Please feel free to submit a Pull Request. |