How is the sum_to_zero_vector implemented under the hood?

I would like to have a constrained parameter type that’s like ordered_sum_to_zero_vector (for paramters corresponding to mixture weights.)

My understanding is that a parameter of type sum_to_zero_vector[k] v only uses k-1 scalar parameters under the hood and then uses some sort of transformation to fill in the last degree of freedom. The “obvious” method would be to simply do something along the lines

v_K = -\sum_{k=1}^{K-1}v_k

but that feels wrong? Like, not sensitive? Like, if the vector is long, the last component will be in a different order magnitude than the rest… So I would guess the transformation is actually something else. What is it?

My idea is to then apply it to a regular ordered[k-1] vector to obtain what I want.

@spinkney might have some magic up his sleeve for this. The built in transform is quite involved, documented here: Constraint Transforms

You are correct that it is not the simple one you suggest (though that one was considered)

The easy way keeps the N total number of variables. It’s overparameterized but probably won’t be a problem.

data {
  int<lower=0> N;
}
parameters {
  ordered[N] x;
}
transformed parameters {
  vector[N] z = x - mean(x);
}
model {
  x ~ std_normal();
}

I’d have to think more about how to do this without the extra 1 parameter.

Ok try this

data {
  int<lower=0> N;
}
parameters {
  vector<lower=0>[N - 1] raw;
 // real<lower=0> scale; // optional, for flexibility
}
transformed parameters {
  vector[N] diff;
  diff[1] = 0;  // Anchor point
  diff[2:N] = cumulative_sum(raw);
 // vector[N] z = scale * (diff - mean(diff)); // if you want to scale
 vector[N] z = (diff - mean(diff));
}
model {
  raw ~ exponential(sqrt(N - 1) - 1);     // or any distribution with mass on the positive reals
 // scale ~ normal(0, 1);  // or any appropriate prior

}
generated quantities {
  real z_sum = sum(z);
}

setting N = 10 results in

   variable   mean median    sd   mad      q5     q95  rhat ess_bulk ess_tail
   <chr>     <dbl>  <dbl> <dbl> <dbl>   <dbl>   <dbl> <dbl>    <dbl>    <dbl>
 1 z[1]     -2.23  -2.13  0.830 0.805 -3.74   -1.06   1.00     9589.    6458.
 2 z[2]     -1.74  -1.66  0.695 0.689 -2.99   -0.774  1.00     9136.    6455.
 3 z[3]     -1.24  -1.16  0.596 0.568 -2.34   -0.426  1.000    8817.    6267.
 4 z[4]     -0.754 -0.692 0.516 0.473 -1.69   -0.0278 1.000    8956.    6929.
 5 z[5]     -0.253 -0.228 0.450 0.406 -1.03    0.430  1.00     9963.    7553.
 6 z[6]      0.249  0.225 0.452 0.405 -0.445   1.02   1.000    9626.    7165.
 7 z[7]      0.736  0.675 0.504 0.471  0.0286  1.65   1.00    10229.    5943.
 8 z[8]      1.24   1.16  0.600 0.561  0.430   2.34   1.000    9507.    6623.
 9 z[9]      1.75   1.65  0.720 0.690  0.761   3.08   1.00     8376.    5692.
10 z[10]     2.24   2.14  0.852 0.826  1.06    3.80   1.00     7868.    5606.
4 Likes