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