kdtree 0.4 → 0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 4d1d98fec6ed9f4ce19cd558098cbe6038c9d77d
4
- data.tar.gz: 4b2f5d14367f4210146a7dea6e0e6dbd62ba9077
2
+ SHA256:
3
+ metadata.gz: 8fa26faf959cacb1da1692bef2539c89031037f4a2c5f715eadc5fed72fa5590
4
+ data.tar.gz: 3377e4521781a8a675840bf5ac7a34998bbd43783643f0b2ab4ee9988d85465d
5
5
  SHA512:
6
- metadata.gz: 68331f4219424518d298fa21b5aec5dd6353909a2e0fec61202894fd7b87aeb91d35761afee2b28f1edfc73547834e790b4ee414b18f40b5eab4c4b67d132c87
7
- data.tar.gz: 506bd2057fec9dd7f9a82132e947ee37fdf2533ed70fa6c721e4643b113f884e32a8f4219ec20459b1e6a812031ff97b3cccf1b71ea93daf3a31941a87a99a1c
6
+ metadata.gz: 7f50f4e1721d3ad2359ac3c3ebf8436a5716a4b333e4cc6de3f1443624417b5cecdabb9a25a76f52baf89014b3a70ca699ae4920657ec384305275fcc01a2c3d
7
+ data.tar.gz: 2075eea9b92b86c547e70a5802df0c2af13554ec43ac92ddedd85d4012d02219ddfa646dabed4e81edb125af363ecc26ad5357b797931184a0a8f3dd8eba53b3
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012 Adam Doppelt
1
+ Copyright (c) 2025 Adam Doppelt
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,28 +1,31 @@
1
- ## Kdtree
1
+ ## Kdtree [![test](https://github.com/gurgeous/kdtree/actions/workflows/test.yml/badge.svg)](https://github.com/gurgeous/kdtree/actions/workflows/test.yml)
2
2
 
3
- [![Build Status](https://travis-ci.org/gurgeous/kdtree.svg?branch=master)](https://travis-ci.org/gurgeous/kdtree)
4
3
 
5
4
  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.
6
5
 
7
6
  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.
8
7
 
9
- 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).
8
+ 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).
10
9
 
11
- Note: kdtree 0.3 obsoletes these forks: ghazel-kdtree, groupon-kdtree, tupalo-kdree. Thanks guys!
10
+ Note: kdtree obsoletes these forks: ghazel-kdtree, groupon-kdtree, tupalo-kdree. Thanks guys!
12
11
 
13
- ### Usage
12
+ ### Installation
14
13
 
15
- First, install kdtree:
14
+ ```ruby
15
+ # install gem
16
+ $ gem install kdtree
16
17
 
17
- ```sh
18
- $ sudo gem install kdtree
18
+ # or add to your Gemfile
19
+ gem "kdtree"
19
20
  ```
20
21
 
22
+ ### Usage
23
+
21
24
  It's easy to use:
22
25
 
23
- * **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**.
24
- * **kd.nearest(x, y)** - find the nearest point. Returns an id.
25
- * **kd.nearestk(x, y, k)** - find the nearest `k` points. Returns an array of ids.
26
+ - **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**.
27
+ - **kd.nearest(x, y)** - find the nearest point. Returns an id.
28
+ - **kd.nearestk(x, y, k)** - find the nearest `k` points. Returns an array of ids.
26
29
 
27
30
  For example:
28
31
 
@@ -50,50 +53,63 @@ kd2 = File.open("treefile") { |f| Kdtree.new(f) }
50
53
 
51
54
  ### Performance
52
55
 
53
- Kdtree is fast. How fast? Using a tree with 1 million points on my i5 2.8ghz:
56
+ Kdtree is fast. How fast? Using a tree with 1 million points on my M1:
54
57
 
55
58
  ```
