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(
161 i,
162 buffer,
163 [&](tiledb::Subarray& subarray, int rowdex) -> void {
164 my_tdb_non_target_dim.add_range(subarray, rowdex, block_start, my_non_target_length);
165 }
166 );
167 }
168
169 template<typename Value_>
170 const Value_* fetch_indices(Index_ i, const std::vector<Index_>& indices, Value_* buffer) {
171 return fetch_raw(
172 i,
173 buffer,
174 [&](tiledb::Subarray& subarray, int rowdex) -> void {
176 indices.data(),
177 indices.size(),
178 [&](Index_ s, Index_ l) -> void {
179 my_tdb_non_target_dim.add_range(subarray, rowdex, s, l);
180 }
181 );
182 }
183 );
184 }
185};
186
187template<typename Index_>
188class OracularCore {
189public:
190 OracularCore(
191 const Components& tdb_comp,
192 const std::string& attribute,
193 bool row,
194 Index_ target_dim_extent,
195 const Dimension& tdb_target_dim,
196 const Dimension& tdb_non_target_dim,
197 tiledb_datatype_t tdb_type,
198 Index_ non_target_length,
200 const CacheParameters<Index_>& cache_stats) :
201 my_tdb_comp(tdb_comp),
202 my_attribute(attribute),
203 my_row(row),
204 my_target_dim_extent(target_dim_extent),
205 my_tdb_target_dim(tdb_target_dim),
206 my_tdb_non_target_dim(tdb_non_target_dim),
207 my_non_target_length(non_target_length),
208 my_target_chunk_length(cache_stats.chunk_length),
209 my_slab_size(cache_stats.slab_size_in_elements),
210 my_holding(tdb_type, my_slab_size * cache_stats.max_slabs_in_cache),
211 my_cache(std::move(oracle), cache_stats.max_slabs_in_cache)
212 {}
213
214private:
215 const Components& my_tdb_comp;
216 const std::string& my_attribute;
217
218 bool my_row;
219 Index_ my_target_dim_extent;
220 const Dimension& my_tdb_target_dim;
221 const Dimension& my_tdb_non_target_dim;
222
223 Index_ my_non_target_length;
224 Index_ my_target_chunk_length;
225 size_t my_slab_size;
226 CacheBuffer my_holding;
227
228 struct Slab {
229 size_t offset;
230 };
231 size_t my_offset = 0;
232 tatami_chunked::OracularSlabCache<Index_, Index_, Slab, true> my_cache;
233
234private:
235 template<class Function_>
236 static void sort_by_field(std::vector<std::pair<Index_, Slab*> >& indices, Function_ field) {
237 auto comp = [&field](const std::pair<Index_, Slab*>& l, const std::pair<Index_, Slab*>& r) -> bool {
238 return field(l) < field(r);
239 };
240 if (!std::is_sorted(indices.begin(), indices.end(), comp)) {
241 std::sort(indices.begin(), indices.end(), comp);
242 }
243 }
244
245 template<typename Value_, class Configure_>
246 const Value_* fetch_raw([[maybe_unused]] Index_ i, Value_* buffer, Configure_ configure) {
247 auto info = my_cache.next(
248 /* identify = */ [&](Index_ current) -> std::pair<Index_, Index_> {
249 return std::pair<Index_, Index_>(current / my_target_chunk_length, current % my_target_chunk_length);
250 },
251 /* create = */ [&]() -> Slab {
252 Slab output;
253 output.offset = my_offset;
254 my_offset += my_slab_size;
255 return output;
256 },
257 /* populate = */ [&](std::vector<std::pair<Index_, Slab*> >& to_populate, std::vector<std::pair<Index_, Slab*> >& to_reuse) -> void {
258 // Defragmenting the existing chunks. We sort by offset to make
259 // sure that we're not clobbering in-use slabs during the copy().
260 sort_by_field(to_reuse, [](const std::pair<Index_, Slab*>& x) -> size_t { return x.second->offset; });
261 size_t running_offset = 0;
262 for (auto& x : to_reuse) {
263 auto& cur_offset = x.second->offset;
264 if (cur_offset != running_offset) {
265 my_holding.shift(cur_offset, my_slab_size, running_offset);
266 cur_offset = running_offset;
267 }
268 running_offset += my_slab_size;
269 }
270
271 // Collapsing runs of consecutive ranges into a single range;
272 // otherwise, making union of ranges. This allows a single TileDb call
273 // to populate the contiguous memory pool that we made available after
274 // defragmentation; then we just update the slab pointers to refer
275 // to the slices of memory corresponding to each slab.
276 sort_by_field(to_populate, [](const std::pair<Index_, Slab*>& x) -> Index_ { return x.first; });
277
278 serialize([&]() -> void {
279 tiledb::Subarray subarray(my_tdb_comp.ctx, my_tdb_comp.array);
280 int rowdex = my_row;
281 configure(subarray, rowdex);
282
283 // Remember, the slab size is equal to the product of the chunk length and the
284 // non-target length, so shifting the memory pool offsets by 'slab_size' will
285 // correspond to a shift of 'chunk_length' on the target dimension. The only
286 // exception is that of the last chunk, but at that point it doesn't matter as
287 // there's no data following the last chunk.
288 Index_ run_chunk_id = to_populate.front().first;
289 Index_ run_chunk_start = run_chunk_id * my_target_chunk_length;
290 Index_ run_length = std::min(my_target_dim_extent - run_chunk_start, my_target_chunk_length);
291
292 to_populate.front().second->offset = running_offset;
293 auto start_offset = running_offset;
294 running_offset += my_slab_size;
295
296 int dimdex = 1 - rowdex;
297 for (size_t ci = 1, cend = to_populate.size(); ci < cend; ++ci) {
298 auto& current_chunk = to_populate[ci];
299 Index_ current_chunk_id = current_chunk.first;
300 Index_ current_chunk_start = current_chunk_id * my_target_chunk_length;
301
302 if (current_chunk_id - run_chunk_id > 1) { // save the existing run of to_populate as one range, and start a new run.
303 my_tdb_target_dim.add_range(subarray, dimdex, run_chunk_start, run_length);
304 run_chunk_id = current_chunk_id;
305 run_chunk_start = current_chunk_start;
306 run_length = 0;
307 }
308
309 Index_ current_length = std::min(my_target_dim_extent - current_chunk_start, my_target_chunk_length);
310 run_length += current_length;
311 current_chunk.second->offset = running_offset;
312 running_offset += my_slab_size;
313 }
314
315 my_tdb_target_dim.add_range(subarray, dimdex, run_chunk_start, run_length);
316 execute_query(my_tdb_comp, subarray, my_attribute, my_row, my_holding, start_offset, running_offset - start_offset);
317 });
318 }
319 );
320
321 size_t final_offset = info.first->offset + my_non_target_length * static_cast<size_t>(info.second); // cast to size_t to avoid overflow
322 my_holding.copy(final_offset, my_non_target_length, buffer);
323 return buffer;
324 }
325
326public:
327 template<typename Value_>
328 const Value_* fetch_block(Index_ i, Index_ block_start, Value_* buffer) {
329 return fetch_raw(
330 i,
331 buffer,
332 [&](tiledb::Subarray& subarray, int rowdex) -> void {
333 my_tdb_non_target_dim.add_range(subarray, rowdex, block_start, my_non_target_length);
334 }
335 );
336 }
337
338 template<typename Value_>
339 const Value_* fetch_indices(Index_ i, const std::vector<Index_>& indices, Value_* buffer) {
340 return fetch_raw(
341 i,
342 buffer,
343 [&](tiledb::Subarray& subarray, int rowdex) -> void {
345 indices.data(),
346 indices.size(),
347 [&](Index_ s, Index_ l) -> void {
348 my_tdb_non_target_dim.add_range(subarray, rowdex, s, l);
349 }
350 );
351 }
352 );
353 }
354};
355
356template<bool oracle_, typename Index_>
357using DenseCore = typename std::conditional<oracle_, OracularCore<Index_>, MyopicCore<Index_> >::type;
358
359/***************************
360 *** Concrete subclasses ***
361 ***************************/
362
363template<bool oracle_, typename Value_, typename Index_>
364class Full : public tatami::DenseExtractor<oracle_, Value_, Index_> {
365public:
366 Full(
367 const Components& tdb_comp,
368 const std::string& attribute,
369 bool row,
370 Index_ target_dim_extent,
371 const Dimension& tdb_target_dim,
372 const Dimension& tdb_non_target_dim,
373 tiledb_datatype_t tdb_type,
375 Index_ non_target_dim,
376 const CacheParameters<Index_>& cache_stats) :
377 my_core(
378 tdb_comp,
379 attribute,
380 row,
381 target_dim_extent,
382 tdb_target_dim,
383 tdb_non_target_dim,
384 tdb_type,
385 non_target_dim,
386 std::move(oracle),
387 cache_stats
388 )
389 {}
390
391 const Value_* fetch(Index_ i, Value_* buffer) {
392 return my_core.fetch_block(i, 0, buffer);
393 }
394
395private:
396 DenseCore<oracle_, Index_> my_core;
397};
398
399template<bool oracle_, typename Value_, typename Index_>
400class Block : public tatami::DenseExtractor<oracle_, Value_, Index_> {
401public:
402 Block(
403 const Components& tdb_comp,
404 const std::string& attribute,
405 bool row,
406 Index_ target_dim_extent,
407 const Dimension& tdb_target_dim,
408 const Dimension& tdb_non_target_dim,
409 tiledb_datatype_t tdb_type,
411 Index_ block_start,
412 Index_ block_length,
413 const CacheParameters<Index_>& cache_stats) :
414 my_core(
415 tdb_comp,
416 attribute,
417 row,
418 target_dim_extent,
419 tdb_target_dim,
420 tdb_non_target_dim,
421 tdb_type,
422 block_length,
423 std::move(oracle),
424 cache_stats
425 ),
426 my_block_start(block_start)
427 {}
428
429 const Value_* fetch(Index_ i, Value_* buffer) {
430 return my_core.fetch_block(i, my_block_start, buffer);
431 }
432
433private:
434 DenseCore<oracle_, Index_> my_core;
435 Index_ my_block_start;
436};
437
438template<bool oracle_, typename Value_, typename Index_>
439class Index : public tatami::DenseExtractor<oracle_, Value_, Index_> {
440public:
441 Index(
442 const Components& tdb_comp,
443 const std::string& attribute,
444 bool row,
445 Index_ target_dim_extent,
446 const Dimension& tdb_target_dim,
447 const Dimension& tdb_non_target_dim,
448 tiledb_datatype_t tdb_type,
450 tatami::VectorPtr<Index_> indices_ptr,
451 const CacheParameters<Index_>& cache_stats) :
452 my_core(
453 tdb_comp,
454 attribute,
455 row,
456 target_dim_extent,
457 tdb_target_dim,
458 tdb_non_target_dim,
459 tdb_type,
460 indices_ptr->size(),
461 std::move(oracle),
462 cache_stats
463 ),
464 my_indices_ptr(std::move(indices_ptr))
465 {}
466
467 const Value_* fetch(Index_ i, Value_* buffer) {
468 return my_core.fetch_indices(i, *my_indices_ptr, buffer);
469 }
470
471private:
472 DenseCore<oracle_, Index_> my_core;
473 tatami::VectorPtr<Index_> my_indices_ptr;
474};
475
476}
495template<typename Value_, typename Index_>
496class DenseMatrix : public tatami::Matrix<Value_, Index_> {
497public:
504 DenseMatrix(const std::string& uri, std::string attribute, tiledb::Context ctx, const DenseMatrixOptions& options) : my_attribute(std::move(attribute)) {
505 initialize(uri, std::move(ctx), options);
506 }
507
513 DenseMatrix(const std::string& uri, std::string attribute, const DenseMatrixOptions& options) : my_attribute(std::move(attribute)) {
514 initialize(uri, false, options);
515 }
516
521 DenseMatrix(const std::string& uri, std::string attribute) : DenseMatrix(uri, std::move(attribute), DenseMatrixOptions()) {}
522
523private:
524 template<class PossibleContext_>
525 void initialize(const std::string& uri, PossibleContext_ ctx, const DenseMatrixOptions& options) {
526 serialize([&]() -> void {
527 my_tdb_comp.reset(
528 [&]{
529 // If we have to create our own Context_ object, we do so inside the serialized
530 // section, rather than using a delegating constructor.
531 if constexpr(std::is_same<PossibleContext_, tiledb::Context>::value) {
532 return new DenseMatrix_internal::Components(std::move(ctx), uri);
533 } else {
534 return new DenseMatrix_internal::Components(uri);
535 }
536 }(),
537 [](DenseMatrix_internal::Components* ptr) -> void {
538 // Serializing the deleter, for completeness's sake.
539 serialize([&]() -> void {
540 delete ptr;
541 });
542 }
543 );
544
545 auto schema = my_tdb_comp->array.schema();
546 if (schema.array_type() != TILEDB_DENSE) {
547 throw std::runtime_error("TileDB array should be dense");
548 }
549
550 if (!schema.has_attribute(my_attribute)) {
551 throw std::runtime_error("no attribute '" + my_attribute + "' is present in the TileDB array");
552 }
553 auto attr = schema.attribute(my_attribute);
554 my_tdb_type = attr.type();
555
556 my_cache_size_in_elements = options.maximum_cache_size / internal::determine_type_size(my_tdb_type);
557 my_require_minimum_cache = options.require_minimum_cache;
558
559 tiledb::Domain domain = schema.domain();
560 if (domain.ndim() != 2) {
561 throw std::runtime_error("TileDB array should have exactly two dimensions");
562 }
563
564 tiledb::Dimension first_dim = domain.dimension(0);
565 my_tdb_first_dim.reset(first_dim);
566 Index_ first_extent = my_tdb_first_dim.extent<Index_>();
567 Index_ first_tile = my_tdb_first_dim.tile<Index_>();
568 my_firstdim_stats = tatami_chunked::ChunkDimensionStats<Index_>(first_extent, first_tile);
569
570 tiledb::Dimension second_dim = domain.dimension(1);
571 my_tdb_second_dim.reset(second_dim);
572 Index_ second_extent = my_tdb_second_dim.extent<Index_>();
573 Index_ second_tile = my_tdb_second_dim.tile<Index_>();
574 my_seconddim_stats = tatami_chunked::ChunkDimensionStats<Index_>(second_extent, second_tile);
575
576 // Favoring extraction on the dimension that involves pulling out fewer chunks per dimension element.
577 auto tiles_per_firstdim = (second_extent / second_tile) + (second_extent % second_tile > 0);
578 auto tiles_per_seconddim = (first_extent / first_tile) + (first_extent % first_tile > 0);
579 my_prefer_firstdim = tiles_per_firstdim <= tiles_per_seconddim;
580 });
581 }
582
583private:
584 std::shared_ptr<DenseMatrix_internal::Components> my_tdb_comp;
585
586 DenseMatrix_internal::Dimension my_tdb_first_dim, my_tdb_second_dim;
587 tiledb_datatype_t my_tdb_type;
588
589 std::string my_attribute;
590 size_t my_cache_size_in_elements;
591 bool my_require_minimum_cache;
592
593 int my_first_offset, my_second_offset;
594 tatami_chunked::ChunkDimensionStats<Index_> my_firstdim_stats, my_seconddim_stats;
595 bool my_prefer_firstdim;
596
597private:
598 Index_ nrow_internal() const {
599 return my_firstdim_stats.dimension_extent;
600 }
601
602 Index_ ncol_internal() const {
603 return my_seconddim_stats.dimension_extent;
604 }
605
606public:
607 Index_ nrow() const {
608 return nrow_internal();
609 }
610
611 Index_ ncol() const {
612 return ncol_internal();
613 }
614
615 bool is_sparse() const {
616 return false;
617 }
618
619 double is_sparse_proportion() const {
620 return 0;
621 }
622
623 bool prefer_rows() const {
624 return my_prefer_firstdim;
625 }
626
627 double prefer_rows_proportion() const {
628 return static_cast<double>(my_prefer_firstdim);
629 }
630
631 bool uses_oracle(bool) const {
632 // The oracle won't necessarily be used if the cache size is non-zero,
633 // but if the cache is empty, the oracle definitely _won't_ be used.
634 return my_cache_size_in_elements > 0;
635 }
636
637private:
638 template<bool oracle_, template<bool, typename, typename> class Extractor_, typename ... Args_>
639 std::unique_ptr<tatami::DenseExtractor<oracle_, Value_, Index_> > populate(bool row, Index_ non_target_length, tatami::MaybeOracle<oracle_, Index_> oracle, Args_&& ... args) const {
640 const auto& target_dim_stats = (row ? my_firstdim_stats : my_seconddim_stats);
641 const auto& tdb_target_dim = (row ? my_tdb_first_dim : my_tdb_second_dim);
642 const auto& tdb_non_target_dim = (row ? my_tdb_second_dim : my_tdb_first_dim);
643
644 tatami_chunked::SlabCacheStats slab_stats(
645 target_dim_stats.chunk_length,
646 non_target_length,
647 target_dim_stats.num_chunks,
648 my_cache_size_in_elements,
649 my_require_minimum_cache
650 );
651
652 // No need to have a dedicated SoloCore for uncached extraction,
653 // because it would still need to hold a single Workspace. We instead
654 // reuse the existing code with a chunk length of 1 to achieve the same
655 // memory usage. This has a mild perf hit from the caching machinery
656 // but perf already sucks without caching so who cares.
657 DenseMatrix_internal::CacheParameters<Index_> cache_params;
658 if (slab_stats.max_slabs_in_cache > 0) {
659 cache_params.chunk_length = target_dim_stats.chunk_length;
660 cache_params.slab_size_in_elements = slab_stats.slab_size_in_elements;
661 cache_params.max_slabs_in_cache = slab_stats.max_slabs_in_cache;
662 } else {
663 cache_params.chunk_length = 1;
664 cache_params.slab_size_in_elements = non_target_length;
665 cache_params.max_slabs_in_cache = 1;
666 }
667
668 return std::make_unique<Extractor_<oracle_, Value_, Index_> >(
669 *my_tdb_comp,
670 my_attribute,
671 row,
672 target_dim_stats.dimension_extent,
673 tdb_target_dim,
674 tdb_non_target_dim,
675 my_tdb_type,
676 std::move(oracle),
677 std::forward<Args_>(args)...,
678 cache_params
679 );
680 }
681
682 /********************
683 *** Myopic dense ***
684 ********************/
685public:
686 std::unique_ptr<tatami::MyopicDenseExtractor<Value_, Index_> > dense(bool row, const tatami::Options&) const {
687 Index_ full_non_target = (row ? ncol_internal() : nrow_internal());
688 return populate<false, DenseMatrix_internal::Full>(row, full_non_target, false, full_non_target);
689 }
690
691 std::unique_ptr<tatami::MyopicDenseExtractor<Value_, Index_> > dense(bool row, Index_ block_start, Index_ block_length, const tatami::Options&) const {
692 return populate<false, DenseMatrix_internal::Block>(row, block_length, false, block_start, block_length);
693 }
694
695 std::unique_ptr<tatami::MyopicDenseExtractor<Value_, Index_> > dense(bool row, tatami::VectorPtr<Index_> indices_ptr, const tatami::Options&) const {
696 auto nidx = indices_ptr->size();
697 return populate<false, DenseMatrix_internal::Index>(row, nidx, false, std::move(indices_ptr));
698 }
699
700 /*********************
701 *** Myopic sparse ***
702 *********************/
703public:
704 std::unique_ptr<tatami::MyopicSparseExtractor<Value_, Index_> > sparse(bool row, const tatami::Options& opt) const {
705 Index_ full_non_target = (row ? ncol_internal() : nrow_internal());
706 return std::make_unique<tatami::FullSparsifiedWrapper<false, Value_, Index_> >(dense(row, opt), full_non_target, opt);
707 }
708
709 std::unique_ptr<tatami::MyopicSparseExtractor<Value_, Index_> > sparse(bool row, Index_ block_start, Index_ block_length, const tatami::Options& opt) const {
710 return std::make_unique<tatami::BlockSparsifiedWrapper<false, Value_, Index_> >(dense(row, block_start, block_length, opt), block_start, block_length, opt);
711 }
712
713 std::unique_ptr<tatami::MyopicSparseExtractor<Value_, Index_> > sparse(bool row, tatami::VectorPtr<Index_> indices_ptr, const tatami::Options& opt) const {
714 auto ptr = dense(row, indices_ptr, opt);
715 return std::make_unique<tatami::IndexSparsifiedWrapper<false, Value_, Index_> >(std::move(ptr), std::move(indices_ptr), opt);
716 }
717
718 /**********************
719 *** Oracular dense ***
720 **********************/
721public:
722 std::unique_ptr<tatami::OracularDenseExtractor<Value_, Index_> > dense(
723 bool row,
724 std::shared_ptr<const tatami::Oracle<Index_> > oracle,
725 const tatami::Options&)
726 const {
727 Index_ full_non_target = (row ? ncol_internal() : nrow_internal());
728 return populate<true, DenseMatrix_internal::Full>(row, full_non_target, std::move(oracle), full_non_target);
729 }
730
731 std::unique_ptr<tatami::OracularDenseExtractor<Value_, Index_> > dense(
732 bool row,
733 std::shared_ptr<const tatami::Oracle<Index_> > oracle,
734 Index_ block_start,
735 Index_ block_length,
736 const tatami::Options&)
737 const {
738 return populate<true, DenseMatrix_internal::Block>(row, block_length, std::move(oracle), block_start, block_length);
739 }
740
741 std::unique_ptr<tatami::OracularDenseExtractor<Value_, Index_> > dense(
742 bool row,
743 std::shared_ptr<const tatami::Oracle<Index_> > oracle,
744 tatami::VectorPtr<Index_> indices_ptr,
745 const tatami::Options&)
746 const {
747 auto nidx = indices_ptr->size();
748 return populate<true, DenseMatrix_internal::Index>(row, nidx, std::move(oracle), std::move(indices_ptr));
749 }
750
751 /***********************
752 *** Oracular sparse ***
753 ***********************/
754public:
755 std::unique_ptr<tatami::OracularSparseExtractor<Value_, Index_> > sparse(
756 bool row,
757 std::shared_ptr<const tatami::Oracle<Index_> > oracle,
758 const tatami::Options& opt)
759 const {
760 Index_ full_non_target = (row ? ncol_internal() : nrow_internal());
761 return std::make_unique<tatami::FullSparsifiedWrapper<true, Value_, Index_> >(dense(row, std::move(oracle), opt), full_non_target, opt);
762 }
763
764 std::unique_ptr<tatami::OracularSparseExtractor<Value_, Index_> > sparse(
765 bool row,
766 std::shared_ptr<const tatami::Oracle<Index_> > oracle,
767 Index_ block_start,
768 Index_ block_length,
769 const tatami::Options& opt)
770 const {
771 return std::make_unique<tatami::BlockSparsifiedWrapper<true, Value_, Index_> >(dense(row, std::move(oracle), block_start, block_length, opt), block_start, block_length, opt);
772 }
773
774 std::unique_ptr<tatami::OracularSparseExtractor<Value_, Index_> > sparse(
775 bool row,
776 std::shared_ptr<const tatami::Oracle<Index_> > oracle,
777 tatami::VectorPtr<Index_> indices_ptr,
778 const tatami::Options& opt)
779 const {
780 auto ptr = dense(row, std::move(oracle), indices_ptr, opt);
781 return std::make_unique<tatami::IndexSparsifiedWrapper<true, Value_, Index_> >(std::move(ptr), std::move(indices_ptr), opt);
782 }
783};
784
785}
786
787#endif
TileDB-backed dense matrix.
Definition DenseMatrix.hpp:496
DenseMatrix(const std::string &uri, std::string attribute, tiledb::Context ctx, const DenseMatrixOptions &options)
Definition DenseMatrix.hpp:504
DenseMatrix(const std::string &uri, std::string attribute, const DenseMatrixOptions &options)
Definition DenseMatrix.hpp:513
DenseMatrix(const std::string &uri, std::string attribute)
Definition DenseMatrix.hpp:521
tatami bindings for TileDB matrices.
Definition DenseMatrix.hpp:20
void serialize(Function_ fun)
Definition serialize.hpp:20
std::shared_ptr< const std::vector< Index_ > > VectorPtr
typename std::conditional< oracle_, std::shared_ptr< const Oracle< Index_ > >, bool >::type MaybeOracle
typename std::conditional< oracle_, OracularDenseExtractor< Value_, Index_ >, MyopicDenseExtractor< Value_, Index_ > >::type DenseExtractor
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