1#ifndef TATAMI_TEST_TEST_ACCESS_HPP
2#define TATAMI_TEST_TEST_ACCESS_HPP
4#include <gtest/gtest.h>
82 output.
use_row = std::get<0>(x);
84 output.
order = std::get<2>(x);
85 output.
jump = std::get<3>(x);
94 return ::testing::Combine(
95 ::testing::Values(
true,
false),
96 ::testing::Values(
true,
false),
97 ::testing::Values(TestAccessOrder::FORWARD, TestAccessOrder::REVERSE, TestAccessOrder::RANDOM),
98 ::testing::Values(1, 3)
107template<
typename Value_>
108void compare_vectors(
const std::vector<Value_>& expected,
const std::vector<Value_>& observed,
const std::string& context) {
109 size_t n_expected = expected.size();
110 ASSERT_EQ(n_expected, observed.size()) <<
"mismatch in vector length (" << context <<
")";
111 for (
size_t i = 0; i < n_expected; ++i) {
112 auto expected_val = expected[i], observed_val = observed[i];
113 if (std::isnan(expected_val)) {
114 EXPECT_EQ(std::isnan(expected_val), std::isnan(observed_val)) <<
"mismatching NaNs at position " << i <<
" (" << context <<
")";
116 EXPECT_EQ(expected_val, observed_val) <<
"different values at position " << i <<
" (" << context <<
")";
121template<
typename Index_>
122uint64_t create_seed(Index_ NR, Index_ NC,
const TestAccessOptions& options) {
123 uint64_t seed =
static_cast<uint64_t
>(NR) *
static_cast<uint64_t
>(NC);
124 seed += 13 *
static_cast<uint64_t
>(options.use_row);
125 seed += 57 *
static_cast<uint64_t
>(options.order);
126 seed += 101 *
static_cast<uint64_t
>(options.jump);
130template<
typename Index_>
131std::vector<Index_> simulate_test_access_sequence(Index_ NR, Index_ NC,
const TestAccessOptions& options) {
132 std::vector<Index_> sequence;
133 auto limit = (options.use_row ? NR : NC);
135 if (options.order == TestAccessOrder::REVERSE) {
136 for (
int i = limit; i > 0; i -= options.jump) {
137 sequence.push_back(i - 1);
140 for (
int i = 0; i < limit; i += options.jump) {
141 sequence.push_back(i);
143 if (options.order == TestAccessOrder::RANDOM) {
144 std::mt19937_64 rng(create_seed(NR, NC, options));
145 std::shuffle(sequence.begin(), sequence.end(), rng);
152template<
bool use_oracle_,
typename Index_>
154 if constexpr(use_oracle_) {
155 std::shared_ptr<tatami::Oracle<Index_> > oracle;
156 if (options.jump == 1 && options.order == TestAccessOrder::FORWARD) {
167template<
bool use_oracle_,
typename Value_,
typename Index_,
class SparseExpand_,
typename ...Args_>
168void test_access_base(
171 const TestAccessOptions& options,
173 SparseExpand_ sparse_expand,
176 auto NR = matrix.
nrow();
177 ASSERT_EQ(NR, reference.
nrow());
178 auto NC = matrix.
ncol();
179 ASSERT_EQ(NC, reference.
ncol());
183 auto sequence = simulate_test_access_sequence(NR, NC, options);
184 auto oracle = create_oracle<use_oracle_>(sequence, options);
186 auto pwork = tatami::new_extractor<false, use_oracle_>(&matrix, options.use_row, oracle, args...);
187 auto swork = tatami::new_extractor<true, use_oracle_>(&matrix, options.use_row, oracle, args...);
191 auto swork_v = tatami::new_extractor<true, use_oracle_>(&matrix, options.use_row, oracle, args..., opt);
194 auto swork_n = tatami::new_extractor<true, use_oracle_>(&matrix, options.use_row, oracle, args..., opt);
197 auto swork_i = tatami::new_extractor<true, use_oracle_>(&matrix, options.use_row, oracle, args..., opt);
199 size_t sparse_counter = 0;
202 for (
auto i : sequence) {
203 auto expected =
fetch(*refwork, i, extent);
207 auto observed = [&]() {
208 if constexpr(use_oracle_) {
209 return fetch(*pwork, extent);
211 return fetch(*pwork, i, extent);
214 compare_vectors(expected, observed,
"dense retrieval");
219 auto observed = [&]() {
220 if constexpr(use_oracle_) {
221 return fetch(*swork, extent);
223 return fetch(*swork, i, extent);
226 compare_vectors(expected, sparse_expand(observed),
"sparse retrieval");
228 sparse_counter += observed.value.size();
230 bool is_increasing =
true;
231 for (
size_t i = 1; i < observed.index.size(); ++i) {
232 if (observed.index[i] <= observed.index[i-1]) {
233 is_increasing =
false;
237 ASSERT_TRUE(is_increasing);
240 std::vector<Index_> indices(extent);
241 auto observed_i = [&]() {
242 if constexpr(use_oracle_) {
243 return swork_i->fetch(NULL, indices.data());
245 return swork_i->fetch(i, NULL, indices.data());
248 ASSERT_TRUE(observed_i.value == NULL);
249 tatami::copy_n(observed_i.index, observed_i.number, indices.data());
250 indices.resize(observed_i.number);
251 ASSERT_EQ(observed.index, indices);
253 std::vector<Value_> values(extent);
254 auto observed_v = [&]() {
255 if constexpr(use_oracle_) {
256 return swork_v->fetch(values.data(), NULL);
258 return swork_v->fetch(i, values.data(), NULL);
261 ASSERT_TRUE(observed_v.index == NULL);
262 tatami::copy_n(observed_v.value, observed_v.number, values.data());
263 values.resize(observed_v.number);
264 compare_vectors(values, observed.value,
"sparse retrieval with values only");
266 auto observed_n = [&]() {
267 if constexpr(use_oracle_) {
268 return swork_n->fetch(NULL, NULL);
270 return swork_n->fetch(i, NULL, NULL);
273 ASSERT_TRUE(observed_n.value == NULL);
274 ASSERT_TRUE(observed_n.index == NULL);
275 ASSERT_EQ(observed.value.size(), observed_n.number);
279 if (options.check_sparse && matrix.
is_sparse()) {
280 EXPECT_TRUE(sparse_counter <
static_cast<size_t>(NR) *
static_cast<size_t>(NC));
284template<
bool use_oracle_,
typename Value_,
typename Index_>
288 const TestAccessOptions& options)
290 Index_ nsecondary = (options.use_row ? reference.
ncol() : reference.
nrow());
291 test_access_base<use_oracle_>(
296 [&](
const auto& svec) ->
auto {
297 std::vector<Value_> output(nsecondary);
298 size_t nnz = svec.index.size();
299 for (
size_t i = 0; i < nnz; ++i) {
300 output[svec.index[i]] = svec.value[i];
307template<
bool use_oracle_,
typename Value_,
typename Index_>
311 double relative_start,
312 double relative_length,
313 const TestAccessOptions& options)
315 Index_ nsecondary = (options.use_row ? reference.
ncol() : reference.
nrow());
316 Index_ start = nsecondary * relative_start;
317 Index_ length = nsecondary * relative_length;
318 test_access_base<use_oracle_>(
323 [&](
const auto& svec) ->
auto {
324 std::vector<Value_> output(length);
325 size_t nnz = svec.index.size();
326 for (
size_t i = 0; i < nnz; ++i) {
327 output[svec.index[i] - start] = svec.value[i];
336template<
bool use_oracle_,
typename Value_,
typename Index_>
340 double relative_start,
342 const TestAccessOptions& options)
344 Index_ nsecondary = (options.use_row ? reference.
ncol() : reference.
nrow());
349 create_seed(matrix.
nrow(), matrix.
ncol(), options) + 999 * probability + 85 * relative_start
352 Index_ num_indices = index_ptr->size();
353 std::vector<size_t> reposition(nsecondary, -1);
355 const auto& indices = *index_ptr;
356 for (Index_ i = 0; i < num_indices; ++i) {
357 reposition[indices[i]] = i;
361 test_access_base<use_oracle_>(
366 [&](
const auto& svec) ->
auto {
367 std::vector<Value_> expected(num_indices);
368 size_t nnz = svec.index.size();
369 for (
size_t i = 0; i < nnz; ++i) {
370 expected[reposition[svec.index[i]]] = svec.value[i];
395template<
typename Value_,
typename Index_>
402 internal::test_full_access<true>(matrix, reference, options);
404 internal::test_full_access<false>(matrix, reference, options);
426template<
typename Value_,
typename Index_>
430 double relative_start,
431 double relative_length,
435 internal::test_block_access<true>(matrix, reference, relative_start, relative_length, options);
437 internal::test_block_access<false>(matrix, reference, relative_start, relative_length, options);
459template<
typename Value_,
typename Index_>
463 double relative_start,
468 internal::test_indexed_access<true>(matrix, reference, relative_start, probability, options);
470 internal::test_indexed_access<false>(matrix, reference, relative_start, probability, options);
486template<
typename Value_,
typename Index_>
505template<
typename Value_,
typename Index_>
std::unique_ptr< MyopicDenseExtractor< Value_, Index_ > > dense_row(const Options &opt) const
virtual Index_ ncol() const=0
std::unique_ptr< MyopicDenseExtractor< Value_, Index_ > > dense_column(const Options &opt) const
virtual Index_ nrow() const=0
virtual bool is_sparse() const=0
Create an indexed subset of dimension elements.
Fetch a row/column into a vector.
Utilities for testing tatami libraries.
Definition create_indexed_subset.hpp:15
void test_block_access(const tatami::Matrix< Value_, Index_ > &matrix, const tatami::Matrix< Value_, Index_ > &reference, double relative_start, double relative_length, const TestAccessOptions &options)
Definition test_access.hpp:427
std::tuple< bool, bool, TestAccessOrder, int > StandardTestAccessOptions
Definition test_access.hpp:71
TestAccessOrder
Definition test_access.hpp:34
void test_indexed_access(const tatami::Matrix< Value_, Index_ > &matrix, const tatami::Matrix< Value_, Index_ > &reference, double relative_start, double probability, const TestAccessOptions &options)
Definition test_access.hpp:460
void test_simple_row_access(const tatami::Matrix< Value_, Index_ > &matrix, const tatami::Matrix< Value_, Index_ > &reference)
Definition test_access.hpp:506
void test_simple_column_access(const tatami::Matrix< Value_, Index_ > &matrix, const tatami::Matrix< Value_, Index_ > &reference)
Definition test_access.hpp:487
tatami::VectorPtr< Index_ > create_indexed_subset(Index_ extent, double relative_start, double probability, uint64_t seed)
Definition create_indexed_subset.hpp:35
TestAccessOptions convert_test_access_options(const StandardTestAccessOptions &x)
Definition test_access.hpp:80
std::vector< Value_ > fetch(tatami::MyopicDenseExtractor< Value_, Index_ > &ext, Index_ i, size_t number)
Definition fetch.hpp:46
auto standard_test_access_options_combinations()
Definition test_access.hpp:93
void test_full_access(const tatami::Matrix< Value_, Index_ > &matrix, const tatami::Matrix< Value_, Index_ > &reference, const TestAccessOptions &options)
Definition test_access.hpp:396
typename std::conditional< oracle_, std::shared_ptr< const Oracle< Index_ > >, bool >::type MaybeOracle
Value_ * copy_n(const Value_ *input, Size_ n, Value_ *output)
bool sparse_extract_index
bool sparse_extract_value
Options for test_full_access() and friends.
Definition test_access.hpp:39
bool use_oracle
Definition test_access.hpp:43
int jump
Definition test_access.hpp:59
bool use_row
Definition test_access.hpp:49
bool check_sparse
Definition test_access.hpp:64
TestAccessOrder order
Definition test_access.hpp:54