From b13902bb369801fb6076f6953ada8c828704d21c Mon Sep 17 00:00:00 2001 From: Stefan Kienle <127690239+stekien@users.noreply.github.com> Date: Thu, 24 Sep 2026 14:52:25 -0400 Subject: [PATCH] Rename zip() to zip_index() Renames stan::math::zip to stan::math::zip_index, along with the header, the unit test file, the include guard, the function-name strings in the error checks, and the test names. No behavioral change. The original name suggested the usual zip semantics of combining two sequences into pairs, whereas the function gathers matrix elements at paired row/column indices. Related to stan-dev/stanc3#1704 --- stan/math/prim/fun.hpp | 2 +- stan/math/prim/fun/{zip.hpp => zip_index.hpp} | 27 ++++++++------ stan/math/rev/fun.hpp | 2 +- stan/math/rev/fun/{zip.hpp => zip_index.hpp} | 19 +++++----- .../fun/{zip_test.cpp => zip_index_test.cpp} | 20 +++++----- .../fun/{zip_test.cpp => zip_index_test.cpp} | 37 ++++++++++--------- 6 files changed, 57 insertions(+), 50 deletions(-) rename stan/math/prim/fun/{zip.hpp => zip_index.hpp} (64%) rename stan/math/rev/fun/{zip.hpp => zip_index.hpp} (71%) rename test/unit/math/prim/fun/{zip_test.cpp => zip_index_test.cpp} (69%) rename test/unit/math/rev/fun/{zip_test.cpp => zip_index_test.cpp} (74%) diff --git a/stan/math/prim/fun.hpp b/stan/math/prim/fun.hpp index a09499863d4..8ef4204c81b 100644 --- a/stan/math/prim/fun.hpp +++ b/stan/math/prim/fun.hpp @@ -353,6 +353,6 @@ #include #include #include -#include +#include #endif diff --git a/stan/math/prim/fun/zip.hpp b/stan/math/prim/fun/zip_index.hpp similarity index 64% rename from stan/math/prim/fun/zip.hpp rename to stan/math/prim/fun/zip_index.hpp index 4c1903cd2bc..e9c93fdf0cd 100644 --- a/stan/math/prim/fun/zip.hpp +++ b/stan/math/prim/fun/zip_index.hpp @@ -1,5 +1,5 @@ -#ifndef STAN_MATH_PRIM_FUN_ZIP_HPP -#define STAN_MATH_PRIM_FUN_ZIP_HPP +#ifndef STAN_MATH_PRIM_FUN_ZIP_INDEX_HPP +#define STAN_MATH_PRIM_FUN_ZIP_INDEX_HPP #include #include @@ -10,9 +10,8 @@ namespace stan { namespace math { /** - * Return a vector of matrix values obtained by zipping - * two N-dimensional integer vectors to form tuples of - * corresponding elements. + * Return the column vector of elements of x selected + * by paired (zipped) 1-based row and column indices * * @tparam EigMat type of the matrix * @param x input matrix @@ -25,9 +24,9 @@ namespace math { template * = nullptr, require_all_vector_t* = nullptr> -inline auto zip(EigMat&& x, IdxRows&& idx_row, IdxCols&& idx_col) { - check_size_match("zip", "size of idx_row", idx_row.size(), "size of idx_col", - idx_col.size()); +inline auto zip_index(EigMat&& x, IdxRows&& idx_row, IdxCols&& idx_col) { + check_size_match("zip_index", "size of idx_row", idx_row.size(), + "size of idx_col", idx_col.size()); return make_holder( [](auto&& x_, auto&& idx_row_, auto&& idx_col_) { using map_t = Eigen::Map>; @@ -35,10 +34,14 @@ inline auto zip(EigMat&& x, IdxRows&& idx_row, IdxCols&& idx_col) { const map_t cols(idx_col_.data(), idx_col_.size()); // If the user turns of range checks do not pay for min and max sweeps #ifndef STAN_NO_RANGE_CHECKS - check_range("zip", "minimum row index", x_.rows(), rows.minCoeff()); - check_range("zip", "maximum row index", x_.rows(), rows.maxCoeff()); - check_range("zip", "minimum column index", x_.cols(), cols.minCoeff()); - check_range("zip", "maximum column index", x_.cols(), cols.maxCoeff()); + check_range("zip_index", "minimum row index", x_.rows(), + rows.minCoeff()); + check_range("zip_index", "maximum row index", x_.rows(), + rows.maxCoeff()); + check_range("zip_index", "minimum column index", x_.cols(), + cols.minCoeff()); + check_range("zip_index", "maximum column index", x_.cols(), + cols.maxCoeff()); #endif const auto linear_idx = (rows.cast() - 1) + (cols.cast() - 1) * x_.rows(); diff --git a/stan/math/rev/fun.hpp b/stan/math/rev/fun.hpp index d6f02c3f13f..e5ef938a302 100644 --- a/stan/math/rev/fun.hpp +++ b/stan/math/rev/fun.hpp @@ -183,7 +183,7 @@ #include #include #include -#include +#include #include #include diff --git a/stan/math/rev/fun/zip.hpp b/stan/math/rev/fun/zip_index.hpp similarity index 71% rename from stan/math/rev/fun/zip.hpp rename to stan/math/rev/fun/zip_index.hpp index 9214cb6ce25..0c137e7333e 100644 --- a/stan/math/rev/fun/zip.hpp +++ b/stan/math/rev/fun/zip_index.hpp @@ -1,11 +1,11 @@ -#ifndef STAN_MATH_REV_FUN_ZIP_HPP -#define STAN_MATH_REV_FUN_ZIP_HPP +#ifndef STAN_MATH_REV_FUN_ZIP_INDEX_HPP +#define STAN_MATH_REV_FUN_ZIP_INDEX_HPP #include #include #include #include -#include +#include #include namespace stan::math { @@ -29,18 +29,19 @@ namespace stan::math { template * = nullptr, require_all_std_vector_t* = nullptr> -inline var_value zip(const var_value& x, - IdxRows&& idx_row, IdxCols&& idx_col) { - check_size_match("zip", "size of idx_row", idx_row.size(), "size of idx_col", - idx_col.size()); +inline var_value zip_index(const var_value& x, + IdxRows&& idx_row, + IdxCols&& idx_col) { + check_size_match("zip_index", "size of idx_row", idx_row.size(), + "size of idx_col", idx_col.size()); if (idx_row.empty()) { return var_value(Eigen::VectorXd(0)); } auto rows = to_arena(std::forward(idx_row)); auto cols = to_arena(std::forward(idx_col)); - return make_callback_var(zip(x.val(), rows, cols), + return make_callback_var(zip_index(x.val(), rows, cols), [x, rows, cols](auto& vi) mutable { - zip(x.adj(), rows, cols) += vi.adj(); + zip_index(x.adj(), rows, cols) += vi.adj(); }); } diff --git a/test/unit/math/prim/fun/zip_test.cpp b/test/unit/math/prim/fun/zip_index_test.cpp similarity index 69% rename from test/unit/math/prim/fun/zip_test.cpp rename to test/unit/math/prim/fun/zip_index_test.cpp index 79c489348e6..31b51f5304a 100644 --- a/test/unit/math/prim/fun/zip_test.cpp +++ b/test/unit/math/prim/fun/zip_index_test.cpp @@ -3,7 +3,7 @@ #include #include -TEST(MathFunctions, zip) { +TEST(MathFunctions, zip_index) { const int J = 5; // Number of locations const int K = 4; // Number of time categories @@ -15,7 +15,7 @@ TEST(MathFunctions, zip) { std::vector loc = {1, 1, 5, 2, 3, 3, 4, 4, 5}; - Eigen::VectorXd zipped = stan::math::zip(delta, loc, time); + Eigen::VectorXd zipped = stan::math::zip_index(delta, loc, time); EXPECT_EQ(zipped.size(), loc.size()); EXPECT_DOUBLE_EQ(zipped[0], delta(0, 0)); @@ -29,7 +29,7 @@ TEST(MathFunctions, zip) { EXPECT_DOUBLE_EQ(zipped[8], delta(4, 0)); } -TEST(MathFunctions, zip_errors) { +TEST(MathFunctions, zip_index_errors) { Eigen::MatrixXd delta(5, 4); // 5 rows, 4 columns delta.setZero(); @@ -37,25 +37,27 @@ TEST(MathFunctions, zip_errors) { std::vector cols = {1, 2, 3}; // valid input does not throw - EXPECT_NO_THROW(stan::math::zip(delta, rows, cols)); + EXPECT_NO_THROW(stan::math::zip_index(delta, rows, cols)); // index vectors of different sizes std::vector cols_short = {1, 2}; - EXPECT_THROW(stan::math::zip(delta, rows, cols_short), std::invalid_argument); + EXPECT_THROW(stan::math::zip_index(delta, rows, cols_short), + std::invalid_argument); // row index too large (matrix has 5 rows) std::vector rows_big = {1, 6, 3}; - EXPECT_THROW(stan::math::zip(delta, rows_big, cols), std::out_of_range); + EXPECT_THROW(stan::math::zip_index(delta, rows_big, cols), std::out_of_range); // row index too small (indices are 1-based) std::vector rows_zero = {0, 2, 3}; - EXPECT_THROW(stan::math::zip(delta, rows_zero, cols), std::out_of_range); + EXPECT_THROW(stan::math::zip_index(delta, rows_zero, cols), + std::out_of_range); // column index too large (matrix has 4 columns) std::vector cols_big = {1, 5, 3}; - EXPECT_THROW(stan::math::zip(delta, rows, cols_big), std::out_of_range); + EXPECT_THROW(stan::math::zip_index(delta, rows, cols_big), std::out_of_range); // column index too small std::vector cols_neg = {1, -1, 3}; - EXPECT_THROW(stan::math::zip(delta, rows, cols_neg), std::out_of_range); + EXPECT_THROW(stan::math::zip_index(delta, rows, cols_neg), std::out_of_range); } diff --git a/test/unit/math/rev/fun/zip_test.cpp b/test/unit/math/rev/fun/zip_index_test.cpp similarity index 74% rename from test/unit/math/rev/fun/zip_test.cpp rename to test/unit/math/rev/fun/zip_index_test.cpp index f0e28e417c7..24316ca300e 100644 --- a/test/unit/math/rev/fun/zip_test.cpp +++ b/test/unit/math/rev/fun/zip_index_test.cpp @@ -3,13 +3,13 @@ #include #include -TEST_F(AgradRev, zip_values_and_gradients) { +TEST_F(AgradRev, zip_index_values_and_gradients) { Eigen::MatrixXd values(3, 2); values << 11, 12, 21, 22, 31, 32; stan::math::var_value x = values; const std::vector rows{3, 1, 3, 2, 1}; const std::vector cols{2, 1, 2, 1, 2}; - const auto y = stan::math::zip(x, rows, cols); + const auto y = stan::math::zip_index(x, rows, cols); EXPECT_EQ(y.rows(), 5); EXPECT_EQ(y.cols(), 1); @@ -36,12 +36,12 @@ TEST_F(AgradRev, zip_index_lifetime) { auto y = [&x]() { std::vector rows{1, 2, 1}; std::vector cols{3, 1, 3}; - auto result = stan::math::zip(x, std::move(rows), std::move(cols)); + auto result = stan::math::zip_index(x, std::move(rows), std::move(cols)); rows.assign(3, 2); cols.assign(3, 2); return result; }(); - auto z = stan::math::zip(x, std::vector{2}, std::vector{2}); + auto z = stan::math::zip_index(x, std::vector{2}, std::vector{2}); stan::math::var objective = stan::math::sum(y) + stan::math::sum(z); objective.grad(); EXPECT_DOUBLE_EQ(x.adj()(0, 0), 0); @@ -52,12 +52,12 @@ TEST_F(AgradRev, zip_index_lifetime) { EXPECT_DOUBLE_EQ(x.adj()(1, 2), 0); } -TEST_F(AgradRev, zip_matrix_view) { +TEST_F(AgradRev, zip_index_matrix_view) { Eigen::MatrixXd values(3, 3); values << 11, 12, 13, 21, 22, 23, 31, 32, 33; stan::math::var_value x = values; - auto y = stan::math::zip(x.block(1, 1, 2, 2), std::vector{2, 1, 2}, - std::vector{1, 2, 1}); + auto y = stan::math::zip_index(x.block(1, 1, 2, 2), std::vector{2, 1, 2}, + std::vector{1, 2, 1}); EXPECT_DOUBLE_EQ(y.val()(0), 32); EXPECT_DOUBLE_EQ(y.val()(1), 23); EXPECT_DOUBLE_EQ(y.val()(2), 32); @@ -70,14 +70,14 @@ TEST_F(AgradRev, zip_matrix_view) { } } -TEST_F(AgradRev, zip_row_major) { +TEST_F(AgradRev, zip_index_row_major) { using matrix_t = Eigen::Matrix; matrix_t values(2, 3); values << 11, 12, 13, 21, 22, 23; stan::math::var_value x = values; - auto y = stan::math::zip(x, std::vector{2, 1, 2}, - std::vector{1, 3, 1}); + auto y = stan::math::zip_index(x, std::vector{2, 1, 2}, + std::vector{1, 3, 1}); EXPECT_DOUBLE_EQ(y.val()(0), 21); EXPECT_DOUBLE_EQ(y.val()(1), 13); EXPECT_DOUBLE_EQ(y.val()(2), 21); @@ -90,13 +90,13 @@ TEST_F(AgradRev, zip_row_major) { } } -TEST_F(AgradRev, zip_empty) { +TEST_F(AgradRev, zip_index_empty) { const std::vector indices; for (int rows : {0, 2}) { for (int cols : {0, 3}) { stan::math::var_value x = Eigen::MatrixXd::Ones(rows, cols); - auto y = stan::math::zip(x, indices, indices); + auto y = stan::math::zip_index(x, indices, indices); EXPECT_EQ(y.rows(), 0); EXPECT_EQ(y.cols(), 1); stan::math::sum(y).grad(); @@ -105,18 +105,18 @@ TEST_F(AgradRev, zip_empty) { } } -TEST_F(AgradRev, zip_errors) { +TEST_F(AgradRev, zip_index_errors) { stan::math::var_value x = Eigen::MatrixXd::Zero(3, 2); const std::vector valid{1, 2}; const std::vector empty; - EXPECT_THROW(stan::math::zip(x, valid, empty), std::invalid_argument); - EXPECT_THROW(stan::math::zip(x, empty, valid), std::invalid_argument); + EXPECT_THROW(stan::math::zip_index(x, valid, empty), std::invalid_argument); + EXPECT_THROW(stan::math::zip_index(x, empty, valid), std::invalid_argument); for (int row : {-1, 0, 4}) { - EXPECT_THROW(stan::math::zip(x, std::vector{1, row}, valid), + EXPECT_THROW(stan::math::zip_index(x, std::vector{1, row}, valid), std::out_of_range); } for (int col : {-1, 0, 3}) { - EXPECT_THROW(stan::math::zip(x, valid, std::vector{1, col}), + EXPECT_THROW(stan::math::zip_index(x, valid, std::vector{1, col}), std::out_of_range); } for (int rows : {0, 2}) { @@ -126,7 +126,8 @@ TEST_F(AgradRev, zip_errors) { } stan::math::var_value empty_x = Eigen::MatrixXd::Zero(rows, cols); - EXPECT_THROW(stan::math::zip(empty_x, valid, valid), std::out_of_range); + EXPECT_THROW(stan::math::zip_index(empty_x, valid, valid), + std::out_of_range); } } }