Ancestral Reconstruction of the Fundamental Niche
arfun estimates species’ environmental niches as bivariate normal ellipses in environmental space — from presence-only data, normalized against a user-supplied environmental background representing the accessible area M — and fits how those ellipses evolve along a phylogeny under Brownian motion (BM), Ornstein–Uhlenbeck (OU), or an independent-species null model. The bivariate ellipsoid is a model-based estimate of the fundamental niche conditional on the data and on M; it is not a direct measurement of physiological tolerance.
What it does
-
Presence-only niche estimation. The Jiménez & Soberón likelihood fits an environmental ellipse
(mu, sigma, rho)to occurrence points normalized against the accessible areaM. -
Niche evolution. Joint models let
mu,sigmaandrhoevolve along a phylogeny under BM or OU, so each species’ ellipse borrows strength from its relatives. -
Boundary diagnostics. A multi-start MAP scan reports which species sit on estimation boundaries (
sigma -> 0,|rho| -> 1,sigma -> Inf) before any MCMC is run — and supports masking poorly identified species so the phylogeny predicts their niche as a validation target. -
Warm starts via xnicher.
niche_warmstart()fits each species independently withxnicherand injects the result into the joint optimization. - Virtual species. Simulate niche evolution (BM / OU / null) inside a real accessible area, draw occurrences, and check recovery — the reverse-engineering loop used to validate the whole pipeline.
Installation
# hard dependencies (all on CRAN)
install.packages(c("ucminfcpp", "xnicher"))
# development version
remotes::install_github("alrobles/arfun")Stan models compile with cmdstanr for full Bayesian inference (requires a working CmdStan installation; install.packages("cmdstanr", repos = c("https://stan-dev.r-universe.dev", getOption("repos")))); the MAP path needs only ucminfcpp.
Quick start
library(arfun)
# per-species occurrence and shared-background environmental matrices
data <- prepare_phylo_niche_data(env_occ_list, env_m_list, tree)
# multi-start MAP on the exact joint log-posterior (C++ backend)
fit <- niche_multistart(data, n_starts = 32)
fit$boundary # per-species diagnostics
# full Bayesian fit of the BM evolving-sigma model
evo <- fit_evolution(model = "bm_evolving", niche_data = data)See vignette("virtual-species-bioregions") for an end-to-end simulate-and-recover benchmark inside a real One Earth bioregion.
The models
| model | niche evolution |
|---|---|
bm_evolving |
BM on centroid, tolerances and correlation |
ou_evolving |
OU toward an ancestral optimum on all parameters |
bm_constant, ou_constant
|
evolution on the centroid with a shared shape |
null |
independent species, no phylogenetic signal |
presence_only |
single-species J&S ellipse |
Formal verification (experimental)
The optional formal/ subproject checks selected mathematical statements in Lean 4.33.1 with a pinned mathlib revision. Its initial 26 lemmas/theorems cover bivariate covariance geometry, likelihood normalization, a conditional quadrature-error bound, and matrix/algebraic identities used in BM and OU. It does not change the R/Stan fitting pipeline or add an R installation dependency.
With Elan/Lake and Python 3.11 or newer, run from the repository root:
For subsequent checks, omit --bootstrap. The verifier builds the library, audits theorem axioms, replays the project modules with leanchecker, and checks that deliberately invalid proof controls are rejected.
See the beginner’s manual in Spanish and the theorem-to-equation registry. These are proofs of the stated real-number specifications, not a certification of the entire Stan executable, MCMC convergence, or ecological assumptions.