Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions stan/math/prim/meta/holder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,9 +479,13 @@ inline auto make_holder_impl(F&& func, std::index_sequence<Is...>,
template <typename F, typename... Args,
require_not_plain_type_t<std::invoke_result_t<F, Args&&...>>*>
inline auto make_holder(F&& func, Args&&... args) {
return internal::make_holder_impl(std::forward<F>(func),
std::make_index_sequence<sizeof...(Args)>(),
std::forward<Args>(args)...);
if constexpr (is_var_matrix_v<std::invoke_result_t<F, Args&&...>>) {
return std::forward<F>(func)(std::forward<Args>(args)...);
} else {
return internal::make_holder_impl(
std::forward<F>(func), std::make_index_sequence<sizeof...(Args)>(),
std::forward<Args>(args)...);
}
}

/**
Expand Down
2 changes: 2 additions & 0 deletions stan/math/prim/meta/is_var_matrix.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ struct is_var_matrix
: bool_constant<
math::conjunction<is_var<T>, is_eigen<value_type_t<T>>>::value> {};

template <typename T>
inline constexpr bool is_var_matrix_v = is_var_matrix<std::decay_t<T>>::value;
/*! \ingroup require_eigens_types */
/*! \defgroup var_matrix_types var_matrix */
/*! \addtogroup var_matrix_types */
Expand Down
27 changes: 27 additions & 0 deletions test/unit/math/rev/fun/transpose_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include <stan/math/rev.hpp>
#include <test/unit/math/rev/util.hpp>
#include <gtest/gtest.h>
#include <test/unit/math/rev/fun/util.hpp>

// Reproduces a compile error: calling `transpose` on a `var_value` that holds
// a non-plain Eigen expression (e.g. a row/block of a `var_value` matrix). The
// resulting `var_value<Eigen::Transpose<...>>` is not a plain type, so
// `make_holder` tries to wrap the `var_value` in an Eigen `Holder` expression,
// which fails because `var_value` has no `StorageKind`.
TEST_F(AgradRev, RevMatrix_transpose_var_block) {
using stan::math::transpose;
using stan::math::var_value;

Eigen::MatrixXd m(2, 3);
m << 1, 2, 3, 4, 5, 6;
var_value<Eigen::MatrixXd> m_vv(m);

// m_vv.row(0) is a var_value<Eigen::Block<Eigen::Map<...>>>
auto rt = transpose(m_vv.row(0));

EXPECT_EQ(3, rt.rows());
EXPECT_EQ(1, rt.cols());
EXPECT_FLOAT_EQ(1, rt.val()(0));
EXPECT_FLOAT_EQ(2, rt.val()(1));
EXPECT_FLOAT_EQ(3, rt.val()(2));
}