Provides density, distribution, quantile, and random generation
functions for the Modified Half-Normal (MHN) distribution, along with
moments and mode; the Fox-Wright Psi normalizing constant is evaluated
internally. The MHN distribution arises as a conditional posterior in
Bayesian Markov chain Monte Carlo and generalizes the half-normal,
truncated normal, and square-root gamma distributions. Implements
efficient sampling via the Sun, Kong & Pal (2023)
An R package providing density, distribution, quantile, and random generation functions for the Modified Half-Normal (MHN) distribution, together with closed-form / recurrence-based helpers for its moments and mode.
The MHN($\alpha$, $\beta$, $\gamma$) distribution has support on $(0, \infty)$ and density
$$f(x \mid \alpha, \beta, \gamma) ;\propto; x^{\alpha - 1} \exp(-\beta x^2 + \gamma x), \qquad x > 0,$$
where $\alpha, \beta > 0$ and $\gamma \in \mathbb{R}$. It arises as a conditional posterior in Bayesian MCMC for several common models (skew-elliptical regression, $t$-shrinkage priors, log-concave likelihoods with a quadratic Bayesian penalty) and generalises a number of familiar one-sided distributions:
| Constraint | Reduction |
|---|---|
| $\gamma = 0$ | $\sqrt{\mathrm{Gamma}}$: $X^2 \sim \mathrm{Gamma}(\alpha/2, \beta)$ |
| $\alpha = 1$ | Truncated normal on $(0, \infty)$ with location $\gamma / (2\beta)$ and scale $1/\sqrt{2\beta}$ |
| $\alpha = 1,; \gamma = 0$ | Half-normal with scale $1/\sqrt{2\beta}$ |
| $\beta \to 0^+,; \gamma < 0$ | $\mathrm{Gamma}(\alpha, -\gamma)$ (limit) |
The package implements the efficient samplers of Sun, Kong & Pal (2023) (Algorithms 1 / 3) and the Gao & Wang (2025) Relaxed Transformed Density Rejection (RTDR) method with a uniform 1/e acceptance bound, and dispatches between them automatically.
install.packages("mhn")
The development version is on GitHub:
# install.packages("remotes")
remotes::install_github("t-momozaki/mhn")
library(mhn)
# Density, CDF, quantile, random generation
dmhn(c(0.5, 1, 2), alpha = 2, beta = 1, gamma = 1)
pmhn(1.5, alpha = 2, beta = 1, gamma = 1)
qmhn(0.95, alpha = 2, beta = 1, gamma = 1)
rmhn(10, alpha = 2, beta = 1, gamma = 1)
# Summary statistics
mhn_mean(2, 1, 1); mhn_var(2, 1, 1); mhn_mode(2, 1, 1)
| Function | Description |
|---|---|
dmhn() |
Density (vectorised over x and parameters; supports log = TRUE) |
pmhn() |
Cumulative distribution function (lower.tail and log.p à la pgamma) |
qmhn() |
Quantile function via TOMS 748 root-finder |
rmhn() |
Random generation; method dispatch via method = c("auto", "rtdr", "sun") |
dmhn(1.5, alpha = 2, beta = 1, gamma = 1, log = TRUE)
pmhn(1.5, alpha = 2, beta = 1, gamma = 1, lower.tail = FALSE)
qmhn(log(0.05), alpha = 2, beta = 1, gamma = 1, log.p = TRUE)
rmhn(5, alpha = c(1, 2, 3), beta = 1, gamma = c(0, 1, -1)) # recycled
| Function | Description |
|---|---|
mhn_mean() |
$E(X) = \Psi[(\alpha+1)/2,, z] ,/, (\sqrt{\beta}, \Psi[\alpha/2,, z])$, with $z = \gamma/\sqrt{\beta}$ |
mhn_var() |
Variance, Sun et al. (2023, Lemma 2c) where that form is well conditioned |
mhn_skewness() |
Skewness $\gamma_1$ |
mhn_kurtosis() |
Excess kurtosis $\gamma_2$ |
mhn_mode() |
Mode (returns NA when no interior mode exists) |
mhn_mean(2, 1, 1) # 1.1337...
mhn_skewness(2, 1, 1) # positive (density right-skewed)
mhn_mode(0.5, 1, -1) # NA: monotone-decreasing density
rmhn(method = "auto")The default method routes each parameter triple to the cheapest sampler
that is provably correct in that region. The decision rules are
benchmarked in inst/benchmarks/auto_dispatch.R:
Closed-form shortcuts:
α = 1, γ = 0 -> half-normal via |rnorm|
γ = 0 -> sqrt(rgamma(...))
α = 1 -> truncated normal
Region α < 1, γ > 0:
Gao & Wang (2025) RTDR (Sun et al. (2023) Algorithm 2 is
intentionally not implemented; RTDR is
uniformly faster here)
Region γ > 0, α > 1:
Sun et al. (2023, Algorithm 1) (Normal or sqrt-Gamma proposal,
closed-form optimal parameters)
Region γ ≤ 0:
n-dependent (the crossover is benchmarked, not theoretical; see
vignette("theory") for the cost-decomposition derivation):
α ≥ 10 -> Sun Algorithm 3 (lower per-proposal
cost than RTDR once the mode sharpens)
samples per setup ≥ N*, α < 10 -> RTDR (lighter per-proposal cost)
samples per setup < N* -> Sun Algorithm 3 (lighter setup cost)
where N* = 25, raised to 100 for α < 0.1: the crossover moves to larger
batches as the shape shrinks.
Choosing a specific sampler:
rmhn(1000, 2, 1, 1, method = "rtdr") # RTDR for the general case
rmhn(1000, 2, 1, 1, method = "sun") # Sun for the general case
# (errors for α < 1, γ > 0)
method selects the sampler used for the general case. The closed-form
special cases are taken first whatever it is set to: a negligible tilt draws
from the square root of a Gamma, and α ≈ 1 from a truncated normal. Both are
exact and cheaper than any rejection scheme.
Full documentation, with a searchable function reference and rendered vignettes, is published at https://t-momozaki.github.io/mhn/.
vignette("introduction", package = "mhn") — a 5-minute tour of
every exported function with worked examples.?dmhn, ?pmhn, ?qmhn, ?rmhn — full argument documentation
including the recycling rules and the method argument.citation("mhn") — package + underlying papers.If you use this package in academic work, please cite both the package
and the methodology papers (citation("mhn") prints all four):
rmhn.)MIT © 2026 Tomotaka Momozaki. See LICENSE.