Skip to content

Commit

Permalink
Check that the row indices for each gene set are not out of range.
Browse files Browse the repository at this point in the history
  • Loading branch information
LTLA committed Dec 28, 2024
1 parent 49820a0 commit ae45c05
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 4 deletions.
16 changes: 12 additions & 4 deletions include/scran_aggregate/aggregate_across_genes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <algorithm>
#include <vector>
#include <unordered_set>
#include <stdexcept>

#include "tatami/tatami.hpp"

Expand Down Expand Up @@ -65,15 +66,22 @@ struct AggregateAcrossGenesResults {
namespace aggregate_across_genes_internal {

template<typename Index_, typename Gene_, typename Weight_>
std::vector<Gene_> create_subset(const std::vector<std::tuple<size_t, const Gene_*, const Weight_*> >& gene_sets) {
std::vector<Gene_> create_subset(const std::vector<std::tuple<size_t, const Gene_*, const Weight_*> >& gene_sets, Index_ nrow) {
std::unordered_set<Gene_> of_interest;
for (const auto& set : gene_sets) {
auto set_size = std::get<0>(set);
auto set_genes = std::get<1>(set);
of_interest.insert(set_genes, set_genes + set_size);
}

std::vector<Index_> subset(of_interest.begin(), of_interest.end());
std::sort(subset.begin(), subset.end());
if (!subset.empty()) {
std::sort(subset.begin(), subset.end());
if (subset.front() < 0 || subset.back() >= nrow) {
throw std::runtime_error("set indices are out of range");
}
}

return subset;
}

Expand All @@ -97,7 +105,7 @@ void compute_aggregate_by_column(
const AggregateAcrossGenesOptions& options)
{
// Identifying the subset of rows that actually need to be extracted.
tatami::VectorPtr<Index_> subset_of_interest = std::make_shared<std::vector<Index_> >(create_subset<Index_>(gene_sets));
tatami::VectorPtr<Index_> subset_of_interest = std::make_shared<std::vector<Index_> >(create_subset<Index_>(gene_sets, p.nrow()));
const auto& subset = *subset_of_interest;
size_t nsubs = subset.size();

Expand Down Expand Up @@ -160,7 +168,7 @@ void compute_aggregate_by_row(
const AggregateAcrossGenesOptions& options)
{
// Identifying the subset of rows that actually need to be extracted.
auto subset = create_subset<Index_>(gene_sets);
auto subset = create_subset<Index_>(gene_sets, p.nrow());
size_t nsubs = subset.size();
auto sub_oracle = std::make_shared<tatami::FixedViewOracle<Index_> >(subset.data(), nsubs);

Expand Down
25 changes: 25 additions & 0 deletions tests/src/aggregate_across_genes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,28 @@ INSTANTIATE_TEST_SUITE_P(
AggregateAcrossGenesTest,
::testing::Values(1, 3) // number of threads
);

TEST(AggregateAcrossGenes, OutOfRange) {
int nr = 11, nc = 78;
auto vec = scran_tests::simulate_vector(nr * nc, []{
scran_tests::SimulationParameters sparams;
sparams.density = 0.1;
return sparams;
}());

tatami::DenseRowMatrix<double, int> mat(nr, nc, std::move(vec));
std::vector<int> example { 1, 10, 100 };
std::vector<std::tuple<size_t, const int*, const double*> > gene_sets;
gene_sets.emplace_back(3, example.data(), static_cast<double*>(NULL));

scran_aggregate::AggregateAcrossGenesOptions opt;
scran_tests::expect_error([&]() {
scran_aggregate::aggregate_across_genes(mat, gene_sets, opt);
}, "out of range");

// Also fails if there are negative values.
example[0] = -1;
scran_tests::expect_error([&]() {
scran_aggregate::aggregate_across_genes(mat, gene_sets, opt);
}, "out of range");
}

0 comments on commit ae45c05

Please sign in to comment.