1 /*
2 # This file is part of libkd.
3 # Licensed under a 3-clause BSD style license - see LICENSE
4 */
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <math.h>
10 #include <stdint.h>
11 #include <strings.h>
12 #include <errno.h>
13
14 #include "cutest.h"
15 #include "kdtree.h"
16 #include "kdtree_fits_io.h"
17
18 #include "test_libkd_common.c"
19
assert_kdtrees_equal(CuTest * ct,const kdtree_t * kd,const kdtree_t * kd2)20 static void assert_kdtrees_equal(CuTest* ct, const kdtree_t* kd, const kdtree_t* kd2) {
21 double del = 1e-10;
22 size_t sz, sz2;
23
24 if (!kd) {
25 CuAssertPtrEquals(ct, NULL, (kdtree_t*)kd2);
26 return;
27 }
28 CuAssertPtrNotNull(ct, kd2);
29
30 CuAssertIntEquals(ct, kd->treetype, kd2->treetype);
31 CuAssertIntEquals(ct, kd->dimbits, kd2->dimbits);
32 CuAssertIntEquals(ct, kd->dimmask, kd2->dimmask);
33 CuAssertIntEquals(ct, kd->splitmask, kd2->splitmask);
34 CuAssertIntEquals(ct, kd->ndata, kd2->ndata);
35 CuAssertIntEquals(ct, kd->ndim, kd2->ndim);
36 CuAssertIntEquals(ct, kd->nnodes, kd2->nnodes);
37 CuAssertIntEquals(ct, kd->nbottom, kd2->nbottom);
38 CuAssertIntEquals(ct, kd->ninterior, kd2->ninterior);
39 CuAssertIntEquals(ct, kd->nlevels, kd2->nlevels);
40 CuAssertIntEquals(ct, kd->has_linear_lr, kd2->has_linear_lr);
41 CuAssertDblEquals(ct, kd->scale, kd2->scale, del);
42 CuAssertDblEquals(ct, kd->invscale, kd2->invscale, del);
43
44 if (kd->lr) {
45 CuAssertPtrNotNull(ct, kd2->lr);
46 sz = kdtree_sizeof_lr(kd );
47 sz2 = kdtree_sizeof_lr(kd2);
48 CuAssertIntEquals(ct, sz, sz2);
49 CuAssert(ct, "lr equal", memcmp(kd->lr, kd2->lr, sz) == 0);
50 } else {
51 CuAssertPtrEquals(ct, NULL, kd2->lr);
52 }
53
54 if (kd->perm) {
55 CuAssertPtrNotNull(ct, kd2->perm);
56 sz = kdtree_sizeof_perm(kd );
57 sz2 = kdtree_sizeof_perm(kd2);
58 CuAssertIntEquals(ct, sz, sz2);
59 CuAssert(ct, "perm equal", memcmp(kd->perm, kd2->perm, sz) == 0);
60 } else {
61 CuAssertPtrEquals(ct, NULL, kd2->perm);
62 }
63
64 if (kd->data.any) {
65 CuAssertPtrNotNull(ct, kd2->data.any);
66 sz = kdtree_sizeof_data(kd );
67 sz2 = kdtree_sizeof_data(kd2);
68 CuAssertIntEquals(ct, sz, sz2);
69 CuAssert(ct, "data equal", memcmp(kd->data.any, kd2->data.any, sz) == 0);
70 } else {
71 CuAssertPtrEquals(ct, NULL, kd2->data.any);
72 }
73
74 if (kd->splitdim) {
75 CuAssertPtrNotNull(ct, kd2->splitdim);
76 sz = kdtree_sizeof_splitdim(kd );
77 sz2 = kdtree_sizeof_splitdim(kd2);
78 CuAssertIntEquals(ct, sz, sz2);
79 CuAssert(ct, "splitdim equal", memcmp(kd->splitdim, kd2->splitdim, sz) == 0);
80 } else {
81 CuAssertPtrEquals(ct, NULL, kd2->splitdim);
82 }
83
84 if (kd->split.any) {
85 CuAssertPtrNotNull(ct, kd2->split.any);
86 sz = kdtree_sizeof_split(kd );
87 sz2 = kdtree_sizeof_split(kd2);
88 CuAssertIntEquals(ct, sz, sz2);
89 CuAssert(ct, "split equal", memcmp(kd->split.any, kd2->split.any, sz) == 0);
90 } else {
91 CuAssertPtrEquals(ct, NULL, kd2->split.any);
92 }
93
94 if (kd->bb.any) {
95 CuAssertPtrNotNull(ct, kd2->bb.any);
96 sz = kdtree_sizeof_bb(kd );
97 sz2 = kdtree_sizeof_bb(kd2);
98 CuAssertIntEquals(ct, sz, sz2);
99 CuAssert(ct, "bb equal", memcmp(kd->bb.any, kd2->bb.any, sz) == 0);
100 } else {
101 CuAssertPtrEquals(ct, NULL, kd2->bb.any);
102 }
103
104 if (kd->minval) {
105 sz = kd->ndim * sizeof(double);
106 CuAssertPtrNotNull(ct, kd2->minval);
107 CuAssert(ct, "minval equal", memcmp(kd->minval, kd2->minval, sz) == 0);
108 } else {
109 CuAssertPtrEquals(ct, NULL, kd2->minval);
110 }
111
112 if (kd->maxval) {
113 CuAssertPtrNotNull(ct, kd2->maxval);
114 sz = kd->ndim * sizeof(double);
115 CuAssert(ct, "maxval equal", memcmp(kd->maxval, kd2->maxval, sz) == 0);
116 } else {
117 CuAssertPtrEquals(ct, NULL, kd2->maxval);
118 }
119
120 if (kd->name) {
121 CuAssertPtrNotNull(ct, kd2->name);
122 CuAssert(ct, "name equal", strcmp(kd->name, kd2->name) == 0);
123 } else {
124 CuAssertPtrEquals(ct, NULL, kd2->name);
125 }
126 }
127
test_read_write_single_tree_unnamed(CuTest * ct)128 void test_read_write_single_tree_unnamed(CuTest* ct) {
129 kdtree_t* kd;
130 double * data;
131 int N = 1000;
132 int Nleaf = 5;
133 int D = 3;
134 char fn[1024];
135 int rtn;
136 kdtree_t* kd2;
137 int fd;
138
139 data = random_points_d(N, D);
140 kd = build_tree(ct, data, N, D, Nleaf, KDTT_DOUBLE, KD_BUILD_SPLIT);
141 kd->name = NULL;
142
143 sprintf(fn, "/tmp/test_libkd_io_single_tree_unnamed.XXXXXX");
144 fd = mkstemp(fn);
145 if (fd == -1) {
146 fprintf(stderr, "Failed to generate a temp filename: %s\n", strerror(errno));
147 CuFail(ct, "mkstemp");
148 }
149 close(fd);
150 printf("Single tree unnamed: writing to file %s.\n", fn);
151
152 rtn = kdtree_fits_write(kd, fn, NULL);
153 CuAssertIntEquals(ct, 0, rtn);
154
155 kd2 = kdtree_fits_read(fn, NULL, NULL);
156
157 assert_kdtrees_equal(ct, kd, kd2);
158
159 free(data);
160 kdtree_free(kd);
161 kdtree_fits_close(kd2);
162 }
163
test_read_write_single_tree_named(CuTest * ct)164 void test_read_write_single_tree_named(CuTest* ct) {
165 kdtree_t* kd;
166 double * data;
167 int N = 1000;
168 int Nleaf = 5;
169 int D = 3;
170 char fn[1024];
171 int rtn;
172 kdtree_t* kd2;
173 int fd;
174
175 data = random_points_d(N, D);
176 kd = build_tree(ct, data, N, D, Nleaf, KDTT_DOUBLE,
177 KD_BUILD_SPLIT | KD_BUILD_BBOX | KD_BUILD_LINEAR_LR);
178 kd->name = strdup("christmas");
179
180 sprintf(fn, "/tmp/test_libkd_io_single_tree_named.XXXXXX");
181 fd = mkstemp(fn);
182 if (fd == -1) {
183 fprintf(stderr, "Failed to generate a temp filename: %s\n", strerror(errno));
184 CuFail(ct, "mkstemp");
185 }
186 close(fd);
187 printf("Single tree named: writing to file %s.\n", fn);
188
189 rtn = kdtree_fits_write(kd, fn, NULL);
190 CuAssertIntEquals(ct, 0, rtn);
191
192 // Loading any tree should succeed.
193 kd2 = kdtree_fits_read(fn, NULL, NULL);
194 assert_kdtrees_equal(ct, kd, kd2);
195 kdtree_fits_close(kd2);
196
197 // Attempting to load a nonexist named tree should fail.
198 kd2 = kdtree_fits_read(fn, "none", NULL);
199 CuAssertPtrEquals(ct, NULL, kd2);
200
201 // Loading by its correct name should work.
202 kd2 = kdtree_fits_read(fn, "christmas", NULL);
203 assert_kdtrees_equal(ct, kd, kd2);
204 kdtree_fits_close(kd2);
205
206 free(data);
207 kdtree_free(kd);
208 }
209
test_read_write_two_trees(CuTest * ct)210 void test_read_write_two_trees(CuTest* ct) {
211 kdtree_t* kd;
212 kdtree_t* kdB;
213 double * data;
214 double * dataB;
215 int N = 1000;
216 int Nleaf = 5;
217 int D = 3;
218 char fn[1024];
219 int rtn;
220 kdtree_t* kd2;
221 kdtree_t* kd2B;
222 int fd;
223 kdtree_fits_t* io;
224
225 data = random_points_d(N, D);
226 kd = build_tree(ct, data, N, D, Nleaf, KDTT_DOUBLE,
227 KD_BUILD_SPLIT | KD_BUILD_BBOX | KD_BUILD_LINEAR_LR);
228 kd->name = strdup("christmas");
229
230 dataB = random_points_d(N, D);
231 kdB = build_tree(ct, dataB, N, D, Nleaf, KDTT_DUU,
232 KD_BUILD_SPLIT | KD_BUILD_SPLITDIM | KD_BUILD_LINEAR_LR);
233 kdB->name = strdup("watermelon");
234
235 sprintf(fn, "/tmp/test_libkd_io_two_trees.XXXXXX");
236 fd = mkstemp(fn);
237 if (fd == -1) {
238 fprintf(stderr, "Failed to generate a temp filename: %s\n", strerror(errno));
239 CuFail(ct, "mkstemp");
240 }
241 printf("Two trees: writing to file %s.\n", fn);
242
243 close(fd);
244
245 io = kdtree_fits_open_for_writing(fn);
246 if (!io) {
247 fprintf(stderr, "Failed to open temp file: %s\n", strerror(errno));
248 CuFail(ct, "fdopen");
249 }
250 rtn = kdtree_fits_write_primary_header(io, NULL);
251 CuAssertIntEquals(ct, 0, rtn);
252 rtn = kdtree_fits_append_tree(io, kd, NULL);
253 CuAssertIntEquals(ct, 0, rtn);
254 rtn = kdtree_fits_append_tree(io, kdB, NULL);
255 CuAssertIntEquals(ct, 0, rtn);
256
257 if (kdtree_fits_io_close(io)) {
258 fprintf(stderr, "Failed to close temp file: %s\n", strerror(errno));
259 CuFail(ct, "fclose");
260 }
261
262 // Loading any tree should return the first one.
263 kd2 = kdtree_fits_read(fn, NULL, NULL);
264 assert_kdtrees_equal(ct, kd, kd2);
265 kdtree_fits_close(kd2);
266
267 // Attempting to load a nonexist named tree should fail.
268 kd2 = kdtree_fits_read(fn, "none", NULL);
269 CuAssertPtrEquals(ct, NULL, kd2);
270
271 // Loading by the correct names should work.
272 kd2 = kdtree_fits_read(fn, "christmas", NULL);
273 assert_kdtrees_equal(ct, kd, kd2);
274
275 kd2B = kdtree_fits_read(fn, "watermelon", NULL);
276 assert_kdtrees_equal(ct, kdB, kd2B);
277
278 kdtree_fits_close(kd2);
279 kdtree_fits_close(kd2B);
280
281 free(data);
282 kdtree_free(kd);
283
284 free(dataB);
285 kdtree_free(kdB);
286 }
287
288