1#ifndef TATAMI_TEST_TEST_ACCESS_HPP
2#define TATAMI_TEST_TEST_ACCESS_HPP
4#include <gtest/gtest.h>
83 output.
use_row = std::get<0>(x);
85 output.
order = std::get<2>(x);
86 output.
jump = std::get<3>(x);
95 return ::testing::Combine(
96 ::testing::Values(
true,
false),
97 ::testing::Values(
true,
false),
98 ::testing::Values(TestAccessOrder::FORWARD, TestAccessOrder::REVERSE, TestAccessOrder::RANDOM),
99 ::testing::Values(1, 3)
108template<
typename Value_>
109void compare_vectors(
const std::vector<Value_>& expected,
const std::vector<Value_>& observed,
const std::string& context) {
110 size_t n_expected = expected.size();
111 ASSERT_EQ(n_expected, observed.size()) <<
"mismatch in vector length (" << context <<
")";
112 for (
size_t i = 0; i < n_expected; ++i) {
113 auto expected_val = expected[i], observed_val = observed[i];
114 if (std::isnan(expected_val)) {
115 EXPECT_EQ(std::isnan(expected_val), std::isnan(observed_val)) <<
"mismatching NaNs at position " << i <<
" (" << context <<
")";
117 EXPECT_EQ(expected_val, observed_val) <<
"different values at position " << i <<
" (" << context <<
")";
122template<
typename Index_>
123uint64_t create_seed(Index_ NR, Index_ NC,
const TestAccessOptions& options) {
124 uint64_t seed =
static_cast<uint64_t
>(NR) *
static_cast<uint64_t
>(NC);
125 seed += 13 *
static_cast<uint64_t
>(options.use_row);
126 seed += 57 *
static_cast<uint64_t
>(options.order);
127 seed += 101 *
static_cast<uint64_t
>(options.jump);
131template<
typename Index_>
132std::vector<Index_> simulate_test_access_sequence(Index_ NR, Index_ NC,
const TestAccessOptions& options) {
133 std::vector<Index_> sequence;
134 auto limit = (options.use_row ? NR : NC);
136 std::mt19937_64 rng(create_seed(NR, NC, options));
137 Index_ start = rng() % options.jump;
140 sequence.push_back(start);
141 Index_ remainder = limit - start;
143 if (
static_cast<typename std::make_unsigned<Index_>::type
>(remainder) <=
static_cast<typename std::make_unsigned<int>::type
>(options.jump)) {
146 start += options.jump;
150 if (options.order == TestAccessOrder::REVERSE) {
151 std::reverse(sequence.begin(), sequence.end());
152 }
else if (options.order == TestAccessOrder::RANDOM) {
153 std::shuffle(sequence.begin(), sequence.end(), rng);
159template<
bool use_oracle_,
typename Index_>
161 if constexpr(use_oracle_) {
162 std::shared_ptr<tatami::Oracle<Index_> > oracle;
163 if (options.jump == 1 && options.order == TestAccessOrder::FORWARD) {
174template<
bool use_oracle_,
typename Value_,
typename Index_,
class SparseExpand_,
typename ...Args_>
175void test_access_base(
178 const TestAccessOptions& options,
180 SparseExpand_ sparse_expand,
183 auto NR = matrix.
nrow();
184 ASSERT_EQ(NR, reference.
nrow());
185 auto NC = matrix.
ncol();
186 ASSERT_EQ(NC, reference.
ncol());
190 auto sequence = simulate_test_access_sequence(NR, NC, options);
191 auto oracle = create_oracle<use_oracle_>(sequence, options);
206 size_t sparse_counter = 0;
209 for (
auto i : sequence) {
210 auto expected =
fetch(*refwork, i, extent);
214 auto observed = [&]() {
215 if constexpr(use_oracle_) {
216 return fetch(*pwork, extent);
218 return fetch(*pwork, i, extent);
221 compare_vectors(expected, observed,
"dense retrieval");
226 auto observed = [&]() {
227 if constexpr(use_oracle_) {
228 return fetch(*swork, extent);
230 return fetch(*swork, i, extent);
233 compare_vectors(expected, sparse_expand(observed),
"sparse retrieval");
235 sparse_counter += observed.value.size();
237 bool is_increasing =
true;
238 for (
size_t i = 1; i < observed.index.size(); ++i) {
239 if (observed.index[i] <= observed.index[i-1]) {
240 is_increasing =
false;
244 ASSERT_TRUE(is_increasing);
247 std::vector<Index_> indices(extent);
248 auto observed_i = [&]() {
249 if constexpr(use_oracle_) {
250 return swork_i->fetch(NULL, indices.data());
252 return swork_i->fetch(i, NULL, indices.data());
255 ASSERT_TRUE(observed_i.value == NULL);
256 tatami::copy_n(observed_i.index, observed_i.number, indices.data());
257 indices.resize(observed_i.number);
258 ASSERT_EQ(observed.index, indices);
260 std::vector<Value_> values(extent);
261 auto observed_v = [&]() {
262 if constexpr(use_oracle_) {
263 return swork_v->fetch(values.data(), NULL);
265 return swork_v->fetch(i, values.data(), NULL);
268 ASSERT_TRUE(observed_v.index == NULL);
269 tatami::copy_n(observed_v.value, observed_v.number, values.data());
270 values.resize(observed_v.number);
271 compare_vectors(values, observed.value,
"sparse retrieval with values only");
273 auto observed_n = [&]() {
274 if constexpr(use_oracle_) {
275 return swork_n->fetch(NULL, NULL);
277 return swork_n->fetch(i, NULL, NULL);
280 ASSERT_TRUE(observed_n.value == NULL);
281 ASSERT_TRUE(observed_n.index == NULL);
282 ASSERT_EQ(observed.value.size(), observed_n.number);
286 if (options.check_sparse && matrix.
is_sparse()) {
287 EXPECT_TRUE(sparse_counter <
static_cast<size_t>(NR) *
static_cast<size_t>(NC));
291template<
bool use_oracle_,
typename Value_,
typename Index_>
295 const TestAccessOptions& options)
297 Index_ nsecondary = (options.use_row ? reference.
ncol() : reference.
nrow());
298 test_access_base<use_oracle_>(
303 [&](
const auto& svec) ->
auto {
304 std::vector<Value_> output(nsecondary);
305 size_t nnz = svec.index.size();
306 for (
size_t i = 0; i < nnz; ++i) {
307 output[svec.index[i]] = svec.value[i];
314template<
bool use_oracle_,
typename Value_,
typename Index_>
318 double relative_start,
319 double relative_length,
320 const TestAccessOptions& options)
322 Index_ nsecondary = (options.use_row ? reference.
ncol() : reference.
nrow());
323 Index_ start = nsecondary * relative_start;
324 Index_ length = nsecondary * relative_length;
325 test_access_base<use_oracle_>(
330 [&](
const auto& svec) ->
auto {
331 std::vector<Value_> output(length);
332 size_t nnz = svec.index.size();
333 for (
size_t i = 0; i < nnz; ++i) {
334 output[svec.index[i] - start] = svec.value[i];
343template<
bool use_oracle_,
typename Value_,
typename Index_>
347 double relative_start,
349 const TestAccessOptions& options)
351 Index_ nsecondary = (options.use_row ? reference.
ncol() : reference.
nrow());
356 create_seed(matrix.
nrow(), matrix.
ncol(), options) + 999 * probability + 85 * relative_start
359 Index_ num_indices = index_ptr->size();
360 std::vector<size_t> reposition(nsecondary, -1);
362 const auto& indices = *index_ptr;
363 for (Index_ i = 0; i < num_indices; ++i) {
364 reposition[indices[i]] = i;
368 test_access_base<use_oracle_>(
373 [&](
const auto& svec) ->
auto {
374 std::vector<Value_> expected(num_indices);
375 size_t nnz = svec.index.size();
376 for (
size_t i = 0; i < nnz; ++i) {
377 expected[reposition[svec.index[i]]] = svec.value[i];
402template<
typename Value_,
typename Index_>
409 internal::test_full_access<true>(matrix, reference, options);
411 internal::test_full_access<false>(matrix, reference, options);
433template<
typename Value_,
typename Index_>
437 double relative_start,
438 double relative_length,
442 internal::test_block_access<true>(matrix, reference, relative_start, relative_length, options);
444 internal::test_block_access<false>(matrix, reference, relative_start, relative_length, options);
466template<
typename Value_,
typename Index_>
470 double relative_start,
475 internal::test_indexed_access<true>(matrix, reference, relative_start, probability, options);
477 internal::test_indexed_access<false>(matrix, reference, relative_start, probability, options);
493template<
typename Value_,
typename Index_>
512template<
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:434
std::tuple< bool, bool, TestAccessOrder, int > StandardTestAccessOptions
Definition test_access.hpp:72
TestAccessOrder
Definition test_access.hpp:35
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:467
void test_simple_row_access(const tatami::Matrix< Value_, Index_ > &matrix, const tatami::Matrix< Value_, Index_ > &reference)
Definition test_access.hpp:513
void test_simple_column_access(const tatami::Matrix< Value_, Index_ > &matrix, const tatami::Matrix< Value_, Index_ > &reference)
Definition test_access.hpp:494
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:81
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:94
void test_full_access(const tatami::Matrix< Value_, Index_ > &matrix, const tatami::Matrix< Value_, Index_ > &reference, const TestAccessOptions &options)
Definition test_access.hpp:403
typename std::conditional< oracle_, std::shared_ptr< const Oracle< Index_ > >, bool >::type MaybeOracle
Value_ * copy_n(const Value_ *input, Size_ n, Value_ *output)
auto new_extractor(const Matrix< Value_, Index_ > &matrix, bool row, MaybeOracle< oracle_, Index_ > oracle, Args_ &&... args)
bool sparse_extract_index
bool sparse_extract_value
Options for test_full_access() and friends.
Definition test_access.hpp:40
bool use_oracle
Definition test_access.hpp:44
int jump
Definition test_access.hpp:60
bool use_row
Definition test_access.hpp:50
bool check_sparse
Definition test_access.hpp:65
TestAccessOrder order
Definition test_access.hpp:55