Skip to content

Commit

Permalink
Zero the buffers before aggregating across genes by row.
Browse files Browse the repository at this point in the history
This ensures that we get the right results if the user-supplied buffers were
not already filled with zeros, e.g., from uninitialized memory.
  • Loading branch information
LTLA committed Dec 28, 2024
1 parent ae45c05 commit c4d2a96
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 0 deletions.
5 changes: 5 additions & 0 deletions include/scran_aggregate/aggregate_across_genes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Sum_>(0));
}

if (p.sparse()) {
tatami::parallelize([&](size_t, Index_ start, Index_ length) {
auto ext = tatami::new_extractor<true, true>(&p, true, sub_oracle, start, length);
Expand Down
59 changes: 59 additions & 0 deletions tests/src/aggregate_across_genes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<double, int> 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<std::vector<int> > 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<std::tuple<size_t, const int*, const double*> > gene_sets;
gene_sets.reserve(groupings.size());
for (const auto& grp : groupings) {
gene_sets.emplace_back(grp.size(), grp.data(), static_cast<double*>(NULL));
}

// Setting up some buffers.
scran_aggregate::AggregateAcrossGenesResults<double> store;
scran_aggregate::AggregateAcrossGenesBuffers<double> 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]);
}
}

0 comments on commit c4d2a96

Please sign in to comment.