lulu 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.gitignore +1 -1
- data/ext/lulu/extconf.rb +3 -0
- data/ext/lulu/lulu.c +6 -6
- data/ext/lulu/marker.c +65 -65
- data/ext/lulu/marker.h +22 -22
- data/ext/lulu/merger.c +116 -154
- data/ext/lulu/merger.h +0 -2
- data/ext/lulu/pq.c +106 -179
- data/ext/lulu/pq.h +10 -13
- data/ext/lulu/qt.c +135 -191
- data/ext/lulu/qt.h +11 -10
- data/ext/lulu/test.c +221 -45
- data/ext/lulu/test.h +5 -0
- data/ext/lulu/utility.c +22 -26
- data/ext/lulu/utility.h +17 -14
- data/lib/lulu/version.rb +1 -1
- data/lulu.gemspec +10 -10
- metadata +6 -8
- data/ext/lulu/Makefile +0 -220
- data/lib/lulu/lulu.bundle +0 -0
data/ext/lulu/qt.h
CHANGED
@@ -11,9 +11,9 @@
|
|
11
11
|
#include "marker.h"
|
12
12
|
|
13
13
|
typedef struct node_s {
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
struct node_s *children;
|
15
|
+
MARKER **markers;
|
16
|
+
int marker_count, markers_size;
|
17
17
|
} NODE;
|
18
18
|
|
19
19
|
#define leaf_p(Node) ((Node)->children == NULL)
|
@@ -37,21 +37,22 @@ typedef struct node_s {
|
|
37
37
|
#define NE 3
|
38
38
|
|
39
39
|
typedef struct quadtree_s {
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
MARKER_COORD x, y;
|
41
|
+
MARKER_DISTANCE w, h;
|
42
|
+
int max_depth;
|
43
|
+
MARKER_INFO *info;
|
44
|
+
NODE root[1];
|
44
45
|
} QUADTREE;
|
45
46
|
|
46
47
|
#define QUADTREE_DECL(Name) QUADTREE Name[1]; qt_init(Name)
|
47
48
|
|
48
49
|
void qt_init(QUADTREE *qt);
|
49
|
-
void qt_setup(QUADTREE *qt, int max_depth,
|
50
|
+
void qt_setup(QUADTREE *qt, int max_depth,
|
51
|
+
MARKER_COORD x, MARKER_COORD y, MARKER_DISTANCE w, MARKER_DISTANCE h,
|
52
|
+
MARKER_INFO *info);
|
50
53
|
void qt_insert(QUADTREE *qt, MARKER *marker);
|
51
54
|
void qt_delete(QUADTREE *qt, MARKER *marker);
|
52
55
|
MARKER *qt_nearest(QUADTREE *qt, MARKER *marker);
|
53
56
|
int qt_nearest_wrt(MARKER *markers, QUADTREE *qt, int a);
|
54
|
-
void qt_clear(QUADTREE *qt);
|
55
|
-
int qt_test(int size);
|
56
57
|
|
57
58
|
#endif /* QT_H_ */
|
data/ext/lulu/test.c
CHANGED
@@ -5,78 +5,254 @@
|
|
5
5
|
* Author: generessler
|
6
6
|
*/
|
7
7
|
|
8
|
+
#ifdef UNIT_TESTS
|
9
|
+
|
8
10
|
#include <stdio.h>
|
9
11
|
#include <stdlib.h>
|
10
12
|
#include <stdarg.h>
|
11
13
|
#include <time.h>
|
14
|
+
#include <sys/time.h>
|
12
15
|
#include "test.h"
|
13
16
|
#include "utility.h"
|
14
17
|
|
18
|
+
double rand_double(void)
|
19
|
+
{
|
20
|
+
unsigned i = rand();
|
21
|
+
i = (i << 8) ^ (unsigned)rand();
|
22
|
+
i = (i << 8) ^ (unsigned)rand();
|
23
|
+
i = (i << 8) ^ (unsigned)rand();
|
24
|
+
return i / (256.0 * 256.0 * 256.0 * 256.0);
|
25
|
+
}
|
26
|
+
|
15
27
|
void emit_rectangle(FILE *f, double x, double y, double w, double h) {
|
16
|
-
|
28
|
+
fprintf(f, " { kind: 'r', color: 'lightGray', p0: { x: %.2f, y: %.2f }, p1: { x: %.2f, y: %.2f } },\n", x, y, x + w, y + h);
|
17
29
|
}
|
18
30
|
|
19
31
|
void emit_segment(FILE *f, MARKER *a, MARKER *b) {
|
20
|
-
|
21
|
-
|
32
|
+
fprintf(f, " { kind: 's', color: 'red', p0: { x: %.2f, y: %.2f }, p1: { x: %.2f, y: %.2f } },\n",
|
33
|
+
mr_x(a), mr_y(a), mr_x(b), mr_y(b));
|
22
34
|
}
|
23
35
|
|
24
36
|
int emit_marker_ptr_array(FILE *f, MARKER **markers, int n_markers) {
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
37
|
+
int n_emitted = 0;
|
38
|
+
for (int i = 0; i < n_markers; ++i) {
|
39
|
+
MARKER *m = markers[i];
|
40
|
+
if (!m->deleted_p) {
|
41
|
+
fprintf(f, " { kind: 'm', x: %.2f, y: %.2f, r: %.2f }, // %d\n", mr_x(m), mr_y(m), mr_r(m), i);
|
42
|
+
n_emitted++;
|
43
|
+
}
|
44
|
+
}
|
45
|
+
return n_emitted;
|
34
46
|
}
|
35
47
|
|
36
48
|
int emit_marker_array(FILE *f, MARKER *markers, int n_markers) {
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
49
|
+
int n_emitted = 0;
|
50
|
+
for (int i = 0; i < n_markers; ++i) {
|
51
|
+
MARKER *m = markers + i;
|
52
|
+
if (!m->deleted_p) {
|
53
|
+
fprintf(f, " { x: %.2f, y: %.2f, r: %.2f }, // %d\n", mr_x(m), mr_y(m), mr_r(m), i);
|
54
|
+
n_emitted++;
|
55
|
+
}
|
56
|
+
}
|
57
|
+
return n_emitted;
|
46
58
|
}
|
47
59
|
|
48
60
|
int emit_markers(const char *name, MARKER *markers, int n_markers) {
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
61
|
+
char buf[1024];
|
62
|
+
sprintf(buf, "test/%s.js", name);
|
63
|
+
FILE *f = fopen(buf, "w");
|
64
|
+
if (!f)
|
65
|
+
return -1;
|
66
|
+
fprintf(f, "var %s = [\n", name);
|
67
|
+
int n_emitted = emit_marker_array(f, markers, n_markers);
|
68
|
+
fprintf(f, "];");
|
69
|
+
fclose(f);
|
70
|
+
return n_emitted;
|
59
71
|
}
|
60
72
|
|
61
73
|
void set_random_markers(MARKER_INFO *info, MARKER *markers, int n_markers) {
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
74
|
+
unsigned t = (unsigned)time(0);
|
75
|
+
fprintf(stderr, "seed=%u\n", t);
|
76
|
+
srand(t);
|
77
|
+
int size = 8;
|
78
|
+
double x_size = 1024;
|
79
|
+
double y_size = 760;
|
80
|
+
for (int i = 0; i < n_markers; i++)
|
81
|
+
mr_set(info, markers + i, x_size * rand_double(), y_size * rand_double(), 1 + random() % (size - 1));
|
70
82
|
}
|
71
83
|
|
72
84
|
int trace_p = 1;
|
73
85
|
|
74
86
|
void trace(const char *fmt, ...)
|
75
87
|
{
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
88
|
+
if (trace_p) {
|
89
|
+
va_list ap;
|
90
|
+
va_start(ap, fmt);
|
91
|
+
vfprintf(stderr, fmt, ap);
|
92
|
+
va_end(ap);
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
/**
|
97
|
+
* Generate many random markers and then merge them. Write
|
98
|
+
* results as a Javascript array to be included included in a test page.
|
99
|
+
*/
|
100
|
+
int merge_test(int size) {
|
101
|
+
struct timeval start[1], stop[1], diff[1];
|
102
|
+
|
103
|
+
MARKER_INFO_DECL(info);
|
104
|
+
mr_info_set(info, CIRCLE, 2);
|
105
|
+
|
106
|
+
NewArrayDecl(MARKER, markers, 2 * size - 1);
|
107
|
+
mr_init(markers, 2 * size - 1);
|
108
|
+
set_random_markers(info, markers, size);
|
109
|
+
|
110
|
+
int m = emit_markers("before", markers, size);
|
111
|
+
fprintf(stderr, "before merge: %d\nmerging...\n", m);
|
112
|
+
|
113
|
+
gettimeofday(start, NULL);
|
114
|
+
|
115
|
+
size = merge_markers_fast(info, markers, size);
|
116
|
+
|
117
|
+
gettimeofday(stop, NULL);
|
118
|
+
|
119
|
+
int n = emit_markers("after", markers, size);
|
120
|
+
fprintf(stderr, "after merge: %d\n", n);
|
121
|
+
|
122
|
+
timersub(stop, start, diff);
|
123
|
+
fprintf(stderr, "%.3f seconds", diff->tv_sec + 1.0e-6 * diff->tv_usec);
|
124
|
+
|
125
|
+
return EXIT_SUCCESS;
|
126
|
+
}
|
127
|
+
|
128
|
+
|
129
|
+
/* Randomly permute the given distance array. */
|
130
|
+
void permute(PRIORITY_QUEUE_VALUE *a, int size) {
|
131
|
+
for (int i = size - 1; i > 0; i--) {
|
132
|
+
int j = rand() % (i + 1);
|
133
|
+
PRIORITY_QUEUE_VALUE tmp = a[i];
|
134
|
+
a[i] = a[j];
|
135
|
+
a[j] = tmp;
|
136
|
+
}
|
137
|
+
}
|
138
|
+
|
139
|
+
// Run a unit test on a priority queue of random data with given size.
|
140
|
+
int pq_test(int size) {
|
141
|
+
PRIORITY_QUEUE q[1];
|
142
|
+
pq_init(q);
|
143
|
+
|
144
|
+
fprintf(stderr, "test: heap_ops (n = %d):\n", size);
|
145
|
+
|
146
|
+
// Build linear pointer array of random keys.
|
147
|
+
PRIORITY_QUEUE_VALUE *dist;
|
148
|
+
NewArray(dist, size);
|
149
|
+
for (int i = 0; i < size; i++)
|
150
|
+
dist[i] = i;
|
151
|
+
permute(dist, size);
|
152
|
+
fprintf(stderr, " built random data\n");
|
153
|
+
|
154
|
+
pq_set_up(q, dist, size);
|
155
|
+
fprintf(stderr, " finished set up\n");
|
156
|
+
|
157
|
+
// Pull min repeatedly and verify vals are what they should be.
|
158
|
+
PRIORITY_QUEUE_VALUE should_be = 0;
|
159
|
+
for (int n = 0; n < size; n++) {
|
160
|
+
int i = pq_get_min(q);
|
161
|
+
if (dist[i] != should_be++) {
|
162
|
+
fprintf(stderr, "fail 1: %i -> %g\n", i, dist[i]);
|
163
|
+
return 42;
|
164
|
+
}
|
165
|
+
}
|
166
|
+
fprintf(stderr, " finished checking heapify\n");
|
167
|
+
|
168
|
+
// Now rebuild the heap by inserting one key at a time.
|
169
|
+
for (int n = 0; n < size; n++)
|
170
|
+
pq_add(q, n);
|
171
|
+
fprintf(stderr, " finished insertions\n");
|
172
|
+
|
173
|
+
// And verify values again.
|
174
|
+
should_be = 0;
|
175
|
+
for (int n = 0; n < size; n++) {
|
176
|
+
int i = pq_get_min(q);
|
177
|
+
if (dist[i] != should_be++) {
|
178
|
+
fprintf(stderr, " fail 2: %i -> %g\n", i, dist[i]);
|
179
|
+
return 4242;
|
180
|
+
}
|
181
|
+
}
|
182
|
+
fprintf(stderr, " finished checking insert\n");
|
183
|
+
|
184
|
+
// Now rebuild the heap by inserting one key at a time in reverse.
|
185
|
+
for (int n = size - 1; n >= 0; n--)
|
186
|
+
pq_add(q, n);
|
187
|
+
fprintf(stderr, " finished reverse insertions\n");
|
188
|
+
|
189
|
+
// Now delete one by one.
|
190
|
+
for (int n = 0; n < size; n++)
|
191
|
+
pq_delete(q, n);
|
192
|
+
fprintf(stderr, " finished reverse deletions\n");
|
193
|
+
|
194
|
+
pq_clear(q);
|
195
|
+
return 0;
|
82
196
|
}
|
197
|
+
|
198
|
+
static void draw(FILE *f, NODE *node, double x, double y, double w, double h) {
|
199
|
+
emit_rectangle(f, x, y, w, h);
|
200
|
+
emit_marker_ptr_array(f, node->markers, node->marker_count);
|
201
|
+
if (internal_p(node)) {
|
202
|
+
for (int q = 0; q < 4; q++) {
|
203
|
+
QUADRANT_DECL(q, qx, qy, qw, qh, x, y, w, h);
|
204
|
+
draw(f, node->children + q, qx, qy, qw, qh);
|
205
|
+
}
|
206
|
+
}
|
207
|
+
}
|
208
|
+
|
209
|
+
static void draw_nearest(FILE *f, MARKER *markers, MARKER **nearest_markers, int n_markers) {
|
210
|
+
for (int i = 0; i < n_markers; i++) {
|
211
|
+
if (nearest_markers[i])
|
212
|
+
emit_segment(f, markers + i, nearest_markers[i]);
|
213
|
+
}
|
214
|
+
}
|
215
|
+
|
216
|
+
int qt_draw(QUADTREE *qt, MARKER *markers, MARKER **nearest_markers, int n_markers, const char *name) {
|
217
|
+
char buf[1024];
|
218
|
+
sprintf(buf, "test/%s.js", name);
|
219
|
+
FILE *f = fopen(buf, "w");
|
220
|
+
if (!f)
|
221
|
+
return -1;
|
222
|
+
fprintf(f, "var %s = [\n", name);
|
223
|
+
draw(f, qt->root, qt->x, qt->y, qt->w, qt->h);
|
224
|
+
draw_nearest(f, markers, nearest_markers, n_markers);
|
225
|
+
fprintf(f, "];\n");
|
226
|
+
fclose(f);
|
227
|
+
return EXIT_SUCCESS;
|
228
|
+
}
|
229
|
+
|
230
|
+
int qt_test(int size) {
|
231
|
+
QUADTREE_DECL(qt);
|
232
|
+
MARKER_INFO_DECL(info);
|
233
|
+
MARKER *markers, **nearest_markers;
|
234
|
+
NewArray(markers, size);
|
235
|
+
NewArray(nearest_markers, size);
|
236
|
+
set_random_markers(info, markers, size);
|
237
|
+
qt_setup(qt, 5, 0, 0, 1024, 724, info);
|
238
|
+
fprintf(stderr, "inserting %d:\n", size);
|
239
|
+
for (int i = 0; i < size; i++) {
|
240
|
+
qt_insert(qt, markers + i);
|
241
|
+
}
|
242
|
+
fprintf(stderr, "inserted %d\n", size);
|
243
|
+
for (int i = 0; i < size; i++) {
|
244
|
+
nearest_markers[i] = qt_nearest(qt, markers + i);
|
245
|
+
}
|
246
|
+
fprintf(stderr, "looked up %d\n", size);
|
247
|
+
qt_draw(qt, markers, nearest_markers, size, "qt");
|
248
|
+
fprintf(stderr, "drew %d\n", size);
|
249
|
+
for (int i = 0; i < size; i++) {
|
250
|
+
qt_delete(qt, markers + i);
|
251
|
+
}
|
252
|
+
fprintf(stderr, "after delete all, root is %s\n",
|
253
|
+
leaf_p(qt->root) ? "leaf (ok)" : "internal (not ok)");
|
254
|
+
|
255
|
+
return EXIT_SUCCESS;
|
256
|
+
}
|
257
|
+
|
258
|
+
#endif
|
data/ext/lulu/test.h
CHANGED
@@ -15,6 +15,11 @@ void emit_rectangle(FILE *f, double x, double y, double w, double h);
|
|
15
15
|
void emit_segment(FILE *f, MARKER *a, MARKER *b);
|
16
16
|
int emit_marker_array(FILE *f, MARKER *markers, int n_markers);
|
17
17
|
int emit_marker_ptr_array(FILE *f, MARKER **markers, int n_markers);
|
18
|
+
double rand_double(void);
|
18
19
|
void set_random_markers(MARKER_INFO *info, MARKER *markers, int n_markers);
|
20
|
+
void qt_clear(QUADTREE *qt);
|
21
|
+
int qt_test(int size);
|
22
|
+
int pq_test(int size);
|
23
|
+
int merge_test(int test_markers_size);
|
19
24
|
|
20
25
|
#endif /* TEST_H_ */
|
data/ext/lulu/utility.c
CHANGED
@@ -9,41 +9,37 @@
|
|
9
9
|
#include <stdlib.h>
|
10
10
|
#include "utility.h"
|
11
11
|
|
12
|
+
#ifdef LULU_STD_C
|
13
|
+
|
12
14
|
void *safe_malloc(size_t size, const char *file, int line) {
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
void *p = malloc(size);
|
16
|
+
if (!p) {
|
17
|
+
fprintf(stderr, "%s:%d: out of memory\n", file, line);
|
18
|
+
exit(1);
|
19
|
+
}
|
20
|
+
return p;
|
19
21
|
}
|
20
22
|
|
21
23
|
void *safe_realloc(void *p, size_t size, const char *file, int line) {
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
p = realloc(p, size);
|
25
|
+
if (!p) {
|
26
|
+
fprintf(stderr, "%s:%d: out of memory\n", file, line);
|
27
|
+
exit(1);
|
28
|
+
}
|
29
|
+
return p;
|
28
30
|
}
|
29
31
|
|
32
|
+
#endif
|
33
|
+
|
30
34
|
/**
|
31
35
|
* Return the 0-based position of highest bit or -1 of zero.
|
32
36
|
*/
|
33
37
|
int high_bit_position(unsigned n) {
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
int p = -1;
|
39
|
+
while (n) {
|
40
|
+
p++;
|
41
|
+
n >>= 1;
|
42
|
+
}
|
43
|
+
return p;
|
40
44
|
}
|
41
45
|
|
42
|
-
double rand_double(void)
|
43
|
-
{
|
44
|
-
unsigned i = rand();
|
45
|
-
i = (i << 8) ^ (unsigned)rand();
|
46
|
-
i = (i << 8) ^ (unsigned)rand();
|
47
|
-
i = (i << 8) ^ (unsigned)rand();
|
48
|
-
return i / (256.0 * 256.0 * 256.0 * 256.0);
|
49
|
-
}
|
data/ext/lulu/utility.h
CHANGED
@@ -10,45 +10,51 @@
|
|
10
10
|
|
11
11
|
#define STATIC_ARRAY_SIZE(A) ((int)(sizeof A / sizeof A[0]))
|
12
12
|
|
13
|
-
#ifdef
|
13
|
+
#ifdef LULU_STD_C
|
14
14
|
|
15
15
|
// Our allocators.
|
16
16
|
#define New(Ptr) do { \
|
17
|
-
|
17
|
+
(Ptr) = safe_malloc(sizeof *(Ptr), __FILE__, __LINE__); \
|
18
18
|
} while (0)
|
19
19
|
|
20
20
|
#define NewArray(Ptr, Size) do { \
|
21
|
-
|
21
|
+
(Ptr) = safe_malloc((Size) * sizeof *(Ptr), __FILE__, __LINE__); \
|
22
22
|
} while (0)
|
23
23
|
|
24
24
|
#define RenewArray(Ptr, Size) do { \
|
25
|
-
|
25
|
+
(Ptr) = safe_realloc((Ptr), (Size) * sizeof *(Ptr), __FILE__, __LINE__); \
|
26
26
|
} while (0)
|
27
27
|
|
28
28
|
#define Free(Ptr) do { \
|
29
|
-
|
30
|
-
|
29
|
+
free(Ptr); \
|
30
|
+
Ptr = NULL; \
|
31
31
|
} while (0)
|
32
32
|
|
33
|
-
|
33
|
+
void *safe_malloc(size_t size, const char *file, int line);
|
34
|
+
void *safe_realloc(void *p, size_t size, const char *file, int line);
|
35
|
+
|
36
|
+
#endif
|
37
|
+
|
38
|
+
#ifdef LULU_GEM
|
34
39
|
|
35
40
|
#include "ruby.h"
|
36
41
|
|
37
42
|
// Ruby allocators. We can't use the macros without rewriting to include type parameters.
|
38
43
|
#define New(Ptr) do { \
|
39
|
-
|
44
|
+
(Ptr) = (void*)xmalloc(sizeof *(Ptr)); \
|
40
45
|
} while (0)
|
41
46
|
|
42
47
|
#define NewArray(Ptr, Size) do { \
|
43
|
-
|
48
|
+
(Ptr) = (void*)xmalloc2((Size), sizeof *(Ptr)); \
|
44
49
|
} while (0)
|
45
50
|
|
46
51
|
#define RenewArray(Ptr, Size) do { \
|
47
|
-
|
52
|
+
(Ptr) = (void*)xrealloc2((char*)(Ptr), (Size), sizeof *(Ptr)); \
|
48
53
|
} while (0)
|
49
54
|
|
50
55
|
#define Free(Ptr) do { \
|
51
|
-
|
56
|
+
xfree(Ptr); \
|
57
|
+
Ptr = NULL; \
|
52
58
|
} while (0)
|
53
59
|
|
54
60
|
#endif
|
@@ -66,9 +72,6 @@ void trace(const char *fmt, ...);
|
|
66
72
|
#define TRACE(Args)
|
67
73
|
#endif
|
68
74
|
|
69
|
-
void *safe_malloc(size_t size, const char *file, int line);
|
70
|
-
void *safe_realloc(void *p, size_t size, const char *file, int line);
|
71
75
|
int high_bit_position(unsigned n);
|
72
|
-
double rand_double(void);
|
73
76
|
|
74
77
|
#endif /* UTILITY_H_ */
|