Skip to content
Open
6 changes: 3 additions & 3 deletions stan/math/opencl/rev/constraint/lub_constrain.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ inline var_value<matrix_cl<double>> lub_constrain(T_x&& x, T_lb&& lb,
auto lb_inf = value_of(lb_arena) == NEGATIVE_INFTY;
auto ub_inf = value_of(ub_arena) == INFTY;
auto inv_logit_x = inv_logit(value_of(x_arena));
auto one_m_inv_logit_x = 1.0 - inv_logit_x;
auto exp_x = exp(value_of(x_arena));
auto one_m_inv_logit_x = elt_divide(1.0, 1.0 + exp_x);
auto res_adj_exp_x = elt_multiply(res.adj(), exp_x);
adjoint_results(x_arena, lb_arena, ub_arena) += expressions(
select(lb_inf, select(ub_inf, res.adj(), -res_adj_exp_x),
Expand Down Expand Up @@ -112,10 +112,10 @@ inline var_value<matrix_cl<double>> lub_constrain(T_x&& x, T_lb&& lb, T_ub&& ub,
auto lb_inf = value_of(lb_arena) == NEGATIVE_INFTY;
auto ub_inf = value_of(ub_arena) == INFTY;
auto inv_logit_x = inv_logit(value_of(x_arena));
auto one_m_inv_logit_x = 1.0 - inv_logit_x;
auto exp_x = exp(value_of(x_arena));
auto one_m_inv_logit_x = elt_divide(1.0, 1.0 + exp_x);
auto diff = value_of(ub_arena) - value_of(lb_arena);
auto one_over_diff = elt_divide(1.0, diff);
auto exp_x = exp(value_of(x_arena));
auto res_adj_exp_x = elt_multiply(res.adj(), exp_x);
adjoint_results(x_arena, lb_arena, ub_arena) += expressions(
select(lb_inf, select(ub_inf, res.adj(), lp.adj() - res_adj_exp_x),
Expand Down
31 changes: 28 additions & 3 deletions stan/math/prim/constraint/lub_constrain.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <stan/math/prim/fun/multiply.hpp>
#include <stan/math/prim/fun/subtract.hpp>
#include <stan/math/prim/fun/sum.hpp>
#include <stan/math/prim/fun/value_of_rec.hpp>
#include <cmath>

namespace stan {
Expand Down Expand Up @@ -55,7 +56,17 @@ inline auto lub_constrain(T&& x, L&& lb, U&& ub) {
return ub_constrain(identity_constrain(x, lb), ub);
} else {
check_less("lub_constrain", "lb", value_of(lb), value_of(ub));
return (ub - lb) * inv_logit(x) + lb;
const auto diff = ub - lb;
if constexpr (is_autodiff_v<return_type_t<T, L, U>>) {
// inv_logit of a non-positive argument only: the derivatives of
// 1 - inv_logit(x) cancel for x >> 0
if (value_of_rec(x) >= 0) {
return ub - diff * inv_logit(-x);
}
return lb + diff * inv_logit(x);
} else {
return diff * inv_logit(x) + lb;
}
}
}

Expand Down Expand Up @@ -108,8 +119,22 @@ inline auto lub_constrain(T&& x, L&& lb, U&& ub, Lp& lp) {
} else {
check_less("lub_constrain", "lb", value_of(lb), value_of(ub));
const auto diff = ub - lb;
lp += add(log(diff), subtract(-abs(x), multiply(2.0, log1p_exp(-abs(x)))));
return diff * inv_logit(x) + lb;
// a branch instead of abs(x), whose forward-mode derivative is 0 at 0
const bool x_nonneg = value_of_rec(x) >= 0;
if (x_nonneg) {
lp += add(log(diff), subtract(-x, multiply(2.0, log1p_exp(-x))));
} else {
lp += add(log(diff), subtract(x, multiply(2.0, log1p_exp(x))));
}
if constexpr (is_autodiff_v<return_type_t<T, L, U>>) {
// inv_logit of a non-positive argument only, as above
if (x_nonneg) {
return ub - diff * inv_logit(-x);
}
return lb + diff * inv_logit(x);
} else {
return diff * inv_logit(x) + lb;
}
}
}

Expand Down
Loading
Loading