How to specify variable parameter constraints based on other model parameters

I’m trying to set unique parameter constraints based on other model parameters.

Consider a case of log-linear cognitive diagnosis model, where a series of dichotomous items measure multiple categorical latent traits. For this example, suppose there are 5 items measuring 2 attributes:

      [1,]  [2,]
[,1]     0     1
[,2]     1     0
[,3]     1     1
[,4]     1     1
[,5]     1     0

Using the LCDM parameterization there should be a main effect for attribute 1 for items 2-5, a main effect for attribute 2 for items 1, 3, and 4, and an interaction between attributes 1 and 2 for items 3 and 4, for 9 total parameters. Further, there are constraints on the parameters. For the main effects this is easy, as all main effects are constrained to be greater than 0. However, interactions are constrained based on the values of the main effects. For example, the interaction for item 3 greater than or equal to the small main effect for item three.

Currently my parameters block looks like this:

parameters {
  real<lower=0> maineffect_2_1;
  real<lower=0> maineffect_3_1;
  real<lower=0> maineffect_4_1;
  real<lower=0> maineffect_5_1;
  real<lower=0> maineffect_1_2;
  real<lower=0> maineffect_3_2;
  real<lower=0> maineffect_4_2;
  real<lower=-min(maineffect_3_1, maineffect_3_2)> interaction_3_12;
  real<lower=-min(maineffect_4_1, maineffect_4_2)> interaction_4_12;

You can see how with more than 5 items, or more than 2 attributes, this becomes a very tedious and unwieldy process. Ultimately, I would like to be able to do something like:

parameters {
  real<lower=0> main_effect1[5];
  real<lower=0> main_effect2[5];
  real<lower=-min(main_effect1, main_effect2)> interaction[5];

And then zero out the unused parameters in the transformed parameters block. However, this syntax fails, because the min() function can’t accept two vectors and return a vector that would then be used to apply a unique constraint to each element of the interaction vector.

Is there a way to implement these type of constraints in Stan without specifying each parameter individually as in the first block of Stan code? Thanks in advance for your help!

1 Like

Agreed. Might be easiest to do this manually with a for loop, transformed parameters, and manual Jacobian adjustment.

Something like (from pages 404-405 of the 2.17.0 manual):

parameters {
  real<lower=0> main_effect1[5];
  real<lower=0> main_effect2[5];
  real interaction_unconstrained[5];

// Transform from unconstrained to constrained space
transformed parameters {
  real interaction[5];
  for(i in 1:5) {
    interaction[i] = exp(interaction_unconstrained[i]) - min(main_effect1[i], main_effect2[i]);

model {
  // Add in Jacobian adjustment
  for(i in 1:5) {
    target += interaction_unconstrained[i];

This is perfect! Thanks!