tatami_tiledb
tatami bindings for TileDB-backed matrices
Loading...
Searching...
No Matches
DenseMatrix.hpp
Go to the documentation of this file.
1#ifndef TATAMI_TILEDB_DENSE_MATRIX_HPP
2#define TATAMI_TILEDB_DENSE_MATRIX_HPP
3
4#include "tatami_chunked/tatami_chunked.hpp"
5#include <tiledb/tiledb>
6
7#include "serialize.hpp"
8#include "utils.hpp"
9
10#include <string>
11#include <memory>
12#include <vector>
13#include <type_traits>
14
20namespace tatami_tiledb {
21
37 size_t maximum_cache_size = 100000000;
38
45};
46
50namespace DenseMatrix_internal {
51
52typedef ::tatami_tiledb::internal::Components Components;
53typedef ::tatami_tiledb::internal::VariablyTypedDimension Dimension;
54typedef ::tatami_tiledb::internal::VariablyTypedVector CacheBuffer;
55
56inline void execute_query(const Components& tdb_comp, const tiledb::Subarray& subarray, const std::string& attribute, bool row, CacheBuffer& buffer, size_t offset, size_t length) {
57 tiledb::Query query(tdb_comp.ctx, tdb_comp.array);
58 query.set_subarray(subarray);
59 query.set_layout(row ? TILEDB_ROW_MAJOR : TILEDB_COL_MAJOR);
60 buffer.set_data_buffer(query, attribute, offset, length);
61 if (query.submit() != tiledb::Query::Status::COMPLETE) {
62 throw std::runtime_error("failed to read dense data from TileDB");
63 }
64}
65
66/********************
67 *** Core classes ***
68 ********************/
69
70template<typename Index_>
71struct CacheParameters {
72 Index_ chunk_length;
73 size_t slab_size_in_elements;
74 size_t max_slabs_in_cache;
75};
76
77template<typename Index_>
78class MyopicCore {
79public:
80 MyopicCore(
81 const Components& tdb_comp,
82 const std::string& attribute,
83 bool row,
84 Index_ target_dim_extent,
85 const Dimension& tdb_target_dim,
86 const Dimension& tdb_non_target_dim,
87 tiledb_datatype_t tdb_type,
88 Index_ non_target_length,
89 [[maybe_unused]] tatami::MaybeOracle<false, Index_> oracle, // for consistency with the oracular version.
90 const CacheParameters<Index_>& cache_stats) :
91 my_tdb_comp(tdb_comp),
92 my_attribute(attribute),
93 my_row(row),
94 my_target_dim_extent(target_dim_extent),
95 my_tdb_target_dim(tdb_target_dim),
96 my_tdb_non_target_dim(tdb_non_target_dim),
97 my_non_target_length(non_target_length),
98 my_target_chunk_length(cache_stats.chunk_length),
99 my_slab_size(cache_stats.slab_size_in_elements),
100 my_holding(tdb_type, my_slab_size * cache_stats.max_slabs_in_cache),
101 my_cache(cache_stats.max_slabs_in_cache)
102 {}
103
104private:
105 const Components& my_tdb_comp;
106 const std::string& my_attribute;
107
108 bool my_row;
109 Index_ my_target_dim_extent;
110 const Dimension& my_tdb_target_dim;
111 const Dimension& my_tdb_non_target_dim;
112
113 Index_ my_non_target_length;
114 Index_ my_target_chunk_length;
115 size_t my_slab_size;
116 CacheBuffer my_holding;
117
118 struct Slab {
119 size_t offset;
120 };
121 size_t my_offset = 0;
122 tatami_chunked::LruSlabCache<Index_, Slab> my_cache;
123
124private:
125 template<typename Value_, class Configure_>
126 const Value_* fetch_raw(Index_ i, Value_* buffer, Configure_ configure) {
127 Index_ chunk = i / my_target_chunk_length;
128 Index_ index = i % my_target_chunk_length;
129
130 const auto& info = my_cache.find(
131 chunk,
132 /* create = */ [&]() -> Slab {
133 Slab output;
134 output.offset = my_offset;
135 my_offset += my_slab_size;
136 return output;
137 },
138 /* populate = */ [&](Index_ id, Slab& contents) -> void {
139 Index_ target_start = id * my_target_chunk_length;
140 Index_ target_length = std::min(my_target_dim_extent - target_start, my_target_chunk_length);
141
142 serialize([&]() -> void {
143 tiledb::Subarray subarray(my_tdb_comp.ctx, my_tdb_comp.array);
144 int rowdex = my_row;
145 configure(subarray, rowdex);
146 my_tdb_target_dim.add_range(subarray, 1 - rowdex, target_start, target_length);
147 execute_query(my_tdb_comp, subarray, my_attribute, my_row, my_holding, contents.offset, my_slab_size);
148 });
149 }
150 );
151
152 size_t final_offset = info.offset + static_cast<size_t>(my_non_target_length) * static_cast<size_t>(index); // cast to size_t to avoid overflow
153 my_holding.copy(final_offset, my_non_target_length, buffer);
154 return buffer;
155 }
156
157public:
158 template<typename Value_>
159 const Value_* fetch_block(Index_ i, Index_ block_start, Value_* buffer) {
160 return fetch_raw(i, buffer, [&](tiledb::Subarray& subarray, int rowdex) {
161 my_tdb_non_target_dim.add_range(subarray, rowdex, block_start, my_non_target_length);
162 });
163 }
164
165 template<typename Value_>
166 const Value_* fetch_indices(Index_ i, const std::vector<Index_>& indices, Value_* buffer) {
167 return fetch_raw(i, buffer, [&](tiledb::Subarray& subarray, int rowdex) {
168 tatami::process_consecutive_indices<Index_>(indices.data(), indices.size(), [&](Index_ s, Index_ l) {
169 my_tdb_non_target_dim.add_range(subarray, rowdex, s, l);
170 });
171 });
172 }
173};
174
175template<typename Index_>
176class OracularCore {
177public:
178 OracularCore(
179 const Components& tdb_comp,
180 const std::string& attribute,
181 bool row,
182 Index_ target_dim_extent,
183 const Dimension& tdb_target_dim,
184 const Dimension& tdb_non_target_dim,
185 tiledb_datatype_t tdb_type,
186 Index_ non_target_length,
188 const CacheParameters<Index_>& cache_stats) :
189 my_tdb_comp(tdb_comp),
190 my_attribute(attribute),
191 my_row(row),
192 my_target_dim_extent(target_dim_extent),
193 my_tdb_target_dim(tdb_target_dim),
194 my_tdb_non_target_dim(tdb_non_target_dim),
195 my_non_target_length(non_target_length),
196 my_target_chunk_length(cache_stats.chunk_length),
197 my_slab_size(cache_stats.slab_size_in_elements),
198 my_holding(tdb_type, my_slab_size * cache_stats.max_slabs_in_cache),
199 my_cache(std::move(oracle), cache_stats.max_slabs_in_cache)
200 {}
201
202private:
203 const Components& my_tdb_comp;
204 const std::string& my_attribute;
205
206 bool my_row;
207 Index_ my_target_dim_extent;
208 const Dimension& my_tdb_target_dim;
209 const Dimension& my_tdb_non_target_dim;
210
211 Index_ my_non_target_length;
212 Index_ my_target_chunk_length;
213 size_t my_slab_size;
214 CacheBuffer my_holding;
215
216 struct Slab {
217 size_t offset;
218 };
219 size_t my_offset = 0;
220 tatami_chunked::OracularSlabCache<Index_, Index_, Slab, true> my_cache;
221
222private:
223 template<class Function_>
224 static void sort_by_field(std::vector<std::pair<Index_, Slab*> >& indices, Function_ field) {
225 auto comp = [&field](const std::pair<Index_, Slab*>& l, const std::pair<Index_, Slab*>& r) -> bool {
226 return field(l) < field(r);
227 };
228 if (!std::is_sorted(indices.begin(), indices.end(), comp)) {
229 std::sort(indices.begin(), indices.end(), comp);
230 }
231 }
232
233 template<typename Value_, class Configure_>
234 const Value_* fetch_raw([[maybe_unused]] Index_ i, Value_* buffer, Configure_ configure) {
235 auto info = my_cache.next(
236 /* identify = */ [&](Index_ current) -> std::pair<Index_, Index_> {
237 return std::pair<Index_, Index_>(current / my_target_chunk_length, current % my_target_chunk_length);
238 },
239 /* create = */ [&]() -> Slab {
240 Slab output;
241 output.offset = my_offset;
242 my_offset += my_slab_size;
243 return output;
244 },
245 /* populate = */ [&](std::vector<std::pair<Index_, Slab*> >& to_populate, std::vector<std::pair<Index_, Slab*> >& to_reuse) {
246 // Defragmenting the existing chunks. We sort by offset to make
247 // sure that we're not clobbering in-use slabs during the copy().
248 sort_by_field(to_reuse, [](const std::pair<Index_, Slab*>& x) -> size_t { return x.second->offset; });
249 size_t running_offset = 0;
250 for (auto& x : to_reuse) {
251 auto& cur_offset = x.second->offset;
252 if (cur_offset != running_offset) {
253 my_holding.shift(cur_offset, my_slab_size, running_offset);
254 cur_offset = running_offset;
255 }
256 running_offset += my_slab_size;
257 }
258
259 // Collapsing runs of consecutive ranges into a single range;
260 // otherwise, making union of ranges. This allows a single TileDb call
261 // to populate the contiguous memory pool that we made available after
262 // defragmentation; then we just update the slab pointers to refer
263 // to the slices of memory corresponding to each slab.
264 sort_by_field(to_populate, [](const std::pair<Index_, Slab*>& x) -> Index_ { return x.first; });
265
266 serialize([&]() -> void {
267 tiledb::Subarray subarray(my_tdb_comp.ctx, my_tdb_comp.array);
268 int rowdex = my_row;
269 configure(subarray, rowdex);
270
271 // Remember, the slab size is equal to the product of the chunk length and the
272 // non-target length, so shifting the memory pool offsets by 'slab_size' will
273 // correspond to a shift of 'chunk_length' on the target dimension. The only
274 // exception is that of the last chunk, but at that point it doesn't matter as
275 // there's no data following the last chunk.
276 Index_ run_chunk_id = to_populate.front().first;
277 Index_ run_chunk_start = run_chunk_id * my_target_chunk_length;
278 Index_ run_length = std::min(my_target_dim_extent - run_chunk_start, my_target_chunk_length);
279
280 to_populate.front().second->offset = running_offset;
281 auto start_offset = running_offset;
282 running_offset += my_slab_size;
283
284 int dimdex = 1 - rowdex;
285 for (size_t ci = 1, cend = to_populate.size(); ci < cend; ++ci) {
286 auto& current_chunk = to_populate[ci];
287 Index_ current_chunk_id = current_chunk.first;
288 Index_ current_chunk_start = current_chunk_id * my_target_chunk_length;
289
290 if (current_chunk_id - run_chunk_id > 1) { // save the existing run of to_populate as one range, and start a new run.
291 my_tdb_target_dim.add_range(subarray, dimdex, run_chunk_start, run_length);
292 run_chunk_id = current_chunk_id;
293 run_chunk_start = current_chunk_start;
294 run_length = 0;
295 }
296
297 Index_ current_length = std::min(my_target_dim_extent - current_chunk_start, my_target_chunk_length);
298 run_length += current_length;
299 current_chunk.second->offset = running_offset;
300 running_offset += my_slab_size;
301 }
302
303 my_tdb_target_dim.add_range(subarray, dimdex, run_chunk_start, run_length);
304 execute_query(my_tdb_comp, subarray, my_attribute, my_row, my_holding, start_offset, running_offset - start_offset);
305 });
306 }
307 );
308
309 size_t final_offset = info.first->offset + my_non_target_length * static_cast<size_t>(info.second); // cast to size_t to avoid overflow
310 my_holding.copy(final_offset, my_non_target_length, buffer);
311 return buffer;
312 }
313
314public:
315 template<typename Value_>
316 const Value_* fetch_block(Index_ i, Index_ block_start, Value_* buffer) {
317 return fetch_raw(i, buffer, [&](tiledb::Subarray& subarray, int rowdex) {
318 my_tdb_non_target_dim.add_range(subarray, rowdex, block_start, my_non_target_length);
319 });
320 }
321
322 template<typename Value_>
323 const Value_* fetch_indices(Index_ i, const std::vector<Index_>& indices, Value_* buffer) {
324 return fetch_raw(i, buffer, [&](tiledb::Subarray& subarray, int rowdex) {
325 tatami::process_consecutive_indices<Index_>(indices.data(), indices.size(), [&](Index_ s, Index_ l) {
326 my_tdb_non_target_dim.add_range(subarray, rowdex, s, l);
327 });
328 });
329 }
330};
331
332template<bool oracle_, typename Index_>
333using DenseCore = typename std::conditional<oracle_, OracularCore<Index_>, MyopicCore<Index_> >::type;
334
335/***************************
336 *** Concrete subclasses ***
337 ***************************/
338
339template<bool oracle_, typename Value_, typename Index_>
340class Full : public tatami::DenseExtractor<oracle_, Value_, Index_> {
341public:
342 Full(
343 const Components& tdb_comp,
344 const std::string& attribute,
345 bool row,
346 Index_ target_dim_extent,
347 const Dimension& tdb_target_dim,
348 const Dimension& tdb_non_target_dim,
349 tiledb_datatype_t tdb_type,
351 Index_ non_target_dim,
352 const CacheParameters<Index_>& cache_stats) :
353 my_core(
354 tdb_comp,
355 attribute,
356 row,
357 target_dim_extent,
358 tdb_target_dim,
359 tdb_non_target_dim,
360 tdb_type,
361 non_target_dim,
362 std::move(oracle),
363 cache_stats
364 )
365 {}
366
367 const Value_* fetch(Index_ i, Value_* buffer) {
368 return my_core.fetch_block(i, 0, buffer);
369 }
370
371private:
372 DenseCore<oracle_, Index_> my_core;
373};
374
375template<bool oracle_, typename Value_, typename Index_>
376class Block : public tatami::DenseExtractor<oracle_, Value_, Index_> {
377public:
378 Block(
379 const Components& tdb_comp,
380 const std::string& attribute,
381 bool row,
382 Index_ target_dim_extent,
383 const Dimension& tdb_target_dim,
384 const Dimension& tdb_non_target_dim,
385 tiledb_datatype_t tdb_type,
387 Index_ block_start,
388 Index_ block_length,
389 const CacheParameters<Index_>& cache_stats) :
390 my_core(
391 tdb_comp,
392 attribute,
393 row,
394 target_dim_extent,
395 tdb_target_dim,
396 tdb_non_target_dim,
397 tdb_type,
398 block_length,
399 std::move(oracle),
400 cache_stats
401 ),
402 my_block_start(block_start)
403 {}
404
405 const Value_* fetch(Index_ i, Value_* buffer) {
406 return my_core.fetch_block(i, my_block_start, buffer);
407 }
408
409private:
410 DenseCore<oracle_, Index_> my_core;
411 Index_ my_block_start;
412};
413
414template<bool oracle_, typename Value_, typename Index_>
415class Index : public tatami::DenseExtractor<oracle_, Value_, Index_> {
416public:
417 Index(
418 const Components& tdb_comp,
419 const std::string& attribute,
420 bool row,
421 Index_ target_dim_extent,
422 const Dimension& tdb_target_dim,
423 const Dimension& tdb_non_target_dim,
424 tiledb_datatype_t tdb_type,
426 tatami::VectorPtr<Index_> indices_ptr,
427 const CacheParameters<Index_>& cache_stats) :
428 my_core(
429 tdb_comp,
430 attribute,
431 row,
432 target_dim_extent,
433 tdb_target_dim,
434 tdb_non_target_dim,
435 tdb_type,
436 indices_ptr->size(),
437 std::move(oracle),
438 cache_stats
439 ),
440 my_indices_ptr(std::move(indices_ptr))
441 {}
442
443 const Value_* fetch(Index_ i, Value_* buffer) {
444 return my_core.fetch_indices(i, *my_indices_ptr, buffer);
445 }
446
447private:
448 DenseCore<oracle_, Index_> my_core;
449 tatami::VectorPtr<Index_> my_indices_ptr;
450};
451
452}
471template<typename Value_, typename Index_>
472class DenseMatrix : public tatami::Matrix<Value_, Index_> {
473public:
480 DenseMatrix(const std::string& uri, std::string attribute, tiledb::Context ctx, const DenseMatrixOptions& options) : my_attribute(std::move(attribute)) {
481 initialize(uri, std::move(ctx), options);
482 }
483
489 DenseMatrix(const std::string& uri, std::string attribute, const DenseMatrixOptions& options) : my_attribute(std::move(attribute)) {
490 initialize(uri, false, options);
491 }
492
497 DenseMatrix(const std::string& uri, std::string attribute) : DenseMatrix(uri, std::move(attribute), DenseMatrixOptions()) {}
498
499private:
500 template<class PossibleContext_>
501 void initialize(const std::string& uri, PossibleContext_ ctx, const DenseMatrixOptions& options) {
502 serialize([&]() {
503 my_tdb_comp.reset(
504 [&]{
505 // If we have to create our own Context_ object, we do so inside the serialized
506 // section, rather than using a delegating constructor.
507 if constexpr(std::is_same<PossibleContext_, tiledb::Context>::value) {
508 return new DenseMatrix_internal::Components(std::move(ctx), uri);
509 } else {
510 return new DenseMatrix_internal::Components(uri);
511 }
512 }(),
513 [](DenseMatrix_internal::Components* ptr) {
514 // Serializing the deleter, for completeness's sake.
515 serialize([&]() {
516 delete ptr;
517 });
518 }
519 );
520
521 auto schema = my_tdb_comp->array.schema();
522 if (schema.array_type() != TILEDB_DENSE) {
523 throw std::runtime_error("TileDB array should be dense");
524 }
525
526 if (!schema.has_attribute(my_attribute)) {
527 throw std::runtime_error("no attribute '" + my_attribute + "' is present in the TileDB array");
528 }
529 auto attr = schema.attribute(my_attribute);
530 my_tdb_type = attr.type();
531
532 my_cache_size_in_elements = options.maximum_cache_size / internal::determine_type_size(my_tdb_type);
533 my_require_minimum_cache = options.require_minimum_cache;
534
535 tiledb::Domain domain = schema.domain();
536 if (domain.ndim() != 2) {
537 throw std::runtime_error("TileDB array should have exactly two dimensions");
538 }
539
540 tiledb::Dimension first_dim = domain.dimension(0);
541 my_tdb_first_dim.reset(first_dim);
542 Index_ first_extent = my_tdb_first_dim.extent<Index_>();
543 Index_ first_tile = my_tdb_first_dim.tile<Index_>();
544 my_firstdim_stats = tatami_chunked::ChunkDimensionStats<Index_>(first_extent, first_tile);
545
546 tiledb::Dimension second_dim = domain.dimension(1);
547 my_tdb_second_dim.reset(second_dim);
548 Index_ second_extent = my_tdb_second_dim.extent<Index_>();
549 Index_ second_tile = my_tdb_second_dim.tile<Index_>();
550 my_seconddim_stats = tatami_chunked::ChunkDimensionStats<Index_>(second_extent, second_tile);
551
552 // Favoring extraction on the dimension that involves pulling out fewer chunks per dimension element.
553 auto tiles_per_firstdim = (second_extent / second_tile) + (second_extent % second_tile > 0);
554 auto tiles_per_seconddim = (first_extent / first_tile) + (first_extent % first_tile > 0);
555 my_prefer_firstdim = tiles_per_firstdim <= tiles_per_seconddim;
556 });
557 }
558
559private:
560 std::shared_ptr<DenseMatrix_internal::Components> my_tdb_comp;
561
562 DenseMatrix_internal::Dimension my_tdb_first_dim, my_tdb_second_dim;
563 tiledb_datatype_t my_tdb_type;
564
565 std::string my_attribute;
566 size_t my_cache_size_in_elements;
567 bool my_require_minimum_cache;
568
569 int my_first_offset, my_second_offset;
570 tatami_chunked::ChunkDimensionStats<Index_> my_firstdim_stats, my_seconddim_stats;
571 bool my_prefer_firstdim;
572
573private:
574 Index_ nrow_internal() const {
575 return my_firstdim_stats.dimension_extent;
576 }
577
578 Index_ ncol_internal() const {
579 return my_seconddim_stats.dimension_extent;
580 }
581
582public:
583 Index_ nrow() const {
584 return nrow_internal();
585 }
586
587 Index_ ncol() const {
588 return ncol_internal();
589 }
590
591 bool is_sparse() const {
592 return false;
593 }
594
595 double is_sparse_proportion() const {
596 return 0;
597 }
598
599 bool prefer_rows() const {
600 return my_prefer_firstdim;
601 }
602
603 double prefer_rows_proportion() const {
604 return static_cast<double>(my_prefer_firstdim);
605 }
606
607 bool uses_oracle(bool) const {
608 // The oracle won't necessarily be used if the cache size is non-zero,
609 // but if the cache is empty, the oracle definitely _won't_ be used.
610 return my_cache_size_in_elements > 0;
611 }
612
613private:
614 template<bool oracle_, template<bool, typename, typename> class Extractor_, typename ... Args_>
615 std::unique_ptr<tatami::DenseExtractor<oracle_, Value_, Index_> > populate(bool row, Index_ non_target_length, tatami::MaybeOracle<oracle_, Index_> oracle, Args_&& ... args) const {
616 const auto& target_dim_stats = (row ? my_firstdim_stats : my_seconddim_stats);
617 const auto& tdb_target_dim = (row ? my_tdb_first_dim : my_tdb_second_dim);
618 const auto& tdb_non_target_dim = (row ? my_tdb_second_dim : my_tdb_first_dim);
619
620 tatami_chunked::SlabCacheStats slab_stats(
621 target_dim_stats.chunk_length,
622 non_target_length,
623 target_dim_stats.num_chunks,
624 my_cache_size_in_elements,
625 my_require_minimum_cache
626 );
627
628 // No need to have a dedicated SoloCore for uncached extraction,
629 // because it would still need to hold a single Workspace. We instead
630 // reuse the existing code with a chunk length of 1 to achieve the same
631 // memory usage. This has a mild perf hit from the caching machinery
632 // but perf already sucks without caching so who cares.
633 DenseMatrix_internal::CacheParameters<Index_> cache_params;
634 if (slab_stats.max_slabs_in_cache > 0) {
635 cache_params.chunk_length = target_dim_stats.chunk_length;
636 cache_params.slab_size_in_elements = slab_stats.slab_size_in_elements;
637 cache_params.max_slabs_in_cache = slab_stats.max_slabs_in_cache;
638 } else {
639 cache_params.chunk_length = 1;
640 cache_params.slab_size_in_elements = non_target_length;
641 cache_params.max_slabs_in_cache = 1;
642 }
643
644 return std::make_unique<Extractor_<oracle_, Value_, Index_> >(
645 *my_tdb_comp,
646 my_attribute,
647 row,
648 target_dim_stats.dimension_extent,
649 tdb_target_dim,
650 tdb_non_target_dim,
651 my_tdb_type,
652 std::move(oracle),
653 std::forward<Args_>(args)...,
654 cache_params
655 );
656 }
657
658 /********************
659 *** Myopic dense ***
660 ********************/
661public:
662 std::unique_ptr<tatami::MyopicDenseExtractor<Value_, Index_> > dense(bool row, const tatami::Options&) const {
663 Index_ full_non_target = (row ? ncol_internal() : nrow_internal());
664 return populate<false, DenseMatrix_internal::Full>(row, full_non_target, false, full_non_target);
665 }
666
667 std::unique_ptr<tatami::MyopicDenseExtractor<Value_, Index_> > dense(bool row, Index_ block_start, Index_ block_length, const tatami::Options&) const {
668 return populate<false, DenseMatrix_internal::Block>(row, block_length, false, block_start, block_length);
669 }
670
671 std::unique_ptr<tatami::MyopicDenseExtractor<Value_, Index_> > dense(bool row, tatami::VectorPtr<Index_> indices_ptr, const tatami::Options&) const {
672 auto nidx = indices_ptr->size();
673 return populate<false, DenseMatrix_internal::Index>(row, nidx, false, std::move(indices_ptr));
674 }
675
676 /*********************
677 *** Myopic sparse ***
678 *********************/
679public:
680 std::unique_ptr<tatami::MyopicSparseExtractor<Value_, Index_> > sparse(bool row, const tatami::Options& opt) const {
681 Index_ full_non_target = (row ? ncol_internal() : nrow_internal());
682 return std::make_unique<tatami::FullSparsifiedWrapper<false, Value_, Index_> >(dense(row, opt), full_non_target, opt);
683 }
684
685 std::unique_ptr<tatami::MyopicSparseExtractor<Value_, Index_> > sparse(bool row, Index_ block_start, Index_ block_length, const tatami::Options& opt) const {
686 return std::make_unique<tatami::BlockSparsifiedWrapper<false, Value_, Index_> >(dense(row, block_start, block_length, opt), block_start, block_length, opt);
687 }
688
689 std::unique_ptr<tatami::MyopicSparseExtractor<Value_, Index_> > sparse(bool row, tatami::VectorPtr<Index_> indices_ptr, const tatami::Options& opt) const {
690 auto ptr = dense(row, indices_ptr, opt);
691 return std::make_unique<tatami::IndexSparsifiedWrapper<false, Value_, Index_> >(std::move(ptr), std::move(indices_ptr), opt);
692 }
693
694 /**********************
695 *** Oracular dense ***
696 **********************/
697public:
698 std::unique_ptr<tatami::OracularDenseExtractor<Value_, Index_> > dense(
699 bool row,
700 std::shared_ptr<const tatami::Oracle<Index_> > oracle,
701 const tatami::Options&)
702 const {
703 Index_ full_non_target = (row ? ncol_internal() : nrow_internal());
704 return populate<true, DenseMatrix_internal::Full>(row, full_non_target, std::move(oracle), full_non_target);
705 }
706
707 std::unique_ptr<tatami::OracularDenseExtractor<Value_, Index_> > dense(
708 bool row,
709 std::shared_ptr<const tatami::Oracle<Index_> > oracle,
710 Index_ block_start,
711 Index_ block_length,
712 const tatami::Options&)
713 const {
714 return populate<true, DenseMatrix_internal::Block>(row, block_length, std::move(oracle), block_start, block_length);
715 }
716
717 std::unique_ptr<tatami::OracularDenseExtractor<Value_, Index_> > dense(
718 bool row,
719 std::shared_ptr<const tatami::Oracle<Index_> > oracle,
720 tatami::VectorPtr<Index_> indices_ptr,
721 const tatami::Options&)
722 const {
723 auto nidx = indices_ptr->size();
724 return populate<true, DenseMatrix_internal::Index>(row, nidx, std::move(oracle), std::move(indices_ptr));
725 }
726
727 /***********************
728 *** Oracular sparse ***
729 ***********************/
730public:
731 std::unique_ptr<tatami::OracularSparseExtractor<Value_, Index_> > sparse(
732 bool row,
733 std::shared_ptr<const tatami::Oracle<Index_> > oracle,
734 const tatami::Options& opt)
735 const {
736 Index_ full_non_target = (row ? ncol_internal() : nrow_internal());
737 return std::make_unique<tatami::FullSparsifiedWrapper<true, Value_, Index_> >(dense(row, std::move(oracle), opt), full_non_target, opt);
738 }
739
740 std::unique_ptr<tatami::OracularSparseExtractor<Value_, Index_> > sparse(
741 bool row,
742 std::shared_ptr<const tatami::Oracle<Index_> > oracle,
743 Index_ block_start,
744 Index_ block_length,
745 const tatami::Options& opt)
746 const {
747 return std::make_unique<tatami::BlockSparsifiedWrapper<true, Value_, Index_> >(dense(row, std::move(oracle), block_start, block_length, opt), block_start, block_length, opt);
748 }
749
750 std::unique_ptr<tatami::OracularSparseExtractor<Value_, Index_> > sparse(
751 bool row,
752 std::shared_ptr<const tatami::Oracle<Index_> > oracle,
753 tatami::VectorPtr<Index_> indices_ptr,
754 const tatami::Options& opt)
755 const {
756 auto ptr = dense(row, std::move(oracle), indices_ptr, opt);
757 return std::make_unique<tatami::IndexSparsifiedWrapper<true, Value_, Index_> >(std::move(ptr), std::move(indices_ptr), opt);
758 }
759};
760
761}
762
763#endif
TileDB-backed dense matrix.
Definition DenseMatrix.hpp:472
DenseMatrix(const std::string &uri, std::string attribute, tiledb::Context ctx, const DenseMatrixOptions &options)
Definition DenseMatrix.hpp:480
DenseMatrix(const std::string &uri, std::string attribute, const DenseMatrixOptions &options)
Definition DenseMatrix.hpp:489
DenseMatrix(const std::string &uri, std::string attribute)
Definition DenseMatrix.hpp:497
tatami bindings for TileDB matrices.
Definition DenseMatrix.hpp:20
void serialize(Function_ fun)
Definition serialize.hpp:20
typename std::conditional< oracle_, OracularDenseExtractor< Value_, Index_ >, MyopicDenseExtractor< Value_, Index_ > >::type DenseExtractor
typename std::conditional< oracle_, std::shared_ptr< const Oracle< Index_ > >, bool >::type MaybeOracle
std::shared_ptr< const std::vector< Index_ > > VectorPtr
void process_consecutive_indices(const Index_ *indices, Index_ length, Function_ fun)
Locking for serial access.
Options for dense TileDB extraction.
Definition DenseMatrix.hpp:27
bool require_minimum_cache
Definition DenseMatrix.hpp:44
size_t maximum_cache_size
Definition DenseMatrix.hpp:37