Skip to content

Commit

Permalink
Fix threading on counts::apply when there are no rows/columns.
Browse files Browse the repository at this point in the history
In such cases, it is possible for the number of threads to be zero, in which
case we should ask for an allocation of length 'num_threads - 1'.
  • Loading branch information
LTLA committed Dec 15, 2024
1 parent 4878b2c commit 8b47e6b
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 9 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.24)

project(tatami_stats
VERSION 1.1.2
VERSION 1.1.3
DESCRIPTION "Matrix statistics for tatami"
LANGUAGES CXX)

Expand Down
13 changes: 8 additions & 5 deletions include/tatami_stats/counts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,14 @@ void apply(bool row, const tatami::Matrix<Value_, Index_>* p, Output_* output, i
} else {
num_threads = subpar::sanitize_num_workers(num_threads, otherdim); // provides some protection against silly num_threads iputs.
std::vector<Output_*> threaded_output_ptrs(num_threads, output);
std::vector<std::vector<Output_> > threaded_output(num_threads - 1);
for (int t = 1; t < num_threads; ++t) {
auto& curout = threaded_output[t - 1];
curout.resize(dim);
threaded_output_ptrs[t] = curout.data();
std::vector<std::vector<Output_> > threaded_output;
if (num_threads > 1) {
threaded_output.resize(num_threads - 1);
for (int t = 1; t < num_threads; ++t) {
auto& curout = threaded_output[t - 1];
curout.resize(dim);
threaded_output_ptrs[t] = curout.data();
}
}

if (p->sparse()) {
Expand Down
39 changes: 36 additions & 3 deletions tests/src/counts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include "tatami_stats/counts.hpp"
#include "tatami_test/tatami_test.hpp"

TEST(ComputingDimCounts, RowNaNCounts) {
TEST(ComputingDimCounts, RowNanCounts) {
size_t NR = 99, NC = 152;
auto dump = tatami_test::simulate_vector<double>(NR * NC, []{
tatami_test::SimulateVectorOptions opt;
Expand Down Expand Up @@ -51,7 +51,7 @@ TEST(ComputingDimCounts, RowNaNCounts) {
EXPECT_EQ(ref, tatami_stats::counts::nan::by_row(unsorted_column.get()));
}

TEST(ComputingDimCounts, ColumNaNCount) {
TEST(ComputingDimCounts, ColumNanCounts) {
size_t NR = 79, NC = 62;
auto dump = tatami_test::simulate_vector<double>(NR * NC, []{
tatami_test::SimulateVectorOptions opt;
Expand Down Expand Up @@ -138,7 +138,7 @@ TEST(ComputingDimCounts, RowZeroCounts) {
EXPECT_EQ(ref, tatami_stats::counts::zero::by_row(unsorted_column.get()));
}

TEST(ComputingDimVariances, RowZeroCountsWithNan) {
TEST(ComputingDimCounts, RowZeroCountsWithNan) {
size_t NR = 52, NC = 83;
auto dump = tatami_test::simulate_vector<double>(NR * NC, []{
tatami_test::SimulateVectorOptions opt;
Expand Down Expand Up @@ -238,3 +238,36 @@ TEST(ComputingDimVariances, ColumnZeroCountsWithNan) {
EXPECT_EQ(ref, tatami_stats::counts::zero::by_column(sparse_row.get()));
EXPECT_EQ(ref, tatami_stats::counts::zero::by_column(sparse_column.get()));
}

TEST(ComputingDimCounts, EmptyCounts) {
size_t NR = 0, NC = 10;
auto dense_row = std::unique_ptr<tatami::NumericMatrix>(new tatami::DenseRowMatrix<double, int>(NR, NC, std::vector<double>()));
auto dense_column = tatami::convert_to_dense(dense_row.get(), false);
auto sparse_row = tatami::convert_to_compressed_sparse(dense_row.get(), true);
auto sparse_column = tatami::convert_to_compressed_sparse(dense_row.get(), false);

tatami_stats::counts::zero::Options nopt;
nopt.num_threads = 3;

std::vector<int> empty_c(NC);
EXPECT_EQ(empty_c, tatami_stats::counts::zero::by_column(dense_row.get()));
EXPECT_EQ(empty_c, tatami_stats::counts::zero::by_column(dense_column.get()));
EXPECT_EQ(empty_c, tatami_stats::counts::zero::by_column(sparse_row.get()));
EXPECT_EQ(empty_c, tatami_stats::counts::zero::by_column(sparse_column.get()));

EXPECT_EQ(empty_c, tatami_stats::counts::zero::by_column(dense_row.get(), nopt));
EXPECT_EQ(empty_c, tatami_stats::counts::zero::by_column(dense_column.get(), nopt));
EXPECT_EQ(empty_c, tatami_stats::counts::zero::by_column(sparse_row.get(), nopt));
EXPECT_EQ(empty_c, tatami_stats::counts::zero::by_column(sparse_column.get(), nopt));

std::vector<int> empty_r(NR);
EXPECT_EQ(empty_r, tatami_stats::counts::zero::by_row(dense_row.get()));
EXPECT_EQ(empty_r, tatami_stats::counts::zero::by_row(dense_column.get()));
EXPECT_EQ(empty_r, tatami_stats::counts::zero::by_row(sparse_row.get()));
EXPECT_EQ(empty_r, tatami_stats::counts::zero::by_row(sparse_column.get()));

EXPECT_EQ(empty_r, tatami_stats::counts::zero::by_row(dense_row.get(), nopt));
EXPECT_EQ(empty_r, tatami_stats::counts::zero::by_row(dense_column.get(), nopt));
EXPECT_EQ(empty_r, tatami_stats::counts::zero::by_row(sparse_row.get(), nopt));
EXPECT_EQ(empty_r, tatami_stats::counts::zero::by_row(sparse_column.get(), nopt));
}

0 comments on commit 8b47e6b

Please sign in to comment.