diff --git a/src/stan/model/indexing/rvalue.hpp b/src/stan/model/indexing/rvalue.hpp index 79c7594b018..a243b04ba2a 100644 --- a/src/stan/model/indexing/rvalue.hpp +++ b/src/stan/model/indexing/rvalue.hpp @@ -185,14 +185,14 @@ inline auto rvalue(EigVec&& v, const char* name, MultiIndex&& idx) { template * = nullptr, require_not_std_vector_t* = nullptr> inline auto rvalue(Vec&& v, const char* name, index_min_max idx) { - math::check_range("vector[min_max] min indexing", name, v.size(), idx.min_); - const Eigen::Index slice_start = idx.min_ - 1; if (idx.max_ >= idx.min_) { + math::check_range("vector[min_max] min indexing", name, v.size(), idx.min_); + const Eigen::Index slice_start = idx.min_ - 1; math::check_range("vector[min_max] max indexing", name, v.size(), idx.max_); const Eigen::Index slice_size = idx.max_ - slice_start; return v.segment(slice_start, slice_size); } else { - return v.segment(slice_start, 0); + return v.segment(0, 0); } } @@ -343,14 +343,14 @@ inline auto rvalue(Mat&& x, const char* name, index_max idx) { */ template * = nullptr> inline auto rvalue(Mat&& x, const char* name, index_min_max idx) { - math::check_range("matrix[min_max] min row indexing", name, x.rows(), - idx.min_); if (idx.max_ >= idx.min_) { + math::check_range("matrix[min_max] min row indexing", name, x.rows(), + idx.min_); math::check_range("matrix[min_max] max row indexing", name, x.rows(), idx.max_); return x.middleRows(idx.min_ - 1, idx.max_ - idx.min_ + 1); } else { - return x.middleRows(idx.min_ - 1, 0); + return x.middleRows(0, 0); } } @@ -371,11 +371,11 @@ inline auto rvalue(Mat&& x, const char* name, index_min_max idx) { template * = nullptr> inline auto rvalue(Mat&& x, const char* name, index_min_max row_idx, index_min_max col_idx) { - math::check_range("matrix[min_max, min_max] min row indexing", name, x.rows(), - row_idx.min_); - math::check_range("matrix[min_max, min_max] min column indexing", name, - x.cols(), col_idx.min_); if (row_idx.max_ >= row_idx.min_ && col_idx.max_ >= col_idx.min_) { + math::check_range("matrix[min_max, min_max] min row indexing", name, + x.rows(), row_idx.min_); + math::check_range("matrix[min_max, min_max] min column indexing", name, + x.cols(), col_idx.min_); math::check_range("matrix[min_max, min_max] max row indexing", name, x.rows(), row_idx.max_); math::check_range("matrix[min_max, min_max] max column indexing", name, @@ -384,17 +384,21 @@ inline auto rvalue(Mat&& x, const char* name, index_min_max row_idx, row_idx.max_ - (row_idx.min_ - 1), col_idx.max_ - (col_idx.min_ - 1)); } else if (row_idx.max_ >= row_idx.min_) { + math::check_range("matrix[min_max, min_max] min row indexing", name, + x.rows(), row_idx.min_); math::check_range("matrix[min_max, min_max] max row indexing", name, x.rows(), row_idx.max_); return x.block(row_idx.min_ - 1, col_idx.min_ - 1, row_idx.max_ - (row_idx.min_ - 1), 0); } else if (col_idx.max_ >= col_idx.min_) { + math::check_range("matrix[min_max, min_max] min column indexing", name, + x.cols(), col_idx.min_); math::check_range("matrix[min_max, min_max] max column indexing", name, x.cols(), col_idx.max_); return x.block(row_idx.min_ - 1, col_idx.min_ - 1, 0, col_idx.max_ - (col_idx.min_ - 1)); } else { - return x.block(row_idx.min_ - 1, col_idx.min_ - 1, 0, 0); + return x.block(0, 0, 0, 0); } } @@ -684,16 +688,16 @@ inline auto rvalue(Mat&& x, const char* name, Idx&& row_idx, template * = nullptr> inline auto rvalue(Mat&& x, const char* name, Idx&& row_idx, index_min_max col_idx) { - math::check_range("matrix[..., min_max] min column indexing", name, x.cols(), - col_idx.min_); - const Eigen::Index col_start = col_idx.min_ - 1; if (col_idx.max_ >= col_idx.min_) { + math::check_range("matrix[..., min_max] min column indexing", name, + x.cols(), col_idx.min_); + const Eigen::Index col_start = col_idx.min_ - 1; math::check_range("matrix[..., min_max] max column indexing", name, x.cols(), col_idx.max_); return rvalue(x.middleCols(col_start, col_idx.max_ - col_start), name, std::forward(row_idx)); } else { - return rvalue(x.middleCols(col_start, 0), name, std::forward(row_idx)); + return rvalue(x.middleCols(0, 0), name, std::forward(row_idx)); } } diff --git a/src/test/unit/model/indexing/rvalue_test.cpp b/src/test/unit/model/indexing/rvalue_test.cpp index d9abc7b6e60..7af6eb9008c 100644 --- a/src/test/unit/model/indexing/rvalue_test.cpp +++ b/src/test/unit/model/indexing/rvalue_test.cpp @@ -185,7 +185,7 @@ TEST(ModelIndexing, rvalue_eigenvec_min_max_nil) { x(1) = 2.2; x(2) = 3.3; x(3) = 4.4; - // min > max + // min < max for (int mn = 0; mn < 4; ++mn) { for (int mx = mn; mx < 4; ++mx) { Eigen::Matrix rx @@ -196,21 +196,31 @@ TEST(ModelIndexing, rvalue_eigenvec_min_max_nil) { } } - // max > min - for (int mn = 3; mn > -1; --mn) { - for (int mx = mn; mx > -1; --mx) { + // min > max, including min > size + for (int mn = 5; mn > -1; --mn) { + for (int mx = mn - 1; mx > -1; --mx) { Eigen::Matrix rx = rvalue(x, "", index_min_max(mn + 1, mx + 1)); - if (mn == mx) { - EXPECT_FLOAT_EQ(1, rx.size()); - } else { - EXPECT_FLOAT_EQ(0, rx.size()); - } + EXPECT_FLOAT_EQ(0, rx.size()); } } + // min == max + for (int mn = 3; mn > -1; --mn) { + Eigen::Matrix rx + = rvalue(x, "", index_min_max(mn + 1, mn + 1)); + EXPECT_FLOAT_EQ(1, rx.size()); + } + test_out_of_range(x, index_min_max(0, 2)); test_out_of_range(x, index_min_max(2, 5)); + + // empty min-max on empty vectors + Eigen::Matrix z(0); + EXPECT_EQ(0, rvalue(z, "", index_min_max(1, 0)).size()); + EXPECT_EQ(0, + rvalue(rvalue(x, "", index_min_max(2, 1)), "", index_min_max(1, 0)) + .size()); } TEST(ModelIndexing, rvalue_doubless_uni_uni) { diff --git a/src/test/unit/model/indexing/rvalue_varmat_test.cpp b/src/test/unit/model/indexing/rvalue_varmat_test.cpp index b03a6da82b8..7a474698392 100644 --- a/src/test/unit/model/indexing/rvalue_varmat_test.cpp +++ b/src/test/unit/model/indexing/rvalue_varmat_test.cpp @@ -264,7 +264,7 @@ TEST_F(RvalueRev, negative_min_max_vec) { } var_value x(x_val); EXPECT_NO_THROW(rvalue(x, "", index_min_max(2, 0))); - test_throw_out_of_range(x, index_min_max(5, 2)); + EXPECT_NO_THROW(rvalue(x, "", index_min_max(5, 2))); } auto make_std_varvec() { @@ -374,7 +374,7 @@ TEST_F(RvalueRev, uni_stdvec_negative_minmax_vec) { = rvalue(x, "", index_uni(2), index_min_max(2, 1)); EXPECT_EQ(0U, y.size()); EXPECT_NO_THROW(rvalue(x, "", index_uni(1), index_min_max(3, 0))); - test_throw_out_of_range(x, index_uni(1), index_min_max(15, 2)); + EXPECT_NO_THROW(rvalue(x, "", index_uni(1), index_min_max(15, 2))); } TEST_F(RvalueRev, uni_stdvec_omni_vec) { using Eigen::VectorXd; @@ -561,7 +561,7 @@ TEST_F(RvalueRev, negative_minmax_uni_matrix) { EXPECT_EQ(1U, y.cols()); test_throw_out_of_range(x, index_min_max(3, 2), index_uni(0)); test_throw_out_of_range(x, index_min_max(3, 2), index_uni(5)); - test_throw_out_of_range(x, index_min_max(6, 1), index_uni(4)); + EXPECT_NO_THROW(rvalue(x, "", index_min_max(6, 1), index_uni(4))); EXPECT_NO_THROW(rvalue(x, "", index_min_max(1, 0), index_uni(4))); } @@ -938,7 +938,7 @@ TEST_F(RvalueRev, negative_min_max_mat) { EXPECT_EQ(0, y.rows()); EXPECT_EQ(4, y.cols()); EXPECT_NO_THROW(rvalue(x, "", index_min_max(3, 0))); - test_throw_out_of_range(x, index_min_max(15, 2)); + EXPECT_NO_THROW(rvalue(x, "", index_min_max(15, 2))); } TEST_F(RvalueRev, positive_minmax_positive_minmax_matrix) { @@ -1071,7 +1071,7 @@ TEST_F(RvalueRev, uni_negative_minmax_matrix) { EXPECT_EQ(0U, y.cols()); test_throw_out_of_range(x, index_uni(0), index_min_max(4, 2)); test_throw_out_of_range(x, index_uni(7), index_min_max(4, 2)); - test_throw_out_of_range(x, index_uni(2), index_min_max(15, 0)); + EXPECT_NO_THROW(rvalue(x, "", index_uni(2), index_min_max(15, 0))); EXPECT_NO_THROW(rvalue(x, "", index_uni(2), index_min_max(2, 0))); }