The pr #979 added the jacobian += and _jacobian function keyword to indicate adding the change of variables correction for a transformed parameter. The jacobian functionality can only be used in the transformed parameters block. That same pr also introduced a warning that _lp type functions will no longer be allowed in the transformed parameters block and will only be supported in the model block. I think the introduction of the jacobian functionality is useful but I believe restricting the _lp to only the model block is a step backwards for Stan.
In merging #979, which users will first see in cmdstan 2.36, any user defined function ending with _lp that is used in the transformed parameters block will receive a warning that this functionality will not be allowed in future releases. The initial reasoning in the discussion for #979 is that allowing functions to access the target was a bug in stanc2 that we continued to support in stanc3. The merged pr is indicating the "fix". However, there are times where it is useful to both add the jacobian correction and to add a log density. I don't believe this is widespread but in matrix parameters I encounter it. For example, below I show the c-vine parameterization of a correlation matrix. I use both the jacobian and the target keywords here. I'm not sure this will compile because I believe it would need to end in _jacobian. I have been using target everywhere where jacobian now is which does compile in previous versions.
vector lb_ub_lp (vector y, real lb, real ub) {
target += log(ub - lb) + log_inv_logit(y) + log1m_inv_logit(y);
return lb + (ub - lb) * inv_logit(y);
}
real lb_ub_lp (real y, real lb, real ub) {
target += log(ub - lb) + log_inv_logit(y) + log1m_inv_logit(y);
return lb + (ub - lb) * inv_logit(y);
}
matrix corr_constrain_cvine_lp (vector col_one_raw, vector off_raw, real eta) {
int K = num_elements(col_one_raw) + 1;
vector[K - 1] z = lb_ub_lp(col_one_raw, -1, 1);
matrix[K, K] C = identity_matrix(K);
matrix[K, K] P;
C[1, 1] = 1;
C[2:K, 1] = z[1:K - 1];
C[1, 2:K] = C[2:K, 1]';
P = C;
int cnt = 1;
target += beta_lpdf(0.5 * (z + 1) | eta + 0.5 * (K - 1), eta + 0.5 * (K - 1));
jacobian += -0.5 * log1m(P[1, 2:K]^2);
for (i in 2:K - 1) {
for (j in i + 1:K) {
P[i, j] = lb_ub_lp(off_raw[cnt], lb, ub);
cnt += 1;
real tem = P[i, j];
jacobian += -0.5 * i * log1m(P[i, j]^2);
target += beta_lpdf(0.5 * (P[i, j] + 1) | eta + 0.5 * (K - 1), eta + 0.5 * (K - 1));
int m = i;
for (k in 1:i - 1) {
m += -1;
tem = P[m, i] * P[m, j] + tem * sqrt( (1 - P[m, i]^2) * (1 - P[m, j]^2) );
}
C[i, j] = tem;
C[j, i] = C[i, j];
}
}
return C;
}
The first thing to note is that I often nest _lp functions, here I have lb_ub_lp called within the corr_constrain_cvine_lp function. The next thing is that I'm traversing the lower triangular part of the matrix and I'm adding a beta prior to a transformed parameter created in this function. However, it is an intermediate parameter used to calculate the final correlation matrix, C.
If the deprecation goes through then I will have to have two functions, one for the jacobian that constructs C while also returning a tuple of matrices for both P and C. Then in the model block I'll have to loop through P to increment the log density by the beta_lpdf. I don't even need P and I definitely don't want to do the double loop again!
The current ability of having _lp works great. Let's keep it and, while we're at it, let's make the language a bit more flexible and add the ability for users to use the jacobian keyword in the model block.
The pr #979 added the
jacobian +=and_jacobianfunction keyword to indicate adding the change of variables correction for a transformed parameter. Thejacobianfunctionality can only be used in the transformed parameters block. That same pr also introduced a warning that_lptype functions will no longer be allowed in the transformed parameters block and will only be supported in the model block. I think the introduction of thejacobianfunctionality is useful but I believe restricting the_lpto only the model block is a step backwards for Stan.In merging #979, which users will first see in cmdstan 2.36, any user defined function ending with
_lpthat is used in the transformed parameters block will receive a warning that this functionality will not be allowed in future releases. The initial reasoning in the discussion for #979 is that allowing functions to access thetargetwas a bug in stanc2 that we continued to support in stanc3. The merged pr is indicating the "fix". However, there are times where it is useful to both add the jacobian correction and to add a log density. I don't believe this is widespread but in matrix parameters I encounter it. For example, below I show the c-vine parameterization of a correlation matrix. I use both thejacobianand thetargetkeywords here. I'm not sure this will compile because I believe it would need to end in_jacobian. I have been usingtargeteverywhere wherejacobiannow is which does compile in previous versions.The first thing to note is that I often nest
_lpfunctions, here I havelb_ub_lpcalled within thecorr_constrain_cvine_lpfunction. The next thing is that I'm traversing the lower triangular part of the matrix and I'm adding abetaprior to a transformed parameter created in this function. However, it is an intermediate parameter used to calculate the final correlation matrix,C.If the deprecation goes through then I will have to have two functions, one for the jacobian that constructs
Cwhile also returning atupleof matrices for bothPandC. Then in the model block I'll have to loop throughPto increment the log density by thebeta_lpdf. I don't even needPand I definitely don't want to do the double loop again!The current ability of having
_lpworks great. Let's keep it and, while we're at it, let's make the language a bit more flexible and add the ability for users to use thejacobiankeyword in the model block.