diff --git a/include/scran_aggregate/aggregate_across_genes.hpp b/include/scran_aggregate/aggregate_across_genes.hpp index ee58dfc..1a9ef73 100644 --- a/include/scran_aggregate/aggregate_across_genes.hpp +++ b/include/scran_aggregate/aggregate_across_genes.hpp @@ -197,7 +197,12 @@ void compute_aggregate_by_row( } } + // Zeroing all of the buffers before iterating. Index_ NC = p.ncol(); + for (size_t s = 0; s < num_sets; ++s) { + std::fill_n(buffers.sum[s], NC, static_cast(0)); + } + if (p.sparse()) { tatami::parallelize([&](size_t, Index_ start, Index_ length) { auto ext = tatami::new_extractor(&p, true, sub_oracle, start, length); diff --git a/tests/src/aggregate_across_genes.cpp b/tests/src/aggregate_across_genes.cpp index 29254db..571f01f 100644 --- a/tests/src/aggregate_across_genes.cpp +++ b/tests/src/aggregate_across_genes.cpp @@ -202,3 +202,62 @@ TEST(AggregateAcrossGenes, OutOfRange) { scran_aggregate::aggregate_across_genes(mat, gene_sets, opt); }, "out of range"); } + +TEST(AggregateAcrossGenes, DirtyBuffers) { + int nr = 110, nc = 78; + auto vec = scran_tests::simulate_vector(nr * nc, []{ + scran_tests::SimulationParameters sparams; + sparams.density = 0.1; + return sparams; + }()); + + tatami::DenseRowMatrix dense_row(nr, nc, std::move(vec)); + auto sparse_column = tatami::convert_to_compressed_sparse(&dense_row, false); + + // Setting up the gene sets. + size_t nsets = 100; + std::vector > groupings(nsets); + { + std::mt19937_64 rng(999); + std::uniform_real_distribution runif; + for (auto& grp : groupings) { + for (int g = 0; g < nr; ++g) { + if (runif(rng) < 0.15) { + grp.push_back(g); + } + } + } + } + + std::vector > gene_sets; + gene_sets.reserve(groupings.size()); + for (const auto& grp : groupings) { + gene_sets.emplace_back(grp.size(), grp.data(), static_cast(NULL)); + } + + // Setting up some buffers. + scran_aggregate::AggregateAcrossGenesResults store; + scran_aggregate::AggregateAcrossGenesBuffers buffers; + store.sum.resize(nsets); + buffers.sum.resize(nsets); + for (size_t s = 0; s < nsets; ++s) { + store.sum[s].resize(nc, -1); // using -1 to simulate uninitialized values. + buffers.sum[s] = store.sum[s].data(); + } + + // Checking that the dirtiness doesn't affect the results. + scran_aggregate::AggregateAcrossGenesOptions opt; + auto ref = scran_aggregate::aggregate_across_genes(dense_row, gene_sets, opt); + scran_aggregate::aggregate_across_genes(dense_row, gene_sets, buffers, opt); + for (size_t s = 0; s < nsets; ++s) { + EXPECT_EQ(ref.sum[s], store.sum[s]); + } + + for (size_t s = 0; s < nsets; ++s) { + std::fill_n(store.sum[s].data(), nc, -1); // dirtying it again for another run. + } + scran_aggregate::aggregate_across_genes(*sparse_column, gene_sets, buffers, opt); + for (size_t s = 0; s < nsets; ++s) { + EXPECT_EQ(ref.sum[s], store.sum[s]); + } +}