Skip to content

Use perfect forwarding for functions that use apply_*_* functions #3215

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 35 commits into from
Closed
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
4eb5681
perfect forward container math overloads
SteveBronder Jun 13, 2025
81bd2d0
use perfect forwarding for functions that use apply
SteveBronder Jun 30, 2025
561f772
Merge commit 'bdd5b3ed4e54666590f5eb6fb6e822f1099da01b' into HEAD
yashikno Jun 30, 2025
e40bd1e
[Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1
stan-buildbot Jun 30, 2025
3c9462e
cleanup apply_scalar_unary
SteveBronder Jun 30, 2025
5dd0f62
[Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1
stan-buildbot Jun 30, 2025
589895d
update sum_to_zero
SteveBronder Jul 1, 2025
6301f3e
Merge commit '09542d0beef76139c8d3df580535cae80cfb0191' into HEAD
yashikno Jul 1, 2025
deec65a
[Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1
stan-buildbot Jul 1, 2025
8a824c9
fix mu and sigma ref
SteveBronder Jul 1, 2025
5fffe24
update offset_multiplier_free requires
SteveBronder Jul 1, 2025
80dbe6c
update functions with holder
SteveBronder Jul 1, 2025
50052d9
make all recursive vector functions pf so that value information is c…
SteveBronder Jul 1, 2025
939ed72
Merge remote-tracking branch 'origin/develop' into fix/perfect-forwar…
SteveBronder Jul 1, 2025
e63c866
update
SteveBronder Jul 1, 2025
67a15d5
[Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1
stan-buildbot Jul 1, 2025
ebb2dbd
fix functions that return expressions
SteveBronder Jul 2, 2025
92e4076
[Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1
stan-buildbot Jul 2, 2025
3e921d4
fix symmetrize
SteveBronder Jul 2, 2025
43a2e0b
update logic for offset_multiply to direct to correct version for std…
SteveBronder Jul 2, 2025
2b9d261
[Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1
stan-buildbot Jul 2, 2025
1144241
fix categorical_logit test to use plain type for rep_matrix
SteveBronder Jul 2, 2025
3c42f90
[Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1
stan-buildbot Jul 2, 2025
0f1658d
add back tests for rep_matrix
SteveBronder Jul 2, 2025
7958b81
[Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1
stan-buildbot Jul 2, 2025
77646e6
fix reverse
SteveBronder Jul 2, 2025
8dc16ca
Update reverse.hpp
SteveBronder Jul 2, 2025
2b52498
update block like functions for expressions
SteveBronder Jul 3, 2025
b033319
[Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1
stan-buildbot Jul 3, 2025
1ebbb3e
remove if in mdivide_left_spd as the expressions return the correct s…
SteveBronder Jul 7, 2025
7862a22
[Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1
stan-buildbot Jul 7, 2025
ea2f224
update
SteveBronder Jul 7, 2025
49a5273
use to_ref in quad_diag_form
SteveBronder Jul 8, 2025
60065f1
use to_ref in quad_diag_form
SteveBronder Jul 8, 2025
54b12e1
use to_ref in quad_diag_form
SteveBronder Jul 8, 2025
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
58 changes: 30 additions & 28 deletions stan/math/fwd/fun/log_softmax.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,36 +19,38 @@ namespace math {
* @throw std::domain_error If the input vector is size 0.
*/
template <typename T, require_vector_st<is_fvar, T>* = nullptr>
inline auto log_softmax(const T& x) {
return apply_vector_unary<T>::apply(x, [&](const auto& alpha) {
using T_alpha = decltype(alpha);
using T_fvar = value_type_t<T_alpha>;
using T_fvar_inner = typename T_fvar::Scalar;

const Eigen::Ref<const plain_type_t<T_alpha>>& alpha_ref = alpha;
Eigen::Matrix<T_fvar_inner, -1, 1> alpha_t = alpha_ref.val();
Eigen::Matrix<T_fvar_inner, -1, 1> softmax_alpha_t = softmax(alpha_t);

Eigen::Matrix<T_fvar, -1, 1> log_softmax_alpha(alpha.size());
log_softmax_alpha.val() = log_softmax(alpha_t);
log_softmax_alpha.d().setZero();

for (int m = 0; m < alpha.size(); ++m) {
T_fvar_inner negative_alpha_m_d_times_softmax_alpha_t_m
= -alpha_ref.coeff(m).d_ * softmax_alpha_t(m);
for (int k = 0; k < alpha.size(); ++k) {
if (m == k) {
log_softmax_alpha(k).d_
+= alpha_ref.coeff(m).d_
+ negative_alpha_m_d_times_softmax_alpha_t_m;
} else {
log_softmax_alpha(k).d_ += negative_alpha_m_d_times_softmax_alpha_t_m;
inline auto log_softmax(T&& x) {
return apply_vector_unary<T>::apply(
std::forward<T>(x), [&](const auto& alpha) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::forward<T>(x), [&](const auto& alpha) {
std::forward<T>(x), [](auto&& alpha) {

The apply_vector_unary functors themselves should probably also perfect-forwarding, since they'll be passing their inputs to apply_* functions as well.

Also probably best to remove the reference-capture default while we're here

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The apply_vector_unary functors themselves should probably also perfect-forwarding, since they'll be passing their inputs to apply_* functions as well.

Can you clarify? I'm not seeing in this function how much forwarding can be done. I do the perfect forwarding in the actual code for apply_vector_unary etc if that is was you mean.

Also probably best to remove the reference-capture default while we're here

Agree

using T_alpha = decltype(alpha);
using T_fvar = value_type_t<T_alpha>;
using T_fvar_inner = typename T_fvar::Scalar;

const Eigen::Ref<const plain_type_t<T_alpha>>& alpha_ref = alpha;
Eigen::Matrix<T_fvar_inner, -1, 1> alpha_t = alpha_ref.val();
Eigen::Matrix<T_fvar_inner, -1, 1> softmax_alpha_t = softmax(alpha_t);

Eigen::Matrix<T_fvar, -1, 1> log_softmax_alpha(alpha.size());
log_softmax_alpha.val() = log_softmax(alpha_t);
log_softmax_alpha.d().setZero();

for (int m = 0; m < alpha.size(); ++m) {
T_fvar_inner negative_alpha_m_d_times_softmax_alpha_t_m
= -alpha_ref.coeff(m).d_ * softmax_alpha_t(m);
for (int k = 0; k < alpha.size(); ++k) {
if (m == k) {
log_softmax_alpha(k).d_
+= alpha_ref.coeff(m).d_
+ negative_alpha_m_d_times_softmax_alpha_t_m;
} else {
log_softmax_alpha(k).d_
+= negative_alpha_m_d_times_softmax_alpha_t_m;
}
}
}
}
}

return log_softmax_alpha;
});
return log_softmax_alpha;
});
}

} // namespace math
Expand Down
4 changes: 2 additions & 2 deletions stan/math/fwd/fun/log_sum_exp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ inline fvar<T> log_sum_exp(const fvar<T>& x1, double x2) {
* @return The log of the sum of the exponentiated vector values.
*/
template <typename T, require_container_st<is_fvar, T>* = nullptr>
inline auto log_sum_exp(const T& x) {
inline auto log_sum_exp(T&& x) {
return apply_vector_unary<ref_type_t<T>>::reduce(
to_ref(x), [&](const auto& v) {
to_ref(std::forward<T>(x)), [&](const auto& v) {
using T_fvar_inner = typename value_type_t<decltype(v)>::Scalar;
using mat_type = Eigen::Matrix<T_fvar_inner, -1, -1>;
mat_type vals = v.val();
Expand Down
4 changes: 2 additions & 2 deletions stan/math/fwd/fun/norm1.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ namespace math {
* @return L1 norm of x.
*/
template <typename Container, require_eigen_vt<is_fvar, Container>* = nullptr>
inline auto norm1(const Container& x) {
inline auto norm1(Container&& x) {
return apply_vector_unary<ref_type_t<Container>>::reduce(
to_ref(x), [&](const auto& v) {
to_ref(std::forward<Container>(x)), [&](const auto& v) {
using T_fvar_inner = typename value_type_t<decltype(v)>::Scalar;
return fvar<T_fvar_inner>(norm1(v.val()),
v.d().cwiseProduct(sign(v.val())).sum());
Expand Down
4 changes: 2 additions & 2 deletions stan/math/fwd/fun/norm2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ namespace math {
* @return L2 norm of x.
*/
template <typename Container, require_eigen_vt<is_fvar, Container>* = nullptr>
inline auto norm2(const Container& x) {
inline auto norm2(Container&& x) {
return apply_vector_unary<ref_type_t<Container>>::reduce(
to_ref(x), [&](const auto& v) {
to_ref(std::forward<Container>(x)), [&](const auto& v) {
using T_fvar_inner = typename value_type_t<decltype(v)>::Scalar;
T_fvar_inner res = norm2(v.val());
return fvar<T_fvar_inner>(res,
Expand Down
8 changes: 6 additions & 2 deletions stan/math/fwd/fun/pow.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,13 @@ inline auto pow(const T1& x1, const T2& x2) {
template <typename T1, typename T2, require_any_container_t<T1, T2>* = nullptr,
require_all_not_matrix_st<is_var, T1, T2>* = nullptr,
require_any_fvar_t<base_type_t<T1>, base_type_t<T2>>* = nullptr>
inline auto pow(const T1& a, const T2& b) {
inline auto pow(T1&& a, T2&& b) {
return apply_scalar_binary(
[](const auto& c, const auto& d) { return stan::math::pow(c, d); }, a, b);
[](auto&& c, auto&& d) {
return stan::math::pow(std::forward<decltype(c)>(c),
std::forward<decltype(d)>(d));
},
std::forward<T1>(a), std::forward<T2>(b));
}

} // namespace math
Expand Down
9 changes: 6 additions & 3 deletions stan/math/fwd/functor/apply_scalar_unary.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,23 @@ namespace math {
* autodiff variable.
*/
template <typename F, typename T>
struct apply_scalar_unary<F, fvar<T> > {
struct apply_scalar_unary<F, T, require_fvar_t<T>> {
/**
* Function return type, which is same as the argument type for
* the function, <code>fvar&lt;T&gt;</code>.
*/
using return_t = fvar<T>;
using return_t = std::decay_t<T>;

/**
* Apply the function specified by F to the specified argument.
*
* @param x Argument variable.
* @return Function applied to the variable.
*/
static inline return_t apply(const fvar<T>& x) { return F::fun(x); }
template <typename T2>
static inline auto apply(const T2& x) {
return F::fun(x);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static inline auto apply(const T2& x) {
return F::fun(x);
}
static inline auto apply(T2&& x) {
return F::fun(std::forward<T2>(x));
}

Should this also be forwarding? As the downstream calls are forwarding their arguments to apply_scalar_unary<*>::apply()

};

} // namespace math
Expand Down
22 changes: 13 additions & 9 deletions stan/math/prim/constraint/cholesky_corr_constrain.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,11 @@ cholesky_corr_constrain(const EigVec& y, int K, Lp& lp) {
* @param K The size of the matrix to return
*/
template <typename T, require_std_vector_t<T>* = nullptr>
inline auto cholesky_corr_constrain(const T& y, int K) {
return apply_vector_unary<T>::apply(
y, [K](auto&& v) { return cholesky_corr_constrain(v, K); });
inline auto cholesky_corr_constrain(T&& y, int K) {
return apply_vector_unary<std::decay_t<T>>::apply(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not something you necessarily need to change in this PR, but it might be a bit cleaner to move the std::decay_t<T> handling into apply_vector_unary itself

std::forward<T>(y), [K](auto&& v) {
return cholesky_corr_constrain(std::forward<decltype(v)>(v), K);
});
}

/**
Expand All @@ -107,9 +109,11 @@ inline auto cholesky_corr_constrain(const T& y, int K) {
*/
template <typename T, typename Lp, require_std_vector_t<T>* = nullptr,
require_convertible_t<return_type_t<T>, Lp>* = nullptr>
inline auto cholesky_corr_constrain(const T& y, int K, Lp& lp) {
return apply_vector_unary<T>::apply(
y, [&lp, K](auto&& v) { return cholesky_corr_constrain(v, K, lp); });
inline auto cholesky_corr_constrain(T&& y, int K, Lp& lp) {
return apply_vector_unary<std::decay_t<T>>::apply(
std::forward<T>(y), [&lp, K](auto&& v) {
return cholesky_corr_constrain(std::forward<decltype(v)>(v), K, lp);
});
}

/**
Expand All @@ -132,11 +136,11 @@ inline auto cholesky_corr_constrain(const T& y, int K, Lp& lp) {
*/
template <bool Jacobian, typename T, typename Lp,
require_convertible_t<return_type_t<T>, Lp>* = nullptr>
inline auto cholesky_corr_constrain(const T& y, int K, Lp& lp) {
inline auto cholesky_corr_constrain(T&& y, int K, Lp& lp) {
if constexpr (Jacobian) {
return cholesky_corr_constrain(y, K, lp);
return cholesky_corr_constrain(std::forward<T>(y), K, lp);
} else {
return cholesky_corr_constrain(y, K);
return cholesky_corr_constrain(std::forward<T>(y), K);
}
}

Expand Down
8 changes: 5 additions & 3 deletions stan/math/prim/constraint/cholesky_corr_free.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,11 @@ inline auto cholesky_corr_free(const T& x) {
* @param x The standard vector to untransform.
*/
template <typename T, require_std_vector_t<T>* = nullptr>
inline auto cholesky_corr_free(const T& x) {
return apply_vector_unary<T>::apply(
x, [](auto&& v) { return cholesky_corr_free(v); });
inline auto cholesky_corr_free(T&& x) {
return apply_vector_unary<std::decay_t<T>>::apply(
std::forward<T>(x), [](auto&& v) {
return cholesky_corr_free(std::forward<decltype(v)>(v));
});
}

} // namespace math
Expand Down
24 changes: 14 additions & 10 deletions stan/math/prim/constraint/cholesky_factor_constrain.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,11 @@ cholesky_factor_constrain(const T& x, int M, int N, Lp& lp) {
* @return Cholesky factor
*/
template <typename T, require_std_vector_t<T>* = nullptr>
inline auto cholesky_factor_constrain(const T& x, int M, int N) {
return apply_vector_unary<T>::apply(
x, [M, N](auto&& v) { return cholesky_factor_constrain(v, M, N); });
inline auto cholesky_factor_constrain(T&& x, int M, int N) {
return apply_vector_unary<std::decay_t<T>>::apply(
std::forward<T>(x), [M, N](auto&& v) {
return cholesky_factor_constrain(std::forward<decltype(v)>(v), M, N);
});
}

/**
Expand All @@ -125,10 +127,12 @@ inline auto cholesky_factor_constrain(const T& x, int M, int N) {
*/
template <typename T, typename Lp, require_std_vector_t<T>* = nullptr,
require_convertible_t<return_type_t<T>, Lp>* = nullptr>
inline auto cholesky_factor_constrain(const T& x, int M, int N, Lp& lp) {
return apply_vector_unary<T>::apply(x, [&lp, M, N](auto&& v) {
return cholesky_factor_constrain(v, M, N, lp);
});
inline auto cholesky_factor_constrain(T&& x, int M, int N, Lp& lp) {
return apply_vector_unary<std::decay_t<T>>::apply(
std::forward<T>(x), [&lp, M, N](auto&& v) {
return cholesky_factor_constrain(std::forward<decltype(v)>(v), M, N,
lp);
});
}

/**
Expand All @@ -155,11 +159,11 @@ inline auto cholesky_factor_constrain(const T& x, int M, int N, Lp& lp) {
*/
template <bool Jacobian, typename T, typename Lp,
require_convertible_t<return_type_t<T>, Lp>* = nullptr>
inline auto cholesky_factor_constrain(const T& x, int M, int N, Lp& lp) {
inline auto cholesky_factor_constrain(T&& x, int M, int N, Lp& lp) {
if constexpr (Jacobian) {
return cholesky_factor_constrain(x, M, N, lp);
return cholesky_factor_constrain(std::forward<T>(x), M, N, lp);
} else {
return cholesky_factor_constrain(x, M, N);
return cholesky_factor_constrain(std::forward<T>(x), M, N);
}
}

Expand Down
8 changes: 5 additions & 3 deletions stan/math/prim/constraint/cholesky_factor_free.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,11 @@ Eigen::Matrix<value_type_t<T>, Eigen::Dynamic, 1> cholesky_factor_free(
* @param x The standard vector to untransform.
*/
template <typename T, require_std_vector_t<T>* = nullptr>
inline auto cholesky_factor_free(const T& x) {
return apply_vector_unary<T>::apply(
x, [](auto&& v) { return cholesky_factor_free(v); });
inline auto cholesky_factor_free(T&& x) {
return apply_vector_unary<std::decay_t<T>>::apply(
std::forward<T>(x), [](auto&& v) {
return cholesky_factor_free(std::forward<decltype(v)>(v));
});
}

} // namespace math
Expand Down
12 changes: 6 additions & 6 deletions stan/math/prim/constraint/corr_constrain.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ namespace math {
* @return tanh transform
*/
template <typename T>
inline plain_type_t<T> corr_constrain(const T& x) {
return tanh(x);
inline plain_type_t<T> corr_constrain(T&& x) {
return tanh(std::forward<T>(x));
}

/**
Expand All @@ -43,7 +43,7 @@ inline plain_type_t<T> corr_constrain(const T& x) {
* @param[in,out] lp log density accumulator
*/
template <typename T_x, typename T_lp>
inline auto corr_constrain(const T_x& x, T_lp& lp) {
inline auto corr_constrain(T_x&& x, T_lp& lp) {
plain_type_t<T_x> tanh_x = tanh(x);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
plain_type_t<T_x> tanh_x = tanh(x);
plain_type_t<T_x> tanh_x = tanh(std::forward<T_x>(x));

lp += sum(log1m(square(tanh_x)));
return tanh_x;
Expand All @@ -65,11 +65,11 @@ inline auto corr_constrain(const T_x& x, T_lp& lp) {
* @param[in,out] lp log density accumulator
*/
template <bool Jacobian, typename T_x, typename T_lp>
inline auto corr_constrain(const T_x& x, T_lp& lp) {
inline auto corr_constrain(T_x&& x, T_lp& lp) {
if constexpr (Jacobian) {
return corr_constrain(x, lp);
return corr_constrain(std::forward<T_x>(x), lp);
} else {
return corr_constrain(x);
return corr_constrain(std::forward<T_x>(x));
}
}

Expand Down
4 changes: 2 additions & 2 deletions stan/math/prim/constraint/corr_free.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ namespace math {
* @return free scalar that transforms to the specified input
*/
template <typename T>
inline plain_type_t<T> corr_free(const T& y) {
inline plain_type_t<T> corr_free(T&& y) {
check_bounded("lub_free", "Correlation variable", y, -1.0, 1.0);
return atanh(y);
return atanh(std::forward<T>(y));
}

} // namespace math
Expand Down
34 changes: 19 additions & 15 deletions stan/math/prim/constraint/corr_matrix_constrain.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ namespace math {
*/
template <typename T, require_eigen_col_vector_t<T>* = nullptr>
inline Eigen::Matrix<value_type_t<T>, Eigen::Dynamic, Eigen::Dynamic>
corr_matrix_constrain(const T& x, Eigen::Index k) {
Eigen::Index k_choose_2 = (k * (k - 1)) / 2;
corr_matrix_constrain(T&& x, Eigen::Index k) {
const Eigen::Index k_choose_2 = (k * (k - 1)) / 2;
check_size_match("cov_matrix_constrain", "x.size()", x.size(), "k_choose_2",
k_choose_2);
return read_corr_matrix(corr_constrain(x), k);
return read_corr_matrix(corr_constrain(std::forward<T>(x)), k);
}

/**
Expand Down Expand Up @@ -70,11 +70,11 @@ corr_matrix_constrain(const T& x, Eigen::Index k) {
template <typename T, typename Lp, require_eigen_col_vector_t<T>* = nullptr,
require_convertible_t<return_type_t<T>, Lp>* = nullptr>
inline Eigen::Matrix<value_type_t<T>, Eigen::Dynamic, Eigen::Dynamic>
corr_matrix_constrain(const T& x, Eigen::Index k, Lp& lp) {
Eigen::Index k_choose_2 = (k * (k - 1)) / 2;
corr_matrix_constrain(T&& x, Eigen::Index k, Lp& lp) {
const Eigen::Index k_choose_2 = (k * (k - 1)) / 2;
check_size_match("cov_matrix_constrain", "x.size()", x.size(), "k_choose_2",
k_choose_2);
return read_corr_matrix(corr_constrain(x, lp), k, lp);
return read_corr_matrix(corr_constrain(std::forward<T>(x), lp), k, lp);
}

/**
Expand All @@ -91,9 +91,11 @@ corr_matrix_constrain(const T& x, Eigen::Index k, Lp& lp) {
* @param K Dimensionality of returned correlation matrix
*/
template <typename T, require_std_vector_t<T>* = nullptr>
inline auto corr_matrix_constrain(const T& y, int K) {
return apply_vector_unary<T>::apply(
y, [K](auto&& v) { return corr_matrix_constrain(v, K); });
inline auto corr_matrix_constrain(T&& y, int K) {
return apply_vector_unary<std::decay_t<T>>::apply(
std::forward<T>(y), [K](auto&& v) {
return corr_matrix_constrain(std::forward<decltype(v)>(v), K);
});
}

/**
Expand All @@ -114,9 +116,11 @@ inline auto corr_matrix_constrain(const T& y, int K) {
*/
template <typename T, typename Lp, require_std_vector_t<T>* = nullptr,
require_convertible_t<return_type_t<T>, Lp>* = nullptr>
inline auto corr_matrix_constrain(const T& y, int K, Lp& lp) {
return apply_vector_unary<T>::apply(
y, [&lp, K](auto&& v) { return corr_matrix_constrain(v, K, lp); });
inline auto corr_matrix_constrain(T&& y, int K, Lp& lp) {
return apply_vector_unary<std::decay_t<T>>::apply(
std::forward<T>(y), [&lp, K](auto&& v) {
return corr_matrix_constrain(std::forward<decltype(v)>(v), K, lp);
});
}

/**
Expand All @@ -142,11 +146,11 @@ inline auto corr_matrix_constrain(const T& y, int K, Lp& lp) {
*/
template <bool Jacobian, typename T, typename Lp,
require_convertible_t<return_type_t<T>, Lp>* = nullptr>
inline auto corr_matrix_constrain(const T& x, Eigen::Index k, Lp& lp) {
inline auto corr_matrix_constrain(T&& x, Eigen::Index k, Lp& lp) {
if constexpr (Jacobian) {
return corr_matrix_constrain(x, k, lp);
return corr_matrix_constrain(std::forward<T>(x), k, lp);
} else {
return corr_matrix_constrain(x, k);
return corr_matrix_constrain(std::forward<T>(x), k);
}
}

Expand Down
Loading