bribera-rubyvor 0.0.4 → 0.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.
- data/Manifest.txt +1 -1
- data/Rakefile +1 -2
- data/ext/output.c +2 -9
- data/ext/rb_cComputation.c +15 -15
- data/ext/rb_cPoint.c +14 -0
- data/ext/rb_cPriorityQueue.c +30 -16
- data/ext/ruby_vor.c +66 -11
- data/ext/ruby_vor.h +15 -11
- data/lib/ruby_vor/computation.rb +49 -34
- data/lib/ruby_vor/point.rb +0 -5
- data/lib/ruby_vor/priority_queue.rb +7 -8
- data/lib/ruby_vor/version.rb +1 -1
- data/rubyvor.gemspec +3 -3
- data/test/test_computation.rb +29 -2
- data/test/test_priority_queue.rb +75 -18
- metadata +3 -3
data/Manifest.txt
CHANGED
@@ -10,12 +10,12 @@ ext/heap.c
|
|
10
10
|
ext/memory.c
|
11
11
|
ext/output.c
|
12
12
|
ext/rb_cComputation.c
|
13
|
+
ext/rb_cPoint.c
|
13
14
|
ext/rb_cPriorityQueue.c
|
14
15
|
ext/ruby_vor.c
|
15
16
|
ext/ruby_vor.h
|
16
17
|
ext/vdefs.h
|
17
18
|
ext/voronoi.c
|
18
|
-
ext/voronoi_interface.c
|
19
19
|
lib/ruby_vor.rb
|
20
20
|
lib/ruby_vor/computation.rb
|
21
21
|
lib/ruby_vor/point.rb
|
data/Rakefile
CHANGED
@@ -7,8 +7,7 @@ require './lib/ruby_vor/version.rb'
|
|
7
7
|
EXT = "ext/voronoi_interface.#{Hoe::DLEXT}"
|
8
8
|
|
9
9
|
Hoe.new('rubyvor', RubyVor::VERSION) do |p|
|
10
|
-
p.developer('Brendan Ribera', 'brendan.ribera+rubyvor@gmail.com')
|
11
|
-
|
10
|
+
p.developer('Brendan Ribera', 'brendan.ribera+rubyvor@gmail.com')
|
12
11
|
p.url = 'http://github.com/bribera/rubyvor'
|
13
12
|
|
14
13
|
# C extension goodness
|
data/ext/output.c
CHANGED
@@ -1,24 +1,17 @@
|
|
1
1
|
|
2
2
|
/*** OUTPUT.C ***/
|
3
3
|
|
4
|
-
|
4
|
+
#include <vdefs.h>
|
5
5
|
#include <stdio.h>
|
6
|
-
|
7
|
-
#include "vdefs.h"
|
6
|
+
#include <unistd.h>
|
8
7
|
|
9
8
|
VoronoiState rubyvorState;
|
10
9
|
|
11
10
|
static float pxmin, pxmax, pymin, pymax, cradius;
|
12
11
|
|
13
12
|
void openpl(void) {}
|
14
|
-
|
15
|
-
#pragma argsused
|
16
13
|
void line(float ax, float ay, float bx, float by) {}
|
17
|
-
|
18
|
-
#pragma argsused
|
19
14
|
void circle(float ax, float ay, float radius) {}
|
20
|
-
|
21
|
-
#pragma argsused
|
22
15
|
void range(float pxmin, float pxmax, float pymin, float pymax) {}
|
23
16
|
|
24
17
|
void
|
data/ext/rb_cComputation.c
CHANGED
@@ -8,18 +8,16 @@ static Site * nextone(void);
|
|
8
8
|
static int scomp(const void *, const void *);
|
9
9
|
|
10
10
|
//
|
11
|
-
//
|
11
|
+
// See ruby_vor.c for RDOC
|
12
12
|
//
|
13
13
|
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
* It is limited to 2-dimensional space, therefore it expects to receive an array of objects that respond to 'x' and 'y' methods.
|
20
|
-
*/
|
15
|
+
//
|
16
|
+
// Class methods for RubyVor::VDDT::Computation
|
17
|
+
//
|
18
|
+
|
21
19
|
VALUE
|
22
|
-
|
20
|
+
RubyVor_from_points(VALUE self, VALUE pointsArray)
|
23
21
|
{
|
24
22
|
//VALUE returnValue;
|
25
23
|
VALUE * inPtr, newComp;
|
@@ -121,16 +119,17 @@ from_points(VALUE self, VALUE pointsArray)
|
|
121
119
|
|
122
120
|
|
123
121
|
//
|
124
|
-
// Instance methods
|
122
|
+
// Instance methods
|
125
123
|
//
|
126
124
|
|
125
|
+
/*
|
127
126
|
VALUE
|
128
|
-
|
127
|
+
RubyVor_minimum_spanning_tree(int argc, VALUE *argv, VALUE self)
|
129
128
|
{
|
130
129
|
VALUE dist_proc, nodes, nnGraph, points, queue, tmpHash, tmpArray, adjList, latestAddition;
|
131
130
|
long i, j;
|
132
131
|
|
133
|
-
|
132
|
+
// 0 mandatory, 1 optional
|
134
133
|
rb_scan_args(argc, argv, "01", &dist_proc);
|
135
134
|
|
136
135
|
if (NIL_P(dist_proc)) {
|
@@ -144,7 +143,7 @@ minimum_spanning_tree(int argc, VALUE *argv, VALUE self)
|
|
144
143
|
points = rb_iv_get(self, "@points");
|
145
144
|
nodes = rb_ary_new2(RARRAY(points)->len);
|
146
145
|
queue = rb_eval_string("RubyVor::PriorityQueue.new(lambda{|a,b| a[:min_distance] < b[:min_distance]})");
|
147
|
-
nnGraph =
|
146
|
+
nnGraph = RubyVor_nn_graph(self);
|
148
147
|
|
149
148
|
for (i=0; i < RARRAY(points)->len; i++) {
|
150
149
|
tmpHash = rb_hash_new();
|
@@ -155,7 +154,7 @@ minimum_spanning_tree(int argc, VALUE *argv, VALUE self)
|
|
155
154
|
rb_hash_aset(tmpHash, ID2SYM(rb_intern("min_distance")), (i == 0) ? INT2FIX(0) : rb_const_get(rb_cFloat, rb_intern("MAX")));
|
156
155
|
// :parent => nil,
|
157
156
|
rb_hash_aset(tmpHash, ID2SYM(rb_intern("parent")), Qnil);
|
158
|
-
// :adjacency_list =>
|
157
|
+
// :adjacency_list => RubyVor_nn_graph[n].clone,
|
159
158
|
rb_hash_aset(tmpHash, ID2SYM(rb_intern("adjacency_list")), rb_funcall(RARRAY(nnGraph)->ptr[i], rb_intern("clone"), 0));
|
160
159
|
// :min_adjacency_list => [],
|
161
160
|
rb_hash_aset(tmpHash, ID2SYM(rb_intern("min_adjacency_list")), rb_ary_new());
|
@@ -185,13 +184,14 @@ minimum_spanning_tree(int argc, VALUE *argv, VALUE self)
|
|
185
184
|
|
186
185
|
return tmpArray;
|
187
186
|
}
|
187
|
+
*/
|
188
188
|
|
189
189
|
VALUE
|
190
|
-
|
190
|
+
RubyVor_nn_graph(VALUE self)
|
191
191
|
{
|
192
192
|
long i;
|
193
193
|
VALUE dtRaw, graph, points, * dtPtr, * tripletPtr, * graphPtr;
|
194
|
-
|
194
|
+
|
195
195
|
graph = rb_iv_get(self, "@nn_graph");
|
196
196
|
|
197
197
|
if (RTEST(graph))
|
data/ext/rb_cPoint.c
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <vdefs.h>
|
3
|
+
#include <ruby_vor.h>
|
4
|
+
#include <math.h>
|
5
|
+
|
6
|
+
/*
|
7
|
+
* Euclidean distance between two Points
|
8
|
+
*/
|
9
|
+
VALUE
|
10
|
+
RubyVor_distance_from(VALUE self, VALUE other)
|
11
|
+
{
|
12
|
+
return rb_float_new(sqrt(pow(NUM2DBL(rb_iv_get(self, "@x")) - NUM2DBL(rb_iv_get(other, "@x")), 2.0) +
|
13
|
+
pow(NUM2DBL(rb_iv_get(self, "@y")) - NUM2DBL(rb_iv_get(other, "@y")), 2.0)));
|
14
|
+
}
|
data/ext/rb_cPriorityQueue.c
CHANGED
@@ -2,37 +2,47 @@
|
|
2
2
|
#include <vdefs.h>
|
3
3
|
#include <ruby_vor.h>
|
4
4
|
|
5
|
-
|
5
|
+
//
|
6
|
+
// Instance methods for RubyVor::VDDT::PriorityQueue
|
7
|
+
//
|
8
|
+
|
9
|
+
|
10
|
+
static VALUE
|
6
11
|
compare(VALUE a, VALUE b)
|
7
12
|
{
|
8
13
|
double aD, bD;
|
9
14
|
ID minDistance;
|
10
15
|
minDistance = ID2SYM(rb_intern("min_distance"));
|
11
16
|
|
12
|
-
if (rb_class_of(a) ==
|
17
|
+
if (rb_class_of(a) == RubyVor_rb_cQueueItem)
|
13
18
|
aD = NUM2DBL(rb_funcall(a, rb_intern("priority"), 0));
|
14
19
|
else
|
15
|
-
|
20
|
+
rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)", rb_obj_classname(a), rb_class2name(RubyVor_rb_cQueueItem));
|
16
21
|
|
17
|
-
if (rb_class_of(b) ==
|
22
|
+
if (rb_class_of(b) == RubyVor_rb_cQueueItem)
|
18
23
|
bD = NUM2DBL(rb_funcall(b, rb_intern("priority"), 0));
|
19
24
|
else
|
20
|
-
|
25
|
+
rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)", rb_obj_classname(b), rb_class2name(RubyVor_rb_cQueueItem));
|
21
26
|
|
22
27
|
return RTEST(aD < bD);
|
23
28
|
}
|
24
29
|
|
25
30
|
VALUE
|
26
|
-
|
31
|
+
RubyVor_percolate_up(VALUE self, VALUE index)
|
27
32
|
{
|
28
33
|
VALUE item, data;
|
29
|
-
long i, j;
|
34
|
+
long i, j, size;
|
35
|
+
|
36
|
+
Check_Type(index, T_FIXNUM);
|
30
37
|
|
31
38
|
data = rb_iv_get(self, "@data");
|
32
39
|
Check_Type(data, T_ARRAY);
|
33
40
|
|
34
|
-
|
41
|
+
size = FIX2INT(rb_iv_get(self, "@size"));
|
42
|
+
i = FIX2INT(index) + 1;
|
35
43
|
|
44
|
+
if (i < 1 || i > size)
|
45
|
+
rb_raise(rb_eIndexError, "index %i out of range", i-1);
|
36
46
|
|
37
47
|
j = i / 2;
|
38
48
|
|
@@ -41,30 +51,34 @@ percolate_up(VALUE self, VALUE index)
|
|
41
51
|
while(j > 0 && compare(item, RARRAY(data)->ptr[j - 1]))
|
42
52
|
{
|
43
53
|
rb_ary_store(data, i-1, RARRAY(data)->ptr[j - 1]);
|
44
|
-
rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i));
|
54
|
+
rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i-1));
|
45
55
|
i = j;
|
46
56
|
j = j / 2;
|
47
57
|
}
|
48
58
|
|
49
59
|
rb_ary_store(data, i-1, item);
|
50
|
-
rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i));
|
60
|
+
rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i-1));
|
51
61
|
|
52
62
|
return Qnil;
|
53
63
|
}
|
54
64
|
|
55
65
|
|
56
66
|
VALUE
|
57
|
-
|
67
|
+
RubyVor_percolate_down(VALUE self, VALUE index)
|
58
68
|
{
|
59
69
|
VALUE item, data;
|
60
70
|
long i, j, k, size;
|
61
71
|
|
72
|
+
Check_Type(index, T_FIXNUM);
|
73
|
+
|
62
74
|
data = rb_iv_get(self, "@data");
|
63
75
|
Check_Type(data, T_ARRAY);
|
64
76
|
|
65
77
|
size = FIX2INT(rb_iv_get(self, "@size"));
|
66
|
-
i = FIX2INT(index);
|
78
|
+
i = FIX2INT(index) + 1;
|
67
79
|
|
80
|
+
if (i < 1 || i > size)
|
81
|
+
rb_raise(rb_eIndexError, "index %i out of range", i-1);
|
68
82
|
|
69
83
|
j = size / 2;
|
70
84
|
|
@@ -81,26 +95,26 @@ percolate_down(VALUE self, VALUE index)
|
|
81
95
|
else
|
82
96
|
{
|
83
97
|
rb_ary_store(data, i-1, RARRAY(data)->ptr[k - 1]);
|
84
|
-
rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i));
|
98
|
+
rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i-1));
|
85
99
|
i = k;
|
86
100
|
}
|
87
101
|
}
|
88
102
|
|
89
103
|
rb_ary_store(data, i-1, item);
|
90
|
-
rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i));
|
104
|
+
rb_funcall(RARRAY(data)->ptr[i-1], rb_intern("index="), 1, INT2FIX(i-1));
|
91
105
|
|
92
106
|
return Qnil;
|
93
107
|
}
|
94
108
|
|
95
109
|
|
96
110
|
VALUE
|
97
|
-
|
111
|
+
RubyVor_heapify(VALUE self)
|
98
112
|
{
|
99
113
|
long i, size;
|
100
114
|
size = FIX2INT(rb_iv_get(self, "@size"));
|
101
115
|
|
102
116
|
for(i = size / 2; i >= 1; i--)
|
103
|
-
|
117
|
+
RubyVor_percolate_down(self, INT2FIX(i-1));
|
104
118
|
|
105
119
|
return Qnil;
|
106
120
|
}
|
data/ext/ruby_vor.c
CHANGED
@@ -2,6 +2,9 @@
|
|
2
2
|
#include <vdefs.h>
|
3
3
|
#include <ruby_vor.h>
|
4
4
|
|
5
|
+
//
|
6
|
+
// Extension initialization
|
7
|
+
//
|
5
8
|
void
|
6
9
|
Init_ruby_vor(void)
|
7
10
|
{
|
@@ -12,30 +15,82 @@ Init_ruby_vor(void)
|
|
12
15
|
/*
|
13
16
|
* Main RubyVor namespace.
|
14
17
|
*/
|
15
|
-
|
18
|
+
RubyVor_rb_mRubyVor = rb_define_module("RubyVor");
|
16
19
|
|
17
20
|
|
18
21
|
/*
|
19
22
|
* Voronoi Digram and Delaunay Triangulation namespace.
|
20
23
|
*/
|
21
|
-
|
24
|
+
RubyVor_rb_mVDDT = rb_define_module_under(RubyVor_rb_mRubyVor, "VDDT");
|
22
25
|
|
23
26
|
|
24
27
|
/*
|
25
28
|
* Class representing a VD/DT computation based on a set of 2-dimensional points
|
26
29
|
*/
|
27
|
-
|
28
|
-
rb_define_singleton_method(
|
29
|
-
rb_define_method(
|
30
|
-
//rb_define_method(
|
30
|
+
RubyVor_rb_cComputation = rb_define_class_under(RubyVor_rb_mVDDT, "Computation", rb_cObject);
|
31
|
+
rb_define_singleton_method(RubyVor_rb_cComputation, "from_points", RubyVor_from_points, 1);
|
32
|
+
rb_define_method(RubyVor_rb_cComputation, "nn_graph", RubyVor_nn_graph, 0);
|
33
|
+
// rb_define_method(RubyVor_rb_cComputation, "minimum_spanning_tree", RubyVor_minimum_spanning_tree, -1);
|
31
34
|
|
32
35
|
|
33
36
|
/*
|
34
37
|
* A priority queue with a customizable heap-order property.
|
35
38
|
*/
|
36
|
-
|
37
|
-
|
38
|
-
rb_define_method(
|
39
|
-
rb_define_method(
|
40
|
-
rb_define_method(
|
39
|
+
RubyVor_rb_cPriorityQueue = rb_define_class_under(RubyVor_rb_mRubyVor, "PriorityQueue", rb_cObject);
|
40
|
+
RubyVor_rb_cQueueItem = rb_define_class_under(RubyVor_rb_cPriorityQueue, "QueueItem", rb_cObject);
|
41
|
+
rb_define_method(RubyVor_rb_cPriorityQueue, "percolate_up", RubyVor_percolate_up, 1);
|
42
|
+
rb_define_method(RubyVor_rb_cPriorityQueue, "percolate_down", RubyVor_percolate_down, 1);
|
43
|
+
rb_define_method(RubyVor_rb_cPriorityQueue, "heapify", RubyVor_heapify, 0);
|
44
|
+
|
45
|
+
|
46
|
+
/*
|
47
|
+
* A simple Point class
|
48
|
+
*/
|
49
|
+
RubyVor_rb_cPoint = rb_define_class_under(RubyVor_rb_mRubyVor, "Point", rb_cObject);
|
50
|
+
rb_define_method(RubyVor_rb_cPoint, "distance_from", RubyVor_distance_from, 1);
|
41
51
|
}
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
//
|
57
|
+
// Method declarations duplicated here for RDOC
|
58
|
+
//
|
59
|
+
|
60
|
+
/*
|
61
|
+
* Compute the voronoi diagram and delaunay triangulation from a set of points.
|
62
|
+
*
|
63
|
+
* This implementation uses Steven Fortune's sweepline algorithm, which runs in O(n log n) time and O(n) space.
|
64
|
+
* It is limited to 2-dimensional space, therefore it expects to receive an array of objects that respond to 'x' and 'y' methods.
|
65
|
+
*/
|
66
|
+
VALUE RubyVor_from_points(VALUE, VALUE);
|
67
|
+
|
68
|
+
/*
|
69
|
+
* Compute the nearest-neighbor graph using the existing Delaunay triangulation.
|
70
|
+
*/
|
71
|
+
VALUE RubyVor_nn_graph(VALUE);
|
72
|
+
|
73
|
+
/*
|
74
|
+
* Compute the MST for the nearest-nearest graph using a Priority Queue and Prim's algorithm.
|
75
|
+
*/
|
76
|
+
// VALUE RubyVor_minimum_spanning_tree(int, VALUE*, VALUE);
|
77
|
+
|
78
|
+
/*
|
79
|
+
* Move from the given index up, restoring the heap-order property.
|
80
|
+
*/
|
81
|
+
VALUE RubyVor_percolate_up(VALUE, VALUE);
|
82
|
+
|
83
|
+
/*
|
84
|
+
* Move from the index down, restoring the heap-order property.
|
85
|
+
*/
|
86
|
+
VALUE RubyVor_percolate_down(VALUE, VALUE);
|
87
|
+
|
88
|
+
/*
|
89
|
+
* Restore the heap-order property for a randomly ordered array of entries.
|
90
|
+
*/
|
91
|
+
VALUE RubyVor_heapify(VALUE);
|
92
|
+
|
93
|
+
/*
|
94
|
+
* Compute the Euclidean distance between two points.
|
95
|
+
*/
|
96
|
+
VALUE RubyVor_distance_from(VALUE, VALUE);
|
data/ext/ruby_vor.h
CHANGED
@@ -4,20 +4,24 @@
|
|
4
4
|
extern VoronoiState rubyvorState;
|
5
5
|
|
6
6
|
/* Base modules */
|
7
|
-
VALUE
|
8
|
-
VALUE
|
7
|
+
VALUE RubyVor_rb_mRubyVor;
|
8
|
+
VALUE RubyVor_rb_mVDDT;
|
9
9
|
|
10
10
|
/* Computation */
|
11
|
-
VALUE
|
12
|
-
VALUE
|
13
|
-
VALUE
|
14
|
-
VALUE minimum_spanning_tree(int, VALUE*, VALUE);
|
11
|
+
VALUE RubyVor_rb_cComputation;
|
12
|
+
VALUE RubyVor_from_points(VALUE, VALUE);
|
13
|
+
VALUE RubyVor_nn_graph(VALUE);
|
14
|
+
// VALUE minimum_spanning_tree(int, VALUE*, VALUE);
|
15
15
|
|
16
16
|
/* PriorityQueue */
|
17
|
-
VALUE
|
18
|
-
VALUE
|
19
|
-
VALUE
|
20
|
-
VALUE
|
21
|
-
VALUE
|
17
|
+
VALUE RubyVor_rb_cPriorityQueue;
|
18
|
+
VALUE RubyVor_rb_cQueueItem;
|
19
|
+
VALUE RubyVor_percolate_up(VALUE, VALUE);
|
20
|
+
VALUE RubyVor_percolate_down(VALUE, VALUE);
|
21
|
+
VALUE RubyVor_heapify(VALUE);
|
22
|
+
|
23
|
+
/* Point */
|
24
|
+
VALUE RubyVor_rb_cPoint;
|
25
|
+
VALUE RubyVor_distance_from(VALUE, VALUE);
|
22
26
|
|
23
27
|
#endif
|
data/lib/ruby_vor/computation.rb
CHANGED
@@ -20,15 +20,14 @@ module RubyVor
|
|
20
20
|
|
21
21
|
clusters = []
|
22
22
|
nodes = (0..points.length-1).to_a
|
23
|
-
visited = []
|
24
|
-
|
23
|
+
visited = [false] * points.length
|
24
|
+
graph = []
|
25
25
|
v = 0
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
|
27
|
+
nn_graph.each_with_index do |neighbors,v|
|
28
|
+
graph[v] = neighbors.select do |neighbor|
|
29
|
+
dist_proc[points[v], points[neighbor]] < max_distance
|
29
30
|
end
|
30
|
-
v += 1
|
31
|
-
neighbors
|
32
31
|
end
|
33
32
|
|
34
33
|
until nodes.empty?
|
@@ -63,37 +62,49 @@ module RubyVor
|
|
63
62
|
nodes = []
|
64
63
|
q = RubyVor::PriorityQueue.new
|
65
64
|
(0..points.length-1).to_a.map do |n|
|
66
|
-
q.push(
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
q.data.each do |n|
|
76
|
-
n.data[:adjacency_list].map!{|v| q.data[v]}
|
77
|
-
nodes.push(n)
|
65
|
+
q.push([
|
66
|
+
n, # :node == 0
|
67
|
+
nil, # :parent == 1
|
68
|
+
nn_graph[n].clone, # :adjacency_list == 2
|
69
|
+
[], # :min_adjacency_list == 3
|
70
|
+
true # :in_q == 4
|
71
|
+
],
|
72
|
+
# Set min_distance of first node to 0, all others (effectively) to Infinity.
|
73
|
+
(n == 0) ? 0.0 : Float::MAX)
|
78
74
|
end
|
79
75
|
|
80
|
-
|
81
|
-
|
76
|
+
# Adjacency list accces
|
77
|
+
nodes = q.data.clone
|
78
|
+
|
79
|
+
# We have now prepped to run through Prim's algorithm.
|
80
|
+
while latest_addition = q.pop
|
81
|
+
# check :in_q
|
82
|
+
latest_addition.data[4] = false
|
82
83
|
|
83
|
-
|
84
|
-
|
85
|
-
|
84
|
+
# check :parent
|
85
|
+
if latest_addition.data[1]
|
86
|
+
# push this node into :adjacency_list of :parent
|
87
|
+
latest_addition.data[1].data[3].push(latest_addition)
|
88
|
+
# push :parent into :adjacency_list of this node
|
89
|
+
latest_addition.data[3].push(latest_addition.data[1])
|
86
90
|
end
|
87
91
|
|
88
|
-
latest_addition.data[
|
89
|
-
|
90
|
-
|
92
|
+
latest_addition.data[2].each do |adjacent|
|
93
|
+
# grab indexed node
|
94
|
+
adjacent = nodes[adjacent]
|
91
95
|
|
92
|
-
|
93
|
-
|
96
|
+
# check :in_q -- only look at new nodes
|
97
|
+
if adjacent.data[4]
|
98
|
+
# compare points by :node -- adjacent against current
|
99
|
+
adjacent_distance = dist_proc[ points[latest_addition.data[0]], points[adjacent.data[0]] ]
|
100
|
+
|
101
|
+
# if the new distance is better than our current priorty, exchange them
|
94
102
|
if adjacent_distance < adjacent.priority
|
95
|
-
|
103
|
+
# set new :parent
|
104
|
+
adjacent.data[1] = latest_addition
|
105
|
+
# update priority
|
96
106
|
adjacent.priority = adjacent_distance
|
107
|
+
# percolate up into correct position
|
97
108
|
q.percolate_up(adjacent.index)
|
98
109
|
end
|
99
110
|
end
|
@@ -103,15 +114,19 @@ module RubyVor
|
|
103
114
|
|
104
115
|
|
105
116
|
nodes.map! do |n|
|
106
|
-
n.data[
|
117
|
+
n.data[3].inject({}) do |h,v|
|
118
|
+
h[v.data[0]] = v.priority
|
119
|
+
h
|
120
|
+
end
|
107
121
|
end
|
108
122
|
end
|
109
123
|
|
110
124
|
def cluster_by_size(sizes=[])
|
111
125
|
# TODO
|
112
|
-
# * Create a minimum_spanning_tree routine to:
|
113
|
-
# 1. compute weights (should be done for us in C?)
|
114
|
-
# 2. Use Prim's algorithm for computation
|
126
|
+
# * (DONE) Create a minimum_spanning_tree routine to:
|
127
|
+
# 1. (DONE) compute weights (should be done for us in C?)
|
128
|
+
# 2. (DONE) Use Prim's algorithm for computation
|
129
|
+
#
|
115
130
|
# * Take MST, and
|
116
131
|
# 1. For n in sizes (taken in descending order), delete the n most expensive edges from MST
|
117
132
|
# * use a MaxHeap?
|
data/lib/ruby_vor/point.rb
CHANGED
@@ -3,10 +3,9 @@ module RubyVor
|
|
3
3
|
|
4
4
|
attr_reader :data, :size
|
5
5
|
|
6
|
-
def initialize(
|
7
|
-
@data =
|
8
|
-
@size =
|
9
|
-
|
6
|
+
def initialize()
|
7
|
+
@data = []
|
8
|
+
@size = 0
|
10
9
|
heapify()
|
11
10
|
end
|
12
11
|
|
@@ -20,20 +19,20 @@ module RubyVor
|
|
20
19
|
r = @data[0]
|
21
20
|
|
22
21
|
@data[0] = @data[@size-1]
|
23
|
-
@data[0].index =
|
22
|
+
@data[0].index = 0
|
24
23
|
@data.delete_at(@size-1)
|
25
24
|
|
26
25
|
@size -= 1
|
27
26
|
|
28
|
-
percolate_down(
|
27
|
+
percolate_down(0) if @size > 0
|
29
28
|
|
30
29
|
return r
|
31
30
|
end
|
32
31
|
|
33
|
-
def push(data, priority=
|
32
|
+
def push(data, priority=data)
|
34
33
|
@size += 1
|
35
34
|
@data[@size - 1] = QueueItem.new(priority, @size - 1, data)
|
36
|
-
percolate_up(@size)
|
35
|
+
percolate_up(@size - 1)
|
37
36
|
end
|
38
37
|
|
39
38
|
# Implemented in C
|
data/lib/ruby_vor/version.rb
CHANGED
data/rubyvor.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{rubyvor}
|
5
|
-
s.version = "0.0.
|
5
|
+
s.version = "0.0.5"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Brendan Ribera"]
|
9
|
-
s.date = %q{2008-12-
|
9
|
+
s.date = %q{2008-12-11}
|
10
10
|
s.description = %q{RubyVor provides efficient computation of Voronoi diagrams and Delaunay triangulation for a set of Ruby points. It is intended to function as a complemenet to GeoRuby. These structures can be used to compute a nearest-neighbor graph for a set of points. This graph can in turn be used for proximity-based clustering of the input points.}
|
11
11
|
s.email = ["brendan.ribera+rubyvor@gmail.com"]
|
12
12
|
s.extensions = ["ext/extconf.rb"]
|
13
13
|
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
|
14
|
-
s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "ext/Doc", "ext/edgelist.c", "ext/extconf.rb", "ext/geometry.c", "ext/heap.c", "ext/memory.c", "ext/output.c", "ext/rb_cComputation.c", "ext/
|
14
|
+
s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "ext/Doc", "ext/edgelist.c", "ext/extconf.rb", "ext/geometry.c", "ext/heap.c", "ext/memory.c", "ext/output.c", "ext/rb_cComputation.c", "ext/rb_cPoint.c", "ext/rb_cPriorityQueue.c", "ext/ruby_vor.c", "ext/ruby_vor.h", "ext/vdefs.h", "ext/voronoi.c", "lib/ruby_vor.rb", "lib/ruby_vor/computation.rb", "lib/ruby_vor/point.rb", "lib/ruby_vor/priority_queue.rb", "lib/ruby_vor/version.rb", "rubyvor.gemspec", "test/test_computation.rb", "test/test_priority_queue.rb", "test/test_voronoi_interface.rb"]
|
15
15
|
s.has_rdoc = true
|
16
16
|
s.homepage = %q{http://github.com/bribera/rubyvor}
|
17
17
|
s.rdoc_options = ["--main", "README.txt"]
|
data/test/test_computation.rb
CHANGED
@@ -53,9 +53,11 @@ class TestComputation < MiniTest::Unit::TestCase
|
|
53
53
|
[0,2],
|
54
54
|
[1]
|
55
55
|
]
|
56
|
+
computed_mst = comp.minimum_spanning_tree
|
56
57
|
|
58
|
+
# Assert nodes are correct
|
57
59
|
assert_equal expected_mst.map{|v| v.sort}.sort, \
|
58
|
-
|
60
|
+
computed_mst.map{|v| v.keys.sort}.sort
|
59
61
|
end
|
60
62
|
|
61
63
|
def test_advanced_mst
|
@@ -119,8 +121,10 @@ class TestComputation < MiniTest::Unit::TestCase
|
|
119
121
|
[22,24], # 23
|
120
122
|
[23] # 24
|
121
123
|
]
|
124
|
+
computed_mst = comp.minimum_spanning_tree
|
125
|
+
|
122
126
|
assert_equal expected_mst.map{|v| v.sort}.sort, \
|
123
|
-
|
127
|
+
computed_mst.map{|v| v.keys.sort}.sort
|
124
128
|
end
|
125
129
|
|
126
130
|
def test_cluster_by_distance
|
@@ -146,6 +150,29 @@ class TestComputation < MiniTest::Unit::TestCase
|
|
146
150
|
|
147
151
|
end
|
148
152
|
|
153
|
+
def test_bad_data
|
154
|
+
assert_raises TypeError do
|
155
|
+
comp = RubyVor::VDDT::Computation.from_points([RubyVor::Point.new(1,1), RubyVor::Point.new(21,3), RubyVor::Point.new(2,:s)])
|
156
|
+
end
|
157
|
+
|
158
|
+
assert_raises TypeError do
|
159
|
+
comp = RubyVor::VDDT::Computation.from_points(RubyVor::Point.new(21,3))
|
160
|
+
end
|
161
|
+
|
162
|
+
assert_raises RuntimeError do
|
163
|
+
comp = RubyVor::VDDT::Computation.from_points([RubyVor::Point.new(1,1), RubyVor::Point.new(21,3), nil])
|
164
|
+
end
|
165
|
+
|
166
|
+
assert_raises RuntimeError do
|
167
|
+
comp = RubyVor::VDDT::Computation.from_points([])
|
168
|
+
end
|
169
|
+
|
170
|
+
comp = RubyVor::VDDT::Computation.from_points([RubyVor::Point.new(1,1), RubyVor::Point.new(21,3), RubyVor::Point.new(2,1.5)])
|
171
|
+
assert_raises ArgumentError do
|
172
|
+
cl = comp.cluster_by_distance(nil)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
149
176
|
#
|
150
177
|
# A few helper methods
|
151
178
|
#
|
data/test/test_priority_queue.rb
CHANGED
@@ -9,7 +9,7 @@ class TestPriorityQueue < MiniTest::Unit::TestCase
|
|
9
9
|
q = RubyVor::PriorityQueue.new
|
10
10
|
|
11
11
|
items = [1,2,3,4,5,6,99,4,-20,101,5412,2,-1,-1,-1,33.0,0,55,7,12321,123.123,-123.123,0,0,0]
|
12
|
-
items.each{|i| q.push(i
|
12
|
+
items.each{|i| q.push(i)}
|
13
13
|
|
14
14
|
items.sort!
|
15
15
|
idx = 0
|
@@ -31,26 +31,83 @@ class TestPriorityQueue < MiniTest::Unit::TestCase
|
|
31
31
|
def test_heapify
|
32
32
|
q = RubyVor::PriorityQueue.new
|
33
33
|
|
34
|
-
|
34
|
+
# Create a randomized data set.
|
35
|
+
#
|
36
|
+
# Not ideal for unit tests, since they *should* be done
|
37
|
+
# on static data so that failure/success is deterministic...
|
38
|
+
# but works for me.
|
35
39
|
|
36
|
-
q.
|
37
|
-
|
38
|
-
|
39
|
-
q.data[7] = RubyVor::PriorityQueue::QueueItem.new(0.9, 7, 0.9)
|
40
|
-
q.data.sort!{|a,b| rand(3)-1}
|
41
|
-
|
40
|
+
100.times{ q.push(rand * 10000.0 - 5000.0)}
|
41
|
+
|
42
|
+
# Set things right.
|
42
43
|
q.heapify()
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
assert_equal 10, q.pop.data
|
50
|
-
assert_equal 10, q.pop.data
|
51
|
-
assert_equal 10, q.pop.data
|
52
|
-
assert_equal 10, q.pop.data
|
53
|
-
assert_equal 100, q.pop.data
|
45
|
+
old_n = -1.0 * Float::MAX
|
46
|
+
while n = q.pop
|
47
|
+
assert n.priority >= old_n
|
48
|
+
old_n = n.priority
|
49
|
+
end
|
54
50
|
end
|
51
|
+
|
52
|
+
def test_bad_data
|
53
|
+
q = RubyVor::PriorityQueue.new
|
54
|
+
10.times { q.push(rand * 100.0 - 50.0) }
|
55
55
|
|
56
|
+
#
|
57
|
+
# Heapify
|
58
|
+
#
|
59
|
+
old_data = q.data[1]
|
60
|
+
q.data[1] = 45
|
61
|
+
assert_raises TypeError do
|
62
|
+
q.heapify()
|
63
|
+
end
|
64
|
+
q.data[1] = old_data
|
65
|
+
assert_nothing_raised do
|
66
|
+
q.heapify()
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
#
|
71
|
+
# Percolation
|
72
|
+
#
|
73
|
+
[100, -100].each do |i|
|
74
|
+
assert_raises IndexError do
|
75
|
+
q.percolate_up(i)
|
76
|
+
end
|
77
|
+
assert_raises IndexError do
|
78
|
+
q.percolate_down(i)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
[:x, Class, nil, false].each do |i|
|
82
|
+
assert_raises TypeError do
|
83
|
+
q.percolate_up(i)
|
84
|
+
end
|
85
|
+
assert_raises TypeError do
|
86
|
+
q.percolate_down(i)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
[0,1,2,3].each do |i|
|
90
|
+
assert_nothing_raised do
|
91
|
+
q.percolate_up(i)
|
92
|
+
end
|
93
|
+
assert_nothing_raised do
|
94
|
+
q.percolate_down(i)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def assert_nothing_raised(&b)
|
103
|
+
begin
|
104
|
+
yield
|
105
|
+
rescue Exception => e
|
106
|
+
flunk "#{mu_pp(e)} exception encountered, expected no exceptions"
|
107
|
+
return
|
108
|
+
end
|
109
|
+
pass()
|
110
|
+
end
|
56
111
|
end
|
112
|
+
|
113
|
+
MiniTest::Unit.autorun
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bribera-rubyvor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brendan Ribera
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-12-
|
12
|
+
date: 2008-12-11 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -45,12 +45,12 @@ files:
|
|
45
45
|
- ext/memory.c
|
46
46
|
- ext/output.c
|
47
47
|
- ext/rb_cComputation.c
|
48
|
+
- ext/rb_cPoint.c
|
48
49
|
- ext/rb_cPriorityQueue.c
|
49
50
|
- ext/ruby_vor.c
|
50
51
|
- ext/ruby_vor.h
|
51
52
|
- ext/vdefs.h
|
52
53
|
- ext/voronoi.c
|
53
|
-
- ext/voronoi_interface.c
|
54
54
|
- lib/ruby_vor.rb
|
55
55
|
- lib/ruby_vor/computation.rb
|
56
56
|
- lib/ruby_vor/point.rb
|