Skip to content

Commit 69d29c5

Browse files
committed
Allow forward_as to convert integers to doubles
1 parent 9f23455 commit 69d29c5

3 files changed

Lines changed: 48 additions & 2 deletions

File tree

stan/math/prim/meta/forward_as.hpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,39 @@ inline T_actual&& forward_as(T_actual&& a) { // NOLINT
5555
* @throw always throws std::runtime_error
5656
*/
5757
template <typename T_desired, typename T_actual,
58+
require_any_not_eigen_t<T_desired, T_actual>* = nullptr,
5859
typename = std::enable_if_t<
5960
!std::is_same<std::decay<T_actual>, std::decay<T_desired>>::value
60-
&& (!is_eigen<T_desired>::value || !is_eigen<T_actual>::value)>>
61+
&& !(std::is_arithmetic_v<std::decay_t<T_desired>>
62+
&& std::is_arithmetic_v<std::decay_t<T_actual>>)>>
6163
inline T_desired forward_as(const T_actual& a) {
6264
throw std::runtime_error("Wrong type assumed! Please file a bug report.");
6365
}
6466

67+
/** \ingroup type_trait
68+
* Assume which type we get. If actual type is not convertible to assumed type
69+
* or in case of eigen types compile time rows and columns are not the same and
70+
* desired sizes are not dynamic this has return type of \c T_desired, but it
71+
* only throws. This version should only be used where it is optimized away so
72+
* the throw should never happen.
73+
*
74+
* This handles the edge case where both types are simple arithmetic types
75+
* and we would like to just convert one to another.
76+
*
77+
* @tparam T_desired type of output we need to avoid compile time errors
78+
* @tparam T_actual actual type of the argument
79+
* @param a input value
80+
* @return a
81+
*/
82+
template <typename T_desired, typename T_actual,
83+
typename = std::enable_if_t<
84+
!std::is_same_v<std::decay_t<T_actual>, std::decay_t<T_desired>>
85+
&& std::is_arithmetic_v<std::decay_t<T_desired>>
86+
&& std::is_arithmetic_v<std::decay_t<T_actual>>>>
87+
inline T_desired forward_as(const T_actual& a) {
88+
return static_cast<T_desired>(a);
89+
}
90+
6591
/** \ingroup type_trait
6692
* Assume which type we get. If actual type is convertible to assumed type or in
6793
* case of eigen types compile time rows and columns also match or desired sizes

test/unit/math/prim/meta/forward_as_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ TEST(MathMetaPrim, ForwardAsScalar) {
99

1010
EXPECT_NO_THROW(forward_as<int>(a) = 2);
1111
EXPECT_EQ(a, 2);
12-
EXPECT_THROW(forward_as<double>(a), std::runtime_error);
12+
EXPECT_FLOAT_EQ(forward_as<double>(a), 2.0);
1313
}

test/unit/math/rev/prob/normal_id_glm_lpdf_test.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,3 +745,23 @@ TEST(ProbDistributionsNormalIdGLM, glm_matches_normal_id_error_checking) {
745745
EXPECT_THROW(stan::math::normal_id_glm_lpdf(y, x, alpha, beta, sigmaw3),
746746
std::domain_error);
747747
}
748+
749+
TEST(ProbDistributionsNormalIdGLM, glm_type_issue_3189) {
750+
// regression test for https://github.com/stan-dev/math/issues/3189
751+
using Eigen::Dynamic;
752+
using Eigen::Matrix;
753+
using stan::math::var;
754+
int J = 3;
755+
int K = 2;
756+
757+
Eigen::Matrix<double, -1, -1> x(J, K);
758+
x << 1.0, 2.0, 3.0, 4.0, 5.0, 6.0;
759+
760+
Eigen::Matrix<stan::math::var, -1, 1> y(J);
761+
y << 0.1, 0.2, 0.3;
762+
Eigen::Matrix<stan::math::var, -1, 1> beta(K);
763+
beta << 0.5, 0.6;
764+
765+
EXPECT_FLOAT_EQ(stan::math::normal_id_glm_lpdf<false>(y, x, 0, beta, 1).val(),
766+
-27.701815);
767+
}

0 commit comments

Comments
 (0)