1 /**
2 * @file unit-capi-sparse_neg.cc
3 *
4 * @section LICENSE
5 *
6 * The MIT License
7 *
8 * @copyright Copyright (c) 2017-2021 TileDB Inc.
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 * THE SOFTWARE.
27 *
28 * @section DESCRIPTION
29 *
30 * Tests of C API for sparse arrays with negative domains.
31 */
32
33 #include "catch.hpp"
34 #include "test/src/helpers.h"
35 #include "test/src/vfs_helpers.h"
36 #ifdef _WIN32
37 #include "tiledb/sm/filesystem/win.h"
38 #else
39 #include "tiledb/sm/filesystem/posix.h"
40 #endif
41 #include "tiledb/sm/c_api/tiledb.h"
42 #include "tiledb/sm/misc/utils.h"
43
44 #include <iostream>
45 #include <sstream>
46 #include <thread>
47
48 using namespace tiledb::test;
49
50 struct SparseNegFx2 {
51 // TileDB context
52 tiledb_ctx_t* ctx_;
53 tiledb_vfs_t* vfs_;
54
55 // Vector of supported filsystems
56 const std::vector<std::unique_ptr<SupportedFs>> fs_vec_;
57
58 // Functions
59 SparseNegFx2();
60 ~SparseNegFx2();
61 void create_temp_dir(const std::string& path);
62 void remove_temp_dir(const std::string& path);
63 void create_sparse_vector(const std::string& path);
64 void create_sparse_array(const std::string& path);
65 void write_sparse_vector(const std::string& path);
66 void write_sparse_array(const std::string& path);
67 void read_sparse_vector(const std::string& path);
68 void read_sparse_array_row(const std::string& path);
69 void read_sparse_array_col(const std::string& path);
70 static std::string random_name(const std::string& prefix);
71 };
72
SparseNegFx2()73 SparseNegFx2::SparseNegFx2()
74 : fs_vec_(vfs_test_get_fs_vec()) {
75 // Initialize vfs test
76 REQUIRE(vfs_test_init(fs_vec_, &ctx_, &vfs_).ok());
77 }
78
~SparseNegFx2()79 SparseNegFx2::~SparseNegFx2() {
80 // Close vfs test
81 REQUIRE(vfs_test_close(fs_vec_, ctx_, vfs_).ok());
82 tiledb_vfs_free(&vfs_);
83 tiledb_ctx_free(&ctx_);
84 }
85
create_temp_dir(const std::string & path)86 void SparseNegFx2::create_temp_dir(const std::string& path) {
87 remove_temp_dir(path);
88 REQUIRE(tiledb_vfs_create_dir(ctx_, vfs_, path.c_str()) == TILEDB_OK);
89 }
90
remove_temp_dir(const std::string & path)91 void SparseNegFx2::remove_temp_dir(const std::string& path) {
92 int is_dir = 0;
93 REQUIRE(tiledb_vfs_is_dir(ctx_, vfs_, path.c_str(), &is_dir) == TILEDB_OK);
94 if (is_dir)
95 REQUIRE(tiledb_vfs_remove_dir(ctx_, vfs_, path.c_str()) == TILEDB_OK);
96 }
97
random_name(const std::string & prefix)98 std::string SparseNegFx2::random_name(const std::string& prefix) {
99 std::stringstream ss;
100 ss << prefix << "-" << std::this_thread::get_id() << "-"
101 << TILEDB_TIMESTAMP_NOW_MS;
102 return ss.str();
103 }
104
create_sparse_vector(const std::string & path)105 void SparseNegFx2::create_sparse_vector(const std::string& path) {
106 int rc;
107 int64_t dim_domain[] = {-1, 2};
108 int64_t tile_extent = 2;
109
110 // Create domain
111 tiledb_domain_t* domain;
112 rc = tiledb_domain_alloc(ctx_, &domain);
113 REQUIRE(rc == TILEDB_OK);
114 tiledb_dimension_t* dim;
115 rc = tiledb_dimension_alloc(
116 ctx_, "d0", TILEDB_INT64, dim_domain, &tile_extent, &dim);
117 REQUIRE(rc == TILEDB_OK);
118 rc = tiledb_domain_add_dimension(ctx_, domain, dim);
119 REQUIRE(rc == TILEDB_OK);
120
121 // Create attribute
122 tiledb_attribute_t* attr;
123 rc = tiledb_attribute_alloc(ctx_, "a", TILEDB_INT32, &attr);
124 REQUIRE(rc == TILEDB_OK);
125
126 // Create array schema
127 tiledb_array_schema_t* array_schema;
128 rc = tiledb_array_schema_alloc(ctx_, TILEDB_SPARSE, &array_schema);
129 REQUIRE(rc == TILEDB_OK);
130 rc = tiledb_array_schema_set_cell_order(ctx_, array_schema, TILEDB_ROW_MAJOR);
131 REQUIRE(rc == TILEDB_OK);
132 rc = tiledb_array_schema_set_tile_order(ctx_, array_schema, TILEDB_ROW_MAJOR);
133 REQUIRE(rc == TILEDB_OK);
134 rc = tiledb_array_schema_set_domain(ctx_, array_schema, domain);
135 REQUIRE(rc == TILEDB_OK);
136 rc = tiledb_array_schema_add_attribute(ctx_, array_schema, attr);
137 REQUIRE(rc == TILEDB_OK);
138
139 rc = tiledb_array_schema_check(ctx_, array_schema);
140 REQUIRE(rc == TILEDB_OK);
141
142 // Create array
143 rc = tiledb_array_create(ctx_, path.c_str(), array_schema);
144 REQUIRE(rc == TILEDB_OK);
145 tiledb_attribute_free(&attr);
146 tiledb_dimension_free(&dim);
147 tiledb_domain_free(&domain);
148 tiledb_array_schema_free(&array_schema);
149 }
150
create_sparse_array(const std::string & path)151 void SparseNegFx2::create_sparse_array(const std::string& path) {
152 // Create dimensions
153 int64_t dim_domain[] = {-2, 1, -2, 1};
154 int64_t tile_extents[] = {2, 2};
155 tiledb_dimension_t* d1;
156 int rc = tiledb_dimension_alloc(
157 ctx_, "d1", TILEDB_INT64, &dim_domain[0], &tile_extents[0], &d1);
158 CHECK(rc == TILEDB_OK);
159 tiledb_dimension_t* d2;
160 rc = tiledb_dimension_alloc(
161 ctx_, "d2", TILEDB_INT64, &dim_domain[2], &tile_extents[1], &d2);
162 CHECK(rc == TILEDB_OK);
163
164 // Create domain
165 tiledb_domain_t* domain;
166 rc = tiledb_domain_alloc(ctx_, &domain);
167 CHECK(rc == TILEDB_OK);
168 rc = tiledb_domain_add_dimension(ctx_, domain, d1);
169 CHECK(rc == TILEDB_OK);
170 rc = tiledb_domain_add_dimension(ctx_, domain, d2);
171 CHECK(rc == TILEDB_OK);
172
173 // Create attributes
174 tiledb_attribute_t* a;
175 rc = tiledb_attribute_alloc(ctx_, "a", TILEDB_INT32, &a);
176 CHECK(rc == TILEDB_OK);
177 tiledb_filter_t* filter;
178 tiledb_filter_list_t* list;
179 rc = tiledb_filter_alloc(ctx_, TILEDB_FILTER_LZ4, &filter);
180 CHECK(rc == TILEDB_OK);
181 rc = tiledb_filter_list_alloc(ctx_, &list);
182 CHECK(rc == TILEDB_OK);
183 rc = tiledb_filter_list_add_filter(ctx_, list, filter);
184 CHECK(rc == TILEDB_OK);
185 rc = tiledb_attribute_set_filter_list(ctx_, a, list);
186 CHECK(rc == TILEDB_OK);
187
188 // Create array schema
189 tiledb_array_schema_t* array_schema;
190 rc = tiledb_array_schema_alloc(ctx_, TILEDB_SPARSE, &array_schema);
191 CHECK(rc == TILEDB_OK);
192 rc = tiledb_array_schema_set_cell_order(ctx_, array_schema, TILEDB_ROW_MAJOR);
193 CHECK(rc == TILEDB_OK);
194 rc = tiledb_array_schema_set_tile_order(ctx_, array_schema, TILEDB_ROW_MAJOR);
195 CHECK(rc == TILEDB_OK);
196 rc = tiledb_array_schema_set_domain(ctx_, array_schema, domain);
197 CHECK(rc == TILEDB_OK);
198 rc = tiledb_array_schema_add_attribute(ctx_, array_schema, a);
199 CHECK(rc == TILEDB_OK);
200
201 // Check array schema
202 rc = tiledb_array_schema_check(ctx_, array_schema);
203 CHECK(rc == TILEDB_OK);
204
205 // Create array
206 rc = tiledb_array_create(ctx_, path.c_str(), array_schema);
207 CHECK(rc == TILEDB_OK);
208
209 // Clean up
210 tiledb_filter_free(&filter);
211 tiledb_filter_list_free(&list);
212 tiledb_attribute_free(&a);
213 tiledb_dimension_free(&d1);
214 tiledb_dimension_free(&d2);
215 tiledb_domain_free(&domain);
216 tiledb_array_schema_free(&array_schema);
217 }
218
write_sparse_vector(const std::string & path)219 void SparseNegFx2::write_sparse_vector(const std::string& path) {
220 // Open array
221 tiledb_array_t* array;
222 int rc = tiledb_array_alloc(ctx_, path.c_str(), &array);
223 CHECK(rc == TILEDB_OK);
224 rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
225 CHECK(rc == TILEDB_OK);
226
227 int a[] = {0, 1};
228 uint64_t a_size = sizeof(a);
229 int64_t coords[] = {-1, 1};
230 uint64_t coords_size = sizeof(coords);
231 tiledb_query_t* query;
232 rc = tiledb_query_alloc(ctx_, array, TILEDB_WRITE, &query);
233 REQUIRE(rc == TILEDB_OK);
234 rc = tiledb_query_set_data_buffer(ctx_, query, "a", a, &a_size);
235 REQUIRE(rc == TILEDB_OK);
236 rc = tiledb_query_set_data_buffer(ctx_, query, "d0", coords, &coords_size);
237 REQUIRE(rc == TILEDB_OK);
238 rc = tiledb_query_set_layout(ctx_, query, TILEDB_GLOBAL_ORDER);
239 REQUIRE(rc == TILEDB_OK);
240 rc = tiledb_query_submit(ctx_, query);
241 REQUIRE(rc == TILEDB_OK);
242 rc = tiledb_query_finalize(ctx_, query);
243 REQUIRE(rc == TILEDB_OK);
244
245 // Close array
246 rc = tiledb_array_close(ctx_, array);
247 CHECK(rc == TILEDB_OK);
248
249 // Clean up
250 tiledb_array_free(&array);
251 tiledb_query_free(&query);
252 }
253
write_sparse_array(const std::string & path)254 void SparseNegFx2::write_sparse_array(const std::string& path) {
255 // Open array
256 tiledb_array_t* array;
257 int rc = tiledb_array_alloc(ctx_, path.c_str(), &array);
258 CHECK(rc == TILEDB_OK);
259 rc = tiledb_array_open(ctx_, array, TILEDB_WRITE);
260 CHECK(rc == TILEDB_OK);
261
262 int a[] = {1, 2, 3, 4};
263 uint64_t a_size = sizeof(a);
264 int64_t coords_dim1[] = {-2, 1, -1, 1};
265 int64_t coords_dim2[] = {0, 1, -1, -1};
266 uint64_t coords_size = sizeof(coords_dim1);
267 tiledb_query_t* query;
268 rc = tiledb_query_alloc(ctx_, array, TILEDB_WRITE, &query);
269 REQUIRE(rc == TILEDB_OK);
270 rc = tiledb_query_set_data_buffer(ctx_, query, "a", a, &a_size);
271 REQUIRE(rc == TILEDB_OK);
272 rc = tiledb_query_set_data_buffer(
273 ctx_, query, "d1", coords_dim1, &coords_size);
274 REQUIRE(rc == TILEDB_OK);
275 rc = tiledb_query_set_data_buffer(
276 ctx_, query, "d2", coords_dim2, &coords_size);
277 REQUIRE(rc == TILEDB_OK);
278 rc = tiledb_query_set_layout(ctx_, query, TILEDB_UNORDERED);
279 REQUIRE(rc == TILEDB_OK);
280 rc = tiledb_query_submit(ctx_, query);
281 REQUIRE(rc == TILEDB_OK);
282 rc = tiledb_query_finalize(ctx_, query);
283 REQUIRE(rc == TILEDB_OK);
284
285 // Close array
286 rc = tiledb_array_close(ctx_, array);
287 CHECK(rc == TILEDB_OK);
288
289 // Clean up
290 tiledb_array_free(&array);
291 tiledb_query_free(&query);
292 }
293
read_sparse_vector(const std::string & path)294 void SparseNegFx2::read_sparse_vector(const std::string& path) {
295 // Open array
296 tiledb_array_t* array;
297 int rc = tiledb_array_alloc(ctx_, path.c_str(), &array);
298 CHECK(rc == TILEDB_OK);
299 rc = tiledb_array_open(ctx_, array, TILEDB_READ);
300 CHECK(rc == TILEDB_OK);
301
302 int a[2];
303 uint64_t a_size = sizeof(a);
304 int64_t coords[2];
305 uint64_t coords_size = sizeof(coords);
306 tiledb_query_t* query;
307 rc = tiledb_query_alloc(ctx_, array, TILEDB_READ, &query);
308 REQUIRE(rc == TILEDB_OK);
309
310 // Set some subarray
311 int64_t s0[] = {-1, 2};
312 rc = tiledb_query_set_layout(ctx_, query, TILEDB_ROW_MAJOR);
313 REQUIRE(rc == TILEDB_OK);
314 rc = tiledb_query_add_range(ctx_, query, 0, &s0[0], &s0[1], nullptr);
315 REQUIRE(rc == TILEDB_OK);
316
317 rc = tiledb_query_set_data_buffer(ctx_, query, "a", a, &a_size);
318 REQUIRE(rc == TILEDB_OK);
319 rc = tiledb_query_set_data_buffer(ctx_, query, "d0", coords, &coords_size);
320 REQUIRE(rc == TILEDB_OK);
321 rc = tiledb_query_submit(ctx_, query);
322 REQUIRE(rc == TILEDB_OK);
323 rc = tiledb_query_finalize(ctx_, query);
324 REQUIRE(rc == TILEDB_OK);
325
326 int a_c[] = {0, 1};
327 int64_t coords_c[] = {-1, 1};
328 CHECK(a_size == sizeof(a_c));
329 CHECK(coords_size == sizeof(coords_c));
330 CHECK(!memcmp(a, a_c, sizeof(a_c)));
331 CHECK(!memcmp(coords, coords_c, sizeof(coords_c)));
332
333 // Close array
334 rc = tiledb_array_close(ctx_, array);
335 CHECK(rc == TILEDB_OK);
336
337 // Clean up
338 tiledb_array_free(&array);
339 tiledb_query_free(&query);
340 }
341
read_sparse_array_row(const std::string & path)342 void SparseNegFx2::read_sparse_array_row(const std::string& path) {
343 // Open array
344 tiledb_array_t* array;
345 int rc = tiledb_array_alloc(ctx_, path.c_str(), &array);
346 CHECK(rc == TILEDB_OK);
347 rc = tiledb_array_open(ctx_, array, TILEDB_READ);
348 CHECK(rc == TILEDB_OK);
349
350 int a[4];
351 uint64_t a_size = sizeof(a);
352 int64_t coords_dim1[4];
353 int64_t coords_dim2[4];
354 uint64_t coords_size = sizeof(coords_dim1);
355 tiledb_query_t* query;
356 rc = tiledb_query_alloc(ctx_, array, TILEDB_READ, &query);
357 REQUIRE(rc == TILEDB_OK);
358 rc = tiledb_query_set_data_buffer(ctx_, query, "a", a, &a_size);
359 REQUIRE(rc == TILEDB_OK);
360 rc = tiledb_query_set_data_buffer(
361 ctx_, query, "d1", coords_dim1, &coords_size);
362 REQUIRE(rc == TILEDB_OK);
363 rc = tiledb_query_set_data_buffer(
364 ctx_, query, "d2", coords_dim2, &coords_size);
365 REQUIRE(rc == TILEDB_OK);
366
367 // Create some subarray
368 int64_t s0[] = {-2, 1};
369 int64_t s1[] = {-2, 1};
370 rc = tiledb_query_set_layout(ctx_, query, TILEDB_ROW_MAJOR);
371 REQUIRE(rc == TILEDB_OK);
372 rc = tiledb_query_add_range(ctx_, query, 0, &s0[0], &s0[1], nullptr);
373 REQUIRE(rc == TILEDB_OK);
374 rc = tiledb_query_add_range(ctx_, query, 1, &s1[0], &s1[1], nullptr);
375 REQUIRE(rc == TILEDB_OK);
376
377 rc = tiledb_query_submit(ctx_, query);
378 REQUIRE(rc == TILEDB_OK);
379 rc = tiledb_query_finalize(ctx_, query);
380 REQUIRE(rc == TILEDB_OK);
381
382 int a_c[] = {1, 3, 4, 2};
383 int64_t coords_c_dim1[] = {-2, -1, 1, 1};
384 int64_t coords_c_dim2[] = {0, -1, -1, 1};
385 CHECK(a_size == sizeof(a_c));
386 CHECK(coords_size == sizeof(coords_c_dim1));
387 CHECK(!memcmp(a, a_c, sizeof(a_c)));
388 CHECK(!memcmp(coords_dim1, coords_c_dim1, sizeof(coords_c_dim1)));
389 CHECK(!memcmp(coords_dim2, coords_c_dim2, sizeof(coords_c_dim2)));
390
391 // Close array
392 rc = tiledb_array_close(ctx_, array);
393 CHECK(rc == TILEDB_OK);
394
395 // Clean up
396 tiledb_array_free(&array);
397 tiledb_query_free(&query);
398 }
399
read_sparse_array_col(const std::string & path)400 void SparseNegFx2::read_sparse_array_col(const std::string& path) {
401 // Open array
402 tiledb_array_t* array;
403 int rc = tiledb_array_alloc(ctx_, path.c_str(), &array);
404 CHECK(rc == TILEDB_OK);
405 rc = tiledb_array_open(ctx_, array, TILEDB_READ);
406 CHECK(rc == TILEDB_OK);
407
408 int a[4];
409 uint64_t a_size = sizeof(a);
410 int64_t coords_dim1[4];
411 int64_t coords_dim2[4];
412 uint64_t coords_size = sizeof(coords_dim1);
413 tiledb_query_t* query;
414 rc = tiledb_query_alloc(ctx_, array, TILEDB_READ, &query);
415 REQUIRE(rc == TILEDB_OK);
416 rc = tiledb_query_set_data_buffer(ctx_, query, "a", a, &a_size);
417 REQUIRE(rc == TILEDB_OK);
418 rc = tiledb_query_set_data_buffer(
419 ctx_, query, "d1", coords_dim1, &coords_size);
420 REQUIRE(rc == TILEDB_OK);
421 rc = tiledb_query_set_data_buffer(
422 ctx_, query, "d2", coords_dim2, &coords_size);
423 REQUIRE(rc == TILEDB_OK);
424
425 // Set some subarray
426 int64_t s0[] = {-2, 1};
427 int64_t s1[] = {-2, 1};
428 rc = tiledb_query_set_layout(ctx_, query, TILEDB_COL_MAJOR);
429 REQUIRE(rc == TILEDB_OK);
430 rc = tiledb_query_add_range(ctx_, query, 0, &s0[0], &s0[1], nullptr);
431 REQUIRE(rc == TILEDB_OK);
432 rc = tiledb_query_add_range(ctx_, query, 1, &s1[0], &s0[1], nullptr);
433 REQUIRE(rc == TILEDB_OK);
434
435 rc = tiledb_query_submit(ctx_, query);
436 REQUIRE(rc == TILEDB_OK);
437 rc = tiledb_query_finalize(ctx_, query);
438 REQUIRE(rc == TILEDB_OK);
439
440 int a_c[] = {3, 4, 1, 2};
441 int64_t coords_c_dim1[] = {-1, 1, -2, 1};
442 int64_t coords_c_dim2[] = {-1, -1, 0, 1};
443 CHECK(a_size == sizeof(a_c));
444 CHECK(coords_size == sizeof(coords_c_dim1));
445 CHECK(!memcmp(a, a_c, sizeof(a_c)));
446 CHECK(!memcmp(coords_dim1, coords_c_dim1, sizeof(coords_c_dim1)));
447 CHECK(!memcmp(coords_dim2, coords_c_dim2, sizeof(coords_c_dim2)));
448
449 // Close array
450 rc = tiledb_array_close(ctx_, array);
451 CHECK(rc == TILEDB_OK);
452
453 // Clean up
454 tiledb_array_free(&array);
455 tiledb_query_free(&query);
456 }
457
458 TEST_CASE_METHOD(
459 SparseNegFx2,
460 "C API: Test 1d sparse vector with negative domain 2",
461 "[capi][sparse-neg-2][sparse-neg-vector-2]") {
462 SupportedFsLocal local_fs;
463 std::string vector_name =
464 local_fs.file_prefix() + local_fs.temp_dir() + "sparse_neg_vector";
465 create_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
466
467 create_sparse_vector(vector_name);
468 write_sparse_vector(vector_name);
469 read_sparse_vector(vector_name);
470
471 remove_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
472 }
473
474 TEST_CASE_METHOD(
475 SparseNegFx2,
476 "C API: Test 2d sparse array with negative domain 2",
477 "[capi][sparse-neg-2][sparse-neg-array-2]") {
478 SupportedFsLocal local_fs;
479 std::string vector_name =
480 local_fs.file_prefix() + local_fs.temp_dir() + "sparse_neg_array";
481 create_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
482
483 create_sparse_array(vector_name);
484 write_sparse_array(vector_name);
485 read_sparse_array_row(vector_name);
486 read_sparse_array_col(vector_name);
487
488 remove_temp_dir(local_fs.file_prefix() + local_fs.temp_dir());
489 }
490