9
9
#include < stan/math/prim/fun/max_size.hpp>
10
10
#include < stan/math/prim/fun/size.hpp>
11
11
#include < stan/math/prim/fun/size_zero.hpp>
12
+ #include < stan/math/prim/fun/to_ref.hpp>
12
13
#include < stan/math/prim/fun/value_of.hpp>
13
14
#include < stan/math/prim/functor/operands_and_partials.hpp>
14
15
#include < cmath>
@@ -37,13 +38,17 @@ template <bool propto, typename T_y, typename T_loc, typename T_scale>
37
38
return_type_t <T_y, T_loc, T_scale> cauchy_lpdf (const T_y& y, const T_loc& mu,
38
39
const T_scale& sigma) {
39
40
using T_partials_return = partials_return_t <T_y, T_loc, T_scale>;
41
+ using T_partials_array = Eigen::Array<T_partials_return, Eigen::Dynamic, 1 >;
40
42
using std::log ;
43
+ using T_y_ref = ref_type_if_t <!is_constant<T_y>::value, T_y>;
44
+ using T_mu_ref = ref_type_if_t <!is_constant<T_loc>::value, T_loc>;
45
+ using T_sigma_ref = ref_type_if_t <!is_constant<T_scale>::value, T_scale>;
41
46
static const char * function = " cauchy_lpdf" ;
42
- check_not_nan (function, " Random variable" , y);
43
- check_finite (function, " Location parameter" , mu);
44
- check_positive_finite (function, " Scale parameter" , sigma);
45
47
check_consistent_sizes (function, " Random variable" , y, " Location parameter" ,
46
48
mu, " Scale parameter" , sigma);
49
+ T_y_ref y_ref = y;
50
+ T_mu_ref mu_ref = mu;
51
+ T_sigma_ref sigma_ref = sigma;
47
52
48
53
if (size_zero (y, mu, sigma)) {
49
54
return 0.0 ;
@@ -53,57 +58,76 @@ return_type_t<T_y, T_loc, T_scale> cauchy_lpdf(const T_y& y, const T_loc& mu,
53
58
}
54
59
55
60
T_partials_return logp (0.0 );
56
- operands_and_partials<T_y, T_loc, T_scale> ops_partials (y, mu, sigma);
61
+ operands_and_partials<T_y_ref, T_mu_ref, T_sigma_ref> ops_partials (
62
+ y_ref, mu_ref, sigma_ref);
57
63
58
- scalar_seq_view<T_y> y_vec (y);
59
- scalar_seq_view<T_loc> mu_vec (mu);
60
- scalar_seq_view<T_scale> sigma_vec (sigma);
61
- size_t N = max_size (y, mu, sigma);
64
+ const auto & y_col = as_column_vector_or_scalar (y_ref);
65
+ const auto & mu_col = as_column_vector_or_scalar (mu_ref);
66
+ const auto & sigma_col = as_column_vector_or_scalar (sigma_ref);
62
67
63
- VectorBuilder<true , T_partials_return, T_scale> inv_sigma (size (sigma));
64
- VectorBuilder<true , T_partials_return, T_scale> sigma_squared (size (sigma));
65
- VectorBuilder<include_summand<propto, T_scale>::value, T_partials_return,
66
- T_scale>
67
- log_sigma (size (sigma));
68
- for (size_t i = 0 ; i < stan::math::size (sigma); i++) {
69
- const T_partials_return sigma_dbl = value_of (sigma_vec[i]);
70
- inv_sigma[i] = 1.0 / sigma_dbl;
71
- sigma_squared[i] = sigma_dbl * sigma_dbl;
72
- if (include_summand<propto, T_scale>::value) {
73
- log_sigma[i] = log (sigma_dbl);
74
- }
75
- }
68
+ const auto & y_arr = as_array_or_scalar (y_col);
69
+ const auto & mu_arr = as_array_or_scalar (mu_col);
70
+ const auto & sigma_arr = as_array_or_scalar (sigma_col);
76
71
77
- for (size_t n = 0 ; n < N; n++) {
78
- const T_partials_return y_dbl = value_of (y_vec[n]);
79
- const T_partials_return mu_dbl = value_of (mu_vec[n]);
72
+ ref_type_t <decltype (value_of (y_arr))> y_val = value_of (y_arr);
73
+ ref_type_t <decltype (value_of (mu_arr))> mu_val = value_of (mu_arr);
74
+ ref_type_t <decltype (value_of (sigma_arr))> sigma_val = value_of (sigma_arr);
75
+ check_not_nan (function, " Random variable" , y_val);
76
+ check_finite (function, " Location parameter" , mu_val);
77
+ check_positive_finite (function, " Scale parameter" , sigma_val);
80
78
81
- const T_partials_return y_minus_mu = y_dbl - mu_dbl;
82
- const T_partials_return y_minus_mu_squared = y_minus_mu * y_minus_mu;
83
- const T_partials_return y_minus_mu_over_sigma = y_minus_mu * inv_sigma[n];
84
- const T_partials_return y_minus_mu_over_sigma_squared
85
- = y_minus_mu_over_sigma * y_minus_mu_over_sigma;
79
+ size_t N = max_size (y, mu, sigma);
86
80
87
- if (include_summand<propto>::value) {
88
- logp -= LOG_PI;
89
- }
90
- if (include_summand<propto, T_scale>::value) {
91
- logp -= log_sigma[n];
92
- }
93
- logp -= log1p (y_minus_mu_over_sigma_squared);
81
+ const auto & inv_sigma
82
+ = to_ref_if<!is_constant_all<T_scale>::value>(inv (sigma_val));
83
+ const auto & y_minus_mu
84
+ = to_ref_if<!is_constant_all<T_y, T_loc, T_scale>::value>(y_val - mu_val);
94
85
95
- if (!is_constant_all<T_y>::value) {
96
- ops_partials.edge1_ .partials_ [n]
97
- -= 2 * y_minus_mu / (sigma_squared[n] + y_minus_mu_squared);
98
- }
99
- if (!is_constant_all<T_loc>::value) {
100
- ops_partials.edge2_ .partials_ [n]
101
- += 2 * y_minus_mu / (sigma_squared[n] + y_minus_mu_squared);
86
+ logp -= sum (log1p (square (y_minus_mu * inv_sigma)));
87
+ if (include_summand<propto>::value) {
88
+ logp -= N * LOG_PI;
89
+ }
90
+ if (include_summand<propto, T_scale>::value) {
91
+ logp -= sum (log (sigma_val)) * N / size (sigma);
92
+ }
93
+
94
+ if (!is_constant_all<T_y, T_loc, T_scale>::value) {
95
+ const auto & sigma_squared
96
+ = to_ref_if<!is_constant_all<T_scale>::value>(square (sigma_val));
97
+ const auto & y_minus_mu_squared
98
+ = to_ref_if<!is_constant_all<T_scale>::value>(square (y_minus_mu));
99
+ if (!is_constant_all<T_y, T_loc>::value) {
100
+ const auto & mu_deriv
101
+ = to_ref_if < !is_constant_all<T_y>::value
102
+ && !is_constant_all<T_loc>::value
103
+ > (2 * y_minus_mu / (sigma_squared + y_minus_mu_squared));
104
+ if (!is_constant_all<T_y>::value) {
105
+ if (is_vector<T_y>::value) {
106
+ ops_partials.edge1_ .partials_
107
+ = forward_as<T_partials_array>(-mu_deriv);
108
+ } else {
109
+ ops_partials.edge1_ .partials_ [0 ] = -sum (mu_deriv);
110
+ }
111
+ }
112
+ if (!is_constant_all<T_loc>::value) {
113
+ if (is_vector<T_loc>::value) {
114
+ ops_partials.edge2_ .partials_
115
+ = std::move (forward_as<T_partials_array>(mu_deriv));
116
+ } else {
117
+ ops_partials.edge2_ .partials_ [0 ] = sum (mu_deriv);
118
+ }
119
+ }
102
120
}
103
121
if (!is_constant_all<T_scale>::value) {
104
- ops_partials.edge3_ .partials_ [n]
105
- += (y_minus_mu_squared - sigma_squared[n]) * inv_sigma[n]
106
- / (sigma_squared[n] + y_minus_mu_squared);
122
+ if (is_vector<T_scale>::value) {
123
+ ops_partials.edge3_ .partials_ = forward_as<T_partials_array>(
124
+ (y_minus_mu_squared - sigma_squared) * inv_sigma
125
+ / (sigma_squared + y_minus_mu_squared));
126
+ } else {
127
+ ops_partials.edge3_ .partials_ [0 ]
128
+ = sum ((y_minus_mu_squared - sigma_squared) * inv_sigma
129
+ / (sigma_squared + y_minus_mu_squared));
130
+ }
107
131
}
108
132
}
109
133
return ops_partials.build (logp);
0 commit comments