Open
Description
Add inverse ILR simplex.
@WardBrian we can do this in 2 loops using the online softmax https://arxiv.org/abs/1805.02867. The first loop constructs the sum to zero, get the max value of that sum to zero vec, and returns the sum of exponentials with the max subtracted. The second loop does the safe exponential of the sum to zero vector with the max subtracted and divides by the sum of exponentials output from the first loop. The jacobian is output after.
inline plain_type_t<Vec> simplex_ilr_constrain(const Vec& y, Lp& lp) {
const auto N = y.size();
plain_type_t<Vec> z = Eigen::VectorXd::Zero(N + 1);
if (unlikely(N == 0)) {
return z;
}
auto&& y_ref = to_ref(y);
value_type_t<Vec> sum_w(0);
// new
double d = 0; // sum of exponentials
double max_val = 0;
double max_val_old = 0;
for (int i = N; i > 0; --i) {
double n = static_cast<double>(i);
auto w = y_ref(i - 1) * inv_sqrt(n * (n + 1));
sum_w += w;
z.coeffRef(i - 1) += sum_w;
z.coeffRef(i) -= w * n;
// new
max_val = max(max_val_old, z.coeff(i));
d = d * exp(max_val_old - max_val) + exp(z.coeff(i) - max_val);
max_val_old = max_val;
}
// new loop
for (int i = 0; i < N; ++i) {
z.coeffRef(i) = exp(z.coeff(i) - max_val) / d;
}
lp += -N * log(d) + 0.5 * log(N);
return z;
}
Metadata
Metadata
Assignees
Labels
No labels