% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/numerical_guards.R
\name{mlumr-numerical-guards}
\alias{mlumr-numerical-guards}
\alias{safe_logit}
\alias{safe_divide}
\title{Numerical guards in the Stan models}
\description{
\code{mlumr}'s Stan models clip a few quantities to avoid undefined arithmetic
in \verb{generated quantities}. This page documents the exact behavior so
users can assess when the guard matters for their analysis.
}
\section{Guards currently in place}{


\describe{
\item{\code{safe_logit(p)} (binomial models)}{Returns
\code{logit(clamp(p, 1e-10, 1 - 1e-10))}. The logit and log-odds-ratio
posterior summaries use this rather than the raw \code{logit(p)} so that
finite samples with \code{p} at the boundaries do not propagate
\code{Inf}/\code{NaN} into the posterior.}
\item{\code{safe_divide(num, denom)} (binomial and Poisson models)}{Returns
\code{num / max(denom, 1e-10)}. Used for risk ratios and rate ratios to
avoid division-by-zero when a comparator posterior draw has a
near-zero mean outcome.}
\item{Stan \verb{<lower=0>} constraints on \code{sigma} (normal family)}{Truncate
the prior to the positive half-line — the reason why
\code{prior_sigma = prior_normal(0, 2.5)} is interpreted as a
half-normal and why \code{\link[=prior_exponential]{prior_exponential()}} is also valid.}
}
}

\section{When the guards introduce bias}{


The guards are one-sided: they replace invalid values with extreme but
finite ones rather than with a symmetric distribution. In practice:

\itemize{
\item For binomial outcomes with event rates in the range
\verb{[1e-4, 1 - 1e-4]} the clipped output is indistinguishable from the
unclipped value at double precision.
\item For event rates outside that range — or Poisson models with
expected rates below \code{1e-4} events per unit exposure — the summary
of the posterior for LOR, RR, and related ratios may be biased
toward the clip boundary. The point estimate for the treatment
effect on the link scale (\code{delta_index} on log-odds, log-rate, or
mean-difference scale) is \emph{not} affected since it does not
go through the guards.
\item \strong{Direction of \code{safe_divide} bias.} When the comparator rate
(the denominator) is smaller than \code{1e-10}, the ratio is clipped
to \code{num / 1e-10}. Because rates and probabilities in mlumr are
non-negative, the clipped value is always \emph{larger} (more
positive) than the mathematical limit — so risk ratios and rate
ratios in near-zero-comparator regimes are \emph{upward-biased},
never downward. Expect the clipped posterior summary to
overstate, not understate, the relative treatment effect in
those draws.
\item For very-rare-event data, consider reframing the model in terms
of rates: an event count with exposure via \code{\link[=set_agd]{set_agd()}} \code{family = "poisson"} is numerically better behaved than Bernoulli /
Binomial at extreme probabilities.
}
}

\section{How to diagnose guard activation}{


Posterior draws of \verb{p_*_index} / \verb{p_*_comparator} or \verb{rate_*_*} are
returned by the Stan models and are available in \code{fit$draws}. If any
posterior draw sits below \code{5e-10} or above \code{1 - 5e-10} for binomial
probabilities (respectively below \code{5e-10} for Poisson rates), the
guards are active for that draw. A quick check:
\preformatted{
  any(fit$draws[, "p_comparator_comparator"] < 5e-10)
}
}

\keyword{internal}