56
- build (init) 3.52s
57
- nearest point 0.000003s
58
- nearest 5 points 0.000004s
59
- nearest 50 points 0.000014s
60
- nearest 255 points 0.000063s
61
-
62
- persist 0.301963s
63
- read (init) 0.432676s
59
+ build (init) 0.96s
60
+ persist 0.000814s
61
+ read (init) 0.009236s
62
+
63
+ nearest point 0.000002s
64
+ nearest 5 points 0.000002s
65
+ nearest 50 points 0.000006s
66
+ nearest 255 points 0.000026s
64
67
  ```
65
68
 
66
69
  ### Limitations
67
70
 
68
- * No **editing** allowed! Once you construct a tree you're stuck with it.
69
- * The tree is stored in **one big memory block**, 20 bytes per point. A tree with one million points will allocate a single 19mb block to store its nodes.
70
- * Persisted trees are **architecture dependent**, and may not work across different machines due to endian issues.
71
- * nearestk is limited to **255 results**
71
+ - No **editing** allowed! Once you construct a tree you're stuck with it.
72
+ - The tree is stored in **one big memory block**, 20 bytes per point. A tree with one million points will allocate a single 19mb block to store its nodes.
73
+ - Persisted trees are **architecture dependent**, and may not work across different machines due to endian issues.
74
+ - nearestk is limited to **255 results**
72
75
 
73
76
  ### Contributors
74
77
 
75
78
  Since this gem was originally released, several folks have contributed important patches:
76
79
 
77
- * @antifuchs (thread safety)
78
- * @evanphx (native cleanups, perf)
79
- * @ghazel (C89 compliance)
80
- * @mcerna (1.9 compat)
80
+ - @antifuchs (thread safety)
81
+ - @evanphx (native cleanups, perf)
82
+ - @ghazel (C89 compliance)
83
+ - @mcerna (1.9 compat)
81
84
 
82
85
  ### Changelog
83
86
 
84
- #### 0.3
87
+ 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!
88
+
89
+ #### 0.5 - May 2025
90
+
91
+ - justfile
92
+ - hygiene - updated deps, format/lint, modernize rakefile
93
+ - moved to ruby 3.x or higher, tested with ruby 3.4
94
+ - updated benchmark numbers (still real fast)
95
+
96
+ #### 0.4 - Mar 2017
97
+
98
+ - this is mostly housekeeping - test on more rubies, fix a few warnings
99
+
100
+ #### 0.3 - Oct 2012
85
101
 
86
- * Ruby 1.9.x compatibility (@mcerna and others)
87
- * renamed KDTree to the more idiomatic Kdtree
88
- * use IO methods directly instead of rooting around in rb_io
89
- * thread safe, no more statics (@antifuchs)
90
- * C90 compliance, no warnings (@ghazel)
91
- * native cleanups (@evanphx)
102
+ - Ruby 1.9.x compatibility (@mcerna and others)
103
+ - renamed KDTree to the more idiomatic Kdtree
104
+ - use IO methods directly instead of rooting around in rb_io
105
+ - thread safe, no more statics (@antifuchs)
106
+ - C90 compliance, no warnings (@ghazel)
107
+ - native cleanups (@evanphx)
92
108
 
93
109
  #### 0.2
94
110
 
95
111
  skipped this version to prevent confusion with other flavors of the gem
96
112
 
97
- #### 0.1
113
+ #### 0.1 - Jan 2010
98
114
 
99
- * Original release
115
+ - Original release
data/ext/kdtree/kdtree.c CHANGED
@@ -5,16 +5,14 @@
5
5
  //
6
6
 
7
7
  // the tree itself
8
- typedef struct kdtree_data
9
- {
8
+ typedef struct kdtree_data {
10
9
  int root;
11
10
  int len;
12
11
  struct kdtree_node *nodes;
13
12
  } kdtree_data;
14
13
 
15
14
  // a node in the tree
16
- typedef struct kdtree_node
17
- {
15
+ typedef struct kdtree_node {
18
16
  float x, y;
19
17
  int id;
20
18
  int left;
@@ -28,7 +26,7 @@ typedef struct kresult {
28
26
  } kresult;
29
27
 
30
28
  // helper macro for digging out our struct
31
- #define KDTREEP \
29
+ #define KDTREEP \
32
30
  struct kdtree_data *kdtreep; \
33
31
  Data_Get_Struct(kdtree, struct kdtree_data, kdtreep);
34
32
 
@@ -43,8 +41,10 @@ static VALUE kdtree_to_s(VALUE kdtree);
43
41
 
44
42
  // kdtree helpers
45
43
  static int kdtree_build(struct kdtree_data *kdtreep, int min, int max, int depth);
46
- static void kdtree_nearest0(struct kdtree_data *kdtreep, int i, float x, float y, int depth, int *n_index, float *n_dist);
47
- static void kdtree_nearestk0(struct kdtree_data *kdtreep, int i, float x, float y, int k, int depth, kresult *k_list, int *k_len, float *k_dist);
44
+ static void kdtree_nearest0(struct kdtree_data *kdtreep, int i, float x, float y, int depth,
45
+ int *n_index, float *n_dist);
46
+ static void kdtree_nearestk0(struct kdtree_data *kdtreep, int i, float x, float y, int k, int depth,
47
+ kresult *k_list, int *k_len, float *k_dist);
48
48
 
49
49
  // io helpers
50
50
  static void read_all(VALUE io, void *buf, int len);
@@ -59,16 +59,14 @@ static ID id_read, id_write, id_binmode;
59
59
  // implementation
60
60
  //
61
61
 
62
- static VALUE kdtree_alloc(VALUE klass)
63
- {
62
+ static VALUE kdtree_alloc(VALUE klass) {
64
63
  struct kdtree_data *kdtreep;
65
64
  VALUE obj = Data_Make_Struct(klass, struct kdtree_data, 0, kdtree_free, kdtreep);
66
65
  kdtreep->root = -1;
67
66
  return obj;
68
67
  }
69
68
 
70
- static void kdtree_free(struct kdtree_data *kdtreep)
71
- {
69
+ static void kdtree_free(struct kdtree_data *kdtreep) {
72
70
  if (kdtreep) {
73
71
  free(kdtreep->nodes);
74
72
  }
@@ -95,15 +93,14 @@ static void kdtree_free(struct kdtree_data *kdtreep)
95
93
  * kdtree. This makes it possible to build the tree in advance, persist it, and
96
94
  * start it up quickly later. See persist for more information.
97
95
  */
98
- static VALUE kdtree_initialize(VALUE kdtree, VALUE arg)
99
- {
96
+ static VALUE kdtree_initialize(VALUE kdtree, VALUE arg) {
100
97
  KDTREEP;
101
98
 
102
99
  if (TYPE(arg) == T_ARRAY) {
103
100
  // init from array of pints
104
101
  VALUE points = arg;
105
102
  int i;
106
- kdtreep->len = RARRAY_LEN(points);
103
+ kdtreep->len = (int)RARRAY_LEN(points);
107
104
  kdtreep->nodes = ALLOC_N(struct kdtree_node, kdtreep->len);
108
105
 
109
106
  for (i = 0; i < RARRAY_LEN(points); ++i) {
@@ -147,23 +144,20 @@ static VALUE kdtree_initialize(VALUE kdtree, VALUE arg)
147
144
  return kdtree;
148
145
  }
149
146
 
150
- static int comparex(const void *pa, const void *pb)
151
- {
152
- float a = ((const struct kdtree_node*)pa)->x;
153
- float b = ((const struct kdtree_node*)pb)->x;
147
+ static int comparex(const void *pa, const void *pb) {
148
+ float a = ((const struct kdtree_node *)pa)->x;
149
+ float b = ((const struct kdtree_node *)pb)->x;
154
150
  return (a < b) ? -1 : ((a > b) ? 1 : 0);
155
151
  }
156
152
 
157
- static int comparey(const void *pa, const void *pb)
158
- {
159
- float a = ((const struct kdtree_node*)pa)->y;
160
- float b = ((const struct kdtree_node*)pb)->y;
153
+ static int comparey(const void *pa, const void *pb) {
154
+ float a = ((const struct kdtree_node *)pa)->y;
155
+ float b = ((const struct kdtree_node *)pb)->y;
161
156
  return (a < b) ? -1 : ((a > b) ? 1 : 0);
162
157
  }
163
158
 
164
- static int kdtree_build(struct kdtree_data *kdtreep, int min, int max, int depth)
165
- {
166
- int(*compar)(const void *, const void *);
159
+ static int kdtree_build(struct kdtree_data *kdtreep, int min, int max, int depth) {
160
+ int (*compar)(const void *, const void *);
167
161
  struct kdtree_node *m;
168
162
  int median;
169
163
  if (max <= min) {
@@ -198,8 +192,7 @@ static int kdtree_build(struct kdtree_data *kdtreep, int min, int max, int depth
198
192
  * # which city is closest to Boston?
199
193
  * kd.nearest(42.4, -71.1) #=> 2
200
194
  */
201
- static VALUE kdtree_nearest(VALUE kdtree, VALUE x, VALUE y)
202
- {
195
+ static VALUE kdtree_nearest(VALUE kdtree, VALUE x, VALUE y) {
203
196
  int n_index;
204
197
  float n_dist;
205
198
  KDTREEP;
@@ -214,8 +207,8 @@ static VALUE kdtree_nearest(VALUE kdtree, VALUE x, VALUE y)
214
207
  return INT2NUM((kdtreep->nodes + n_index)->id);
215
208
  }
216
209
 
217
- static void kdtree_nearest0(struct kdtree_data *kdtreep, int i, float x, float y, int depth, int *n_index, float *n_dist)
218
- {
210
+ static void kdtree_nearest0(struct kdtree_data *kdtreep, int i, float x, float y, int depth,
211
+ int *n_index, float *n_dist) {
219
212
  struct kdtree_node *n;
220
213
  float ad;
221
214
  int near, far;
@@ -234,11 +227,13 @@ static void kdtree_nearest0(struct kdtree_data *kdtreep, int i, float x, float y
234
227
  //
235
228
 
236
229
  if (ad <= 0) {
237
- near = n->left; far = n->right;
230
+ near = n->left;
231
+ far = n->right;
238
232
  } else {
239
- near = n->right; far = n->left;
233
+ near = n->right;
234
+ far = n->left;
240
235
  }
241
- kdtree_nearest0(kdtreep, near, x, y, depth + 1, n_index, n_dist);
236
+ kdtree_nearest0(kdtreep, near, x, y, depth + 1, n_index, n_dist);
242
237
  if (ad * ad < *n_dist) {
243
238
  kdtree_nearest0(kdtreep, far, x, y, depth + 1, n_index, n_dist);
244
239
  }
@@ -280,9 +275,9 @@ static void kdtree_nearest0(struct kdtree_data *kdtreep, int i, float x, float y
280
275
  * # which two cities are closest to San Francisco?
281
276
  * kd.nearestk(34.1, -118.2, 2) #=> [2, 1]
282
277
  */
283
- static VALUE kdtree_nearestk(VALUE kdtree, VALUE x, VALUE y, VALUE k)
284
- {
285
- // note I leave an extra slot here at the end because of the way our binary insert works
278
+ static VALUE kdtree_nearestk(VALUE kdtree, VALUE x, VALUE y, VALUE k) {
279
+ // note I leave an extra slot here at the end because of the way our binary
280
+ // insert works
286
281
  kresult k_list[MAX_K + 1];
287
282
  int k_len = 0;
288
283
  float k_dist = INT_MAX;
@@ -296,7 +291,8 @@ static VALUE kdtree_nearestk(VALUE kdtree, VALUE x, VALUE y, VALUE k)
296
291
  } else if (ki > MAX_K) {
297
292
  ki = MAX_K;
298
293
  }
299
- kdtree_nearestk0(kdtreep, kdtreep->root, NUM2DBL(x), NUM2DBL(y), ki, 0, k_list, &k_len, &k_dist);
294
+ kdtree_nearestk0(kdtreep, kdtreep->root, NUM2DBL(x), NUM2DBL(y), ki, 0, k_list, &k_len,
295
+ &k_dist);
300
296
 
301
297
  // convert result to ruby array
302
298
  ary = rb_ary_new();
@@ -306,8 +302,8 @@ static VALUE kdtree_nearestk(VALUE kdtree, VALUE x, VALUE y, VALUE k)
306
302
  return ary;
307
303
  }
308
304
 
309
- static void kdtree_nearestk0(struct kdtree_data *kdtreep, int i, float x, float y, int k, int depth, kresult *k_list, int *k_len, float *k_dist)
310
- {
305
+ static void kdtree_nearestk0(struct kdtree_data *kdtreep, int i, float x, float y, int k, int depth,
306
+ kresult *k_list, int *k_len, float *k_dist) {
311
307
  struct kdtree_node *n;
312
308
  float ad;
313
309
  int near, far;
@@ -327,11 +323,13 @@ static void kdtree_nearestk0(struct kdtree_data *kdtreep, int i, float x, float
327
323
  //
328
324
 
329
325
  if (ad <= 0) {
330
- near = n->left; far = n->right;
326
+ near = n->left;
327
+ far = n->right;
331
328
  } else {
332
- near = n->right; far = n->left;
329
+ near = n->right;
330
+ far = n->left;
333
331
  }
334
- kdtree_nearestk0(kdtreep, near, x, y, k, depth + 1, k_list, k_len, k_dist);
332
+ kdtree_nearestk0(kdtreep, near, x, y, k, depth + 1, k_list, k_len, k_dist);
335
333
  if (ad * ad < *k_dist) {
336
334
  kdtree_nearestk0(kdtreep, far, x, y, k, depth + 1, k_list, k_len, k_dist);
337
335
  }
@@ -404,9 +402,7 @@ static void kdtree_nearestk0(struct kdtree_data *kdtreep, int i, float x, float
404
402
  * # later, read the tree from disk
405
403
  * kd2 = File.open("treefile") { |f| Kdtree.new(f) }
406
404
  */
407
- static VALUE kdtree_persist(VALUE kdtree, VALUE io)
408
- {
409
- VALUE str;
405
+ static VALUE kdtree_persist(VALUE kdtree, VALUE io) {
410
406
  KDTREEP;
411
407
 
412
408
  if (!rb_respond_to(io, rb_intern("write"))) {
@@ -428,12 +424,11 @@ static VALUE kdtree_persist(VALUE kdtree, VALUE io)
428
424
  *
429
425
  * A string that tells you a bit about the tree.
430
426
  */
431
- static VALUE kdtree_to_s(VALUE kdtree)
432
- {
427
+ static VALUE kdtree_to_s(VALUE kdtree) {
433
428
  char buf[256];
434
429
  KDTREEP;
435
430
 
436
- sprintf(buf, "#<%s:%p nodes=%d>", rb_obj_classname(kdtree), (void*)kdtree, kdtreep->len);
431
+ sprintf(buf, "#<%s:%p nodes=%d>", rb_obj_classname(kdtree), (void *)kdtree, kdtreep->len);
437
432
  return rb_str_new(buf, strlen(buf));
438
433
  }
439
434
 
@@ -441,8 +436,7 @@ static VALUE kdtree_to_s(VALUE kdtree)
441
436
  // io helpers
442
437
  //
443
438
 
444
- static void read_all(VALUE io, void *buf, int len)
445
- {
439
+ static void read_all(VALUE io, void *buf, int len) {
446
440
  VALUE string = rb_funcall(io, id_read, 1, INT2NUM(len));
447
441
  if (NIL_P(string) || RSTRING_LEN(string) != len) {
448
442
  rb_raise(rb_eEOFError, "end of file reached");
@@ -450,8 +444,7 @@ static void read_all(VALUE io, void *buf, int len)
450
444
  memcpy(buf, RSTRING_PTR(string), len);
451
445
  }
452
446
 
453
- static void write_all(VALUE io, const void *buf, int len)
454
- {
447
+ static void write_all(VALUE io, const void *buf, int len) {
455
448
  rb_funcall(io, id_write, 1, rb_str_new(buf, len));
456
449
  }
457
450
 
@@ -487,8 +480,7 @@ static void write_all(VALUE io, const void *buf, int len)
487
480
  *
488
481
  * http://en.wikipedia.org/wiki/Kd-tree
489
482
  */
490
- void Init_kdtree()
491
- {
483
+ void Init_kdtree() {
492
484
  static VALUE clazz;
493
485
 
494
486
  clazz = rb_define_class("Kdtree", rb_cObject);
data/kdtree.gemspec CHANGED
@@ -1,24 +1,33 @@
1
1
  Gem::Specification.new do |s|
2
- s.name = "kdtree"
3
- s.version = "0.4"
2
+ s.name = "kdtree"
3
+ s.version = "0.5"
4
+ s.authors = ["Adam Doppelt"]
5
+ s.email = "amd@gurge.com"
4
6
 
5
- s.authors = ["Adam Doppelt"]
6
- s.email = ["amd@gurge.com"]
7
- s.homepage = "http://github.com/gurgeous/kdtree"
8
- s.license = "MIT"
9
- s.summary = "Blazingly fast, native 2d kdtree."
10
- s.description = <<EOF
11
- A kdtree is a data structure that makes it possible to quickly solve
12
- the nearest neighbor problem. This is a native 2d kdtree suitable for
13
- production use with millions of points.
14
- EOF
7
+ s.summary = "Blazingly fast, native 2d kdtree."
8
+ s.homepage = "http://github.com/gurgeous/kdtree"
9
+ s.description = <<~EOF
10
+ A kdtree is a data structure that makes it possible to quickly solve
11
+ the nearest neighbor problem. This is a native 2d kdtree suitable for
12
+ production use with millions of points.
13
+ EOF
14
+ s.license = "MIT"
15
+ s.required_ruby_version = ">= 3.0.0"
16
+ s.metadata = {
17
+ "homepage_uri" => s.homepage,
18
+ "rubygems_mfa_required" => "true",
19
+ "source_code_uri" => s.homepage,
20
+ }
15
21
 
16
- s.rubyforge_project = "kdtree"
17
- s.add_development_dependency "minitest", "~> 5.0"
18
- s.add_development_dependency "rake-compiler", "~> 1.0"
22
+ s.files = %w[
23
+ ext/kdtree/extconf.rb
24
+ ext/kdtree/kdtree.c
25
+ kdtree.gemspec
26
+ lib/kdtree.rb
27
+ LICENSE
28
+ README.md
29
+ ]
19
30
 
20
- s.files = `git ls-files`.split("\n")
21
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
31
  s.extensions = ["ext/kdtree/extconf.rb"]
23
32
  s.require_paths = ["lib"]
24
33
  end
metadata CHANGED
@@ -1,70 +1,39 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kdtree
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.4'
4
+ version: '0.5'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Doppelt
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-28 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: minitest
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '5.0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '5.0'
27
- - !ruby/object:Gem::Dependency
28
- name: rake-compiler
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '1.0'
11
+ date: 2025-05-01 00:00:00.000000000 Z
12
+ dependencies: []
41
13
  description: |
42
14
  A kdtree is a data structure that makes it possible to quickly solve
43
15
  the nearest neighbor problem. This is a native 2d kdtree suitable for
44
16
  production use with millions of points.
45
- email:
46
- - amd@gurge.com
17
+ email: amd@gurge.com
47
18
  executables: []
48
19
  extensions:
49
20
  - ext/kdtree/extconf.rb
50
21
  extra_rdoc_files: []
51
22
  files:
52
- - ".gitignore"
53
- - ".travis.yml"
54
- - Gemfile
55
23
  - LICENSE
56
24
  - README.md
57
- - Rakefile
58
25
  - ext/kdtree/extconf.rb
59
26
  - ext/kdtree/kdtree.c
60
27
  - kdtree.gemspec
61
28
  - lib/kdtree.rb
62
- - test/test_kdtree.rb
63
29
  homepage: http://github.com/gurgeous/kdtree
64
30
  licenses:
65
31
  - MIT
66
- metadata: {}
67
- post_install_message:
32
+ metadata:
33
+ homepage_uri: http://github.com/gurgeous/kdtree
34
+ rubygems_mfa_required: 'true'
35
+ source_code_uri: http://github.com/gurgeous/kdtree
36
+ post_install_message:
68
37
  rdoc_options: []
69
38
  require_paths:
70
39
  - lib
@@ -72,17 +41,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
72
41
  requirements:
73
42
  - - ">="
74
43
  - !ruby/object:Gem::Version
75
- version: '0'
44
+ version: 3.0.0
76
45
  required_rubygems_version: !ruby/object:Gem::Requirement
77
46
  requirements:
78
47
  - - ">="
79
48
  - !ruby/object:Gem::Version
80
49
  version: '0'
81
50
  requirements: []
82
- rubyforge_project: kdtree
83
- rubygems_version: 2.6.11
84
- signing_key:
51
+ rubygems_version: 3.5.16
52
+ signing_key:
85
53
  specification_version: 4
86
54
  summary: Blazingly fast, native 2d kdtree.
87
- test_files:
88
- - test/test_kdtree.rb
55
+ test_files: []
data/.gitignore DELETED
@@ -1,6 +0,0 @@
1
- *.gem
2
- .ruby-version
3
- Gemfile.lock
4
- lib/*.so
5
- lib/kdtree.bundle
6
- tmp
data/.travis.yml DELETED
@@ -1,7 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.0.0
4
- - 2.1.0
5
- - 2.2.0
6
- - 2.3.0
7
- - 2.4.0
data/Gemfile DELETED
@@ -1,2 +0,0 @@
1
- source "http://rubygems.org"
2
- gemspec
data/Rakefile DELETED
@@ -1,41 +0,0 @@
1
- require "bundler/setup"
2
- require "rake/extensiontask"
3
- require "rake/testtask"
4
-
5
- # load the spec, we use it below
6
- spec = Gem::Specification.load("kdtree.gemspec")
7
-
8
- #
9
- # gem
10
- #
11
-
12
- task :build do
13
- system "gem build --quiet kdtree.gemspec"
14
- end
15
-
16
- task install: :build do
17
- system "sudo gem install --quiet kdtree-#{spec.version}.gem"
18
- end
19
-
20
- task release: :build do
21
- system "git tag -a #{spec.version} -m 'Tagging #{spec.version}'"
22
- system "git push --tags"
23
- system "gem push kdtree-#{spec.version}.gem"
24
- end
25
-
26
- #
27
- # rake-compiler
28
- #
29
-
30
- Rake::ExtensionTask.new("kdtree", spec)
31
-
32
-
33
- #
34
- # testing
35
- #
36
-
37
- Rake::TestTask.new(:test) do |test|
38
- test.libs << "test"
39
- end
40
- task test: :compile
41
- task default: :test
data/test/test_kdtree.rb DELETED
@@ -1,148 +0,0 @@
1
- require "benchmark"
2
- require "kdtree"
3
- require "tempfile"
4
- require "minitest/autorun"
5
-
6
- #
7
- # create a tree
8
- #
9
-
10
- class KdtreeTest < Minitest::Test
11
- TMP = "#{Dir.tmpdir}/kdtree_test"
12
-
13
- def setup
14
- @points = (0...1000).map { |i| [rand_coord, rand_coord, i] }
15
- @kdtree = Kdtree.new(@points)
16
- end
17
-
18
- def teardown
19
- File.unlink(TMP) if File.exist?(TMP)
20
- end
21
-
22
- def test_nearest
23
- 100.times do
24
- pt = [rand_coord, rand_coord]
25
-
26
- # kdtree search
27
- id = @kdtree.nearest(pt[0], pt[1])
28
- kdpt = @points[id]
29
-
30
- # slow search
31
- sortpt = @points.sort_by { |i| distance(i, pt) }.first
32
-
33
- # assert
34
- kdd = distance(kdpt, pt)
35
- sortd = distance(sortpt, pt)
36
- assert((kdd - sortd).abs < 0.0000001, "kdtree didn't return the closest result")
37
- end
38
- end
39
-
40
- def test_nearestk
41
- 100.times do
42
- pt = [rand_coord, rand_coord]
43
-
44
- # kdtree search
45
- list = @kdtree.nearestk(pt[0], pt[1], 5)
46
- kdpt = @points[list.last]
47
-
48
- # slow search
49
- sortpt = @points.sort_by { |i| distance(i, pt) }[list.length - 1]
50
-
51
- # assert
52
- kdd = distance(kdpt, pt)
53
- sortd = distance(sortpt, pt)
54
- assert((kdd - sortd).abs < 0.0000001, "kdtree didn't return the closest result")
55
- end
56
- end
57
-
58
- def test_persist
59
- # write
60
- File.open(TMP, "w") { |f| @kdtree.persist(f) }
61
- # read
62
- kdtree2 = File.open(TMP, "r") { |f| Kdtree.new(f) }
63
-
64
- # now test some random points
65
- 100.times do
66
- pt = [rand_coord, rand_coord]
67
- id1 = @kdtree.nearest(*pt)
68
- id2 = kdtree2.nearest(*pt)
69
- assert(id1 == id2, "kdtree2 differed from kdtree")
70
- end
71
- end
72
-
73
- def test_bad_magic
74
- File.open(TMP, "w") { |f| f.puts "That ain't right" }
75
- assert_raises RuntimeError do
76
- File.open(TMP, "r") { |f| Kdtree.new(f) }
77
- end
78
- end
79
-
80
- def test_eof
81
- File.open(TMP, "w") { |f| @kdtree.persist(f) }
82
- bytes = File.read(TMP)
83
-
84
- [2, 10, 100].each do |len|
85
- File.open(TMP, "w") { |f| f.write(bytes[0, len]) }
86
- assert_raises EOFError do
87
- File.open(TMP, "r") { |f| Kdtree.new(f) }
88
- end
89
- end
90
- end
91
-
92
- def dont_test_speed
93
- sizes = [1, 100, 1000, 10000, 100000, 1000000]
94
- ks = [1, 5, 50, 255]
95
- sizes.each do |s|
96
- points = (0...s).map { |i| [rand_coord, rand_coord, i] }
97
-
98
- # build
99
- Benchmark.bm(17) do |bm|
100
- kdtree = nil
101
- bm.report "build" do
102
- kdtree = Kdtree.new(points)
103
- end
104
- bm.report "persist" do
105
- File.open(TMP, "w") { |f| kdtree.persist(f) }
106
- end
107
- bm.report "read" do
108
- File.open(TMP, "r") { |f| Kdtree.new(f) }
109
- end
110
-
111
- ks.each do |k|
112
- bm.report "100 queries (#{k})" do
113
- 100.times do
114
- if k == 1
115
- kdtree.nearest(rand_coord, rand_coord)
116
- else
117
- kdtree.nearestk(rand_coord, rand_coord, k)
118
- end
119
- end
120
- end
121
- end
122
- end
123
- puts
124
- end
125
- end
126
-
127
- protected
128
-
129
- def distance(a, b)
130
- x, y = a[0] - b[0], a[1] - b[1]
131
- x * x + y * y
132
- end
133
-
134
- def rand_coord
135
- rand(0) * 10 - 5
136
- end
137
- end
138
-
139
- # running dont_test_speed on my i5 2.8ghz:
140
- #
141
- # user system total real
142
- # build 3.350000 0.020000 3.370000 ( 3.520528)
143
- # persist 0.150000 0.020000 0.170000 ( 0.301963)
144
- # read 0.280000 0.000000 0.280000 ( 0.432676)
145
- # 100 queries (1) 0.000000 0.000000 0.000000 ( 0.000319)
146
- # 100 queries (5) 0.000000 0.000000 0.000000 ( 0.000412)
147
- # 100 queries (50) 0.000000 0.000000 0.000000 ( 0.001417)
148
- # 100 queries (255) 0.000000 0.000000 0.000000 ( 0.006268)