Skip to content

prep for 0.5 #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 1, 2025
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
16 changes: 0 additions & 16 deletions .github/workflows/ci.yml

This file was deleted.

20 changes: 20 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: test

on: [push]

jobs:
test:
strategy:
max-parallel: 3
matrix:
os: [macos, ubuntu]
ruby: [3.0, 3.4]
runs-on: ${{ matrix.os }}-latest
steps:
- uses: actions/checkout@v3
- uses: taiki-e/install-action@just
- uses: ruby/setup-ruby@v1
with:
bundler-cache: true
ruby-version: ${{ matrix.ruby }}
- run: just ci
12 changes: 6 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
*.gem
.ruby-version
Gemfile.lock
lib/*.so
lib/kdtree.bundle
tmp
*.bundle
*.so
/.tool-versions
/Gemfile.lock
/pkg/
/tmp/
59 changes: 59 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
require:
- standard

inherit_gem:
standard: config/ruby-3.3.yml
standard-custom: config/base.yml
standard-performance: config/base.yml

plugins:
- standard-custom
- standard-performance
- rubocop-performance

AllCops:
NewCops: enable
SuggestExtensions: false

#
# fight with standardrb!
#

# we like these, don't remove
Bundler/OrderedGems: { Enabled: true } # sort gems in gemfile
Bundler/GemVersion: { Enabled: true } # make sure we have versions
Layout/EmptyLineBetweenDefs: { AllowAdjacentOneLineDefs: true }
Lint/NonLocalExitFromIterator: { Enabled: false }
Lint/RedundantDirGlobSort: { Enabled: true } # glob is already sorted
Performance/RegexpMatch: { Enabled: false }
Style/HashSyntax: { EnforcedShorthandSyntax: always } # use modern hash syntax
Style/NestedTernaryOperator: { Enabled: false } # we do this sometimes
Style/NonNilCheck: { Enabled: false } # allow x != nil for clarity
Style/RedundantAssignment: { Enabled: false } # allows s=xxx;s=yyy;s
Style/RedundantReturn: { Enabled: false } # sometines we do this while working on something
Style/StringConcatenation: { Enabled: true } # prefer interpolation
Style/TrailingCommaInArrayLiteral: { EnforcedStyleForMultiline: consistent_comma } # commas!!
Style/TrailingCommaInHashLiteral: { EnforcedStyleForMultiline: consistent_comma } # commas!!

#
# These are rules that are not enabled by default (in standardrb) but we tend to
# write code this way. We don't often trigger these, but it matches our style.
#

Lint/MissingSuper: { Enabled: true }
Naming/FileName: { Enabled: true }
Naming/MemoizedInstanceVariableName: { Enabled: true }
Naming/MethodName: { Enabled: true }
Performance/MapCompact: { Enabled: true }
Performance/SelectMap: { Enabled: true }
Style/BlockDelimiters: { Enabled: true }
Style/CollectionCompact: { Enabled: true }
Style/CollectionMethods: { Enabled: true }
Style/HashEachMethods: { Enabled: true }
Style/HashTransformKeys: { Enabled: true }
Style/HashTransformValues: { Enabled: true }
Style/MinMax: { Enabled: true }
Style/PreferredHashMethods: { Enabled: true }
Style/SelectByRegexp: { Enabled: true }
Style/SymbolArray: { Enabled: true }
Style/WordArray: { Enabled: true }
7 changes: 7 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
source "http://rubygems.org"
gemspec

group :development, :test do
gem "minitest", "~> 5.25"
gem "rake", "~> 13.2"
gem "rake-compiler", "~> 1.3"
gem "standard", "~> 1.49", require: false, platform: :mri
end
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2012 Adam Doppelt
Copyright (c) 2025 Adam Doppelt

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
Expand Down
48 changes: 29 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
## Kdtree
## Kdtree [![test](https://github.com/gurgeous/kdtree/actions/workflows/test.yml/badge.svg)](https://github.com/gurgeous/kdtree/actions/workflows/test.yml)

[![Build Status](https://github.com/gurgeous/kdtree/workflows/ci/badge.svg?branch=master)](https://github.com/gurgeous/kdtree/actions)

A kd tree is a data structure that recursively partitions the world in order to rapidly answer nearest neighbor queries. A generic kd tree can support any number of dimensions, and can return either the nearest neighbor or a set of N nearest neighbors.

This gem is a blazingly fast, native, 2d kdtree. It's specifically built to find the nearest neighbor when searching millions of points. It's used in production at Urbanspoon and several other companies.

The first version of this gem was released back in 2009. See the original [blog post](http://gurge.com/2009/10/22/ruby-nearest-neighbor-fast-kdtree-gem/) for the full story. Wikipedia has a great [article on kdtrees](http://en.wikipedia.org/wiki/K-d_tree).
The first version of this gem was released back in 2009. Wikipedia has a great [article on kdtrees](http://en.wikipedia.org/wiki/K-d_tree).

Note: kdtree 0.3 obsoletes these forks: ghazel-kdtree, groupon-kdtree, tupalo-kdree. Thanks guys!
Note: kdtree obsoletes these forks: ghazel-kdtree, groupon-kdtree, tupalo-kdree. Thanks guys!

### Usage
### Installation

First, install kdtree:
```ruby
# install gem
$ gem install kdtree

```sh
$ sudo gem install kdtree
# or add to your Gemfile
gem "kdtree"
```

### Usage

It's easy to use:

- **Kdtree.new(points)** - construct a new tree. Each point should be of the form `[x, y, id]`, where `x/y` are floats and `id` is an int. Not a string, not an object, **just an int**.
Expand Down Expand Up @@ -50,17 +53,17 @@ kd2 = File.open("treefile") { |f| Kdtree.new(f) }

### Performance

Kdtree is fast. How fast? Using a tree with 1 million points on my i5 2.8ghz:
Kdtree is fast. How fast? Using a tree with 1 million points on my M1:

```
build (init) 3.52s
nearest point 0.000003s
nearest 5 points 0.000004s
nearest 50 points 0.000014s
nearest 255 points 0.000063s

persist 0.301963s
read (init) 0.432676s
build (init) 0.96s
persist 0.000814s
read (init) 0.009236s

nearest point 0.000002s
nearest 5 points 0.000002s
nearest 50 points 0.000006s
nearest 255 points 0.000026s
```

### Limitations
Expand All @@ -81,9 +84,16 @@ Since this gem was originally released, several folks have contributed important

### Changelog

Note: This gem is stable, maintained and continues to work great with all modern versions of Ruby MRI. Our CI tests through Ruby 2.7. No need for new releases until something breaks!
Note: This gem is stable, maintained and continues to work great with all modern versions of Ruby MRI. Our CI tests through Ruby 3.4. No need for new releases until something breaks!

#### 0.5 - May 2025

- justfile
- hygiene - updated deps, format/lint, modernize rakefile
- moved to ruby 3.x or higher, tested with ruby 3.4
- updated benchmark numbers (still real fast)

#### 0.4 - current
#### 0.4 - Mar 2017

- this is mostly housekeeping - test on more rubies, fix a few warnings

Expand Down
41 changes: 6 additions & 35 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,41 +1,12 @@
require "bundler/setup"
require "bundler/gem_tasks"
require "rake/extensiontask"
require "rake/testtask"

# load the spec, we use it below
spec = Gem::Specification.load("kdtree.gemspec")

#
# gem
#

task :build do
system "gem build --quiet kdtree.gemspec"
end

task install: :build do
system "sudo gem install --quiet kdtree-#{spec.version}.gem"
end

task release: :build do
system "git tag -a #{spec.version} -m 'Tagging #{spec.version}'"
system "git push --tags"
system "gem push kdtree-#{spec.version}.gem"
end

#
# rake-compiler
#

Rake::ExtensionTask.new("kdtree", spec)


#
# testing
#
Rake::ExtensionTask.new("kdtree")
task test: :compile

Rake::TestTask.new(:test) do |test|
test.libs << "test"
Rake::TestTask.new do
_1.libs << "test"
_1.test_files = FileList["test/**/test_*.rb"]
end
task test: :compile
task default: :test
Loading