Changelog
Source:NEWS.md
xpam 1.0.0
First CRAN release. xpam consolidates the GitHub-only 0.1.0–0.3.0 line into a single, reviewed submission: the small-input dense path (get_geo_pam()) plus the streaming native engine, the sparse incidence surface and the native Jaccard backend described under 0.3.0 below.
Submission preparation
- Documentation and vignettes are published on the package website (https://alrobles.github.io/xpam/) rather than shipped in the CRAN tarball;
vignettes/andinst/doc/are excluded from the build (.Rbuildignore), and theVignetteBuilderfield was dropped so the source package carries no prebuilt vignette index.README.mdandNEWS.mdare now shipped in the tarball. - Examples that touch remote data (
get_rodentia_mexico(),get_world_pca(), and the downloaded example inget_geo_pam()) are guarded: the functions document and honour a"Can't access data."character return when the data server is unreachable, and the examples test for it, soR CMD check --run-donttestpasses offline. Theget_geo_pam()example additionally runs a fully localSpatVectorexample that needs no download at all. - GDAL remains optional:
configuredetects it and the native raster path links only when it is present; without GDAL the package installs, loads and the terra-based fallback works. Engine tests are skipped when GDAL is absent. - Network-dependent tests are gated with
skip_on_cran()+skip_if_offline().
Engine and API (carried from 0.3.0)
-
pam_env_engine()streaming environmental PAM;pam_incidence()sparse incidence (Matrix::dgCMatrixori/jtriplets);pam_jaccard()species- or site-wise Jaccard with an optional exact thresholded edge list;pam_env()dense small-input environmental path;has_gdal()build-time capability report. - Occurrence sources: in-memory pairs, the
XPOCbinary pair file (xpam_write_occ_bin()), and GDAL/OGR vector sources – single paths, vectors of paths, directories (k-way merged and deduplicated) or in-memoryterra::SpatVectors. - OpenMP regions honour
OMP_THREAD_LIMIT.
xpam 0.3.0
The engine release: xpam is now a standalone high-performance PAM package — streamed incidence construction, a sparse PAM surface, and a native Jaccard backend, on top of the original get_geo_pam() API.
Streaming engine core
- New
pam_env_engine(): builds the environmental PAM straight from raster files. APamEngineC++ object (opaque XPtr) owns GDAL I/O and all computation; R passes only paths, the (species, cell) table and scalars. Full-width strips are read into a pixel-major buffer, each cell is binned byGridBinning, and pairs – pre-sorted by cell – merge-join the strips in a single pass intoPamBitset. Memory is O(bitset + strip);max_bitset_mbtriggers the sort fallback as inpam_env(). Requires GDAL at build time (has_gdal()reports it);configuredegrades gracefully without it. Raster cells are terra cellnumbers (1-based). -
PamBitsetrows are word-aligned (<= 63 pad bits per species), so pairwise kernels dopopcount(A & B)/popcount(A | B)per row pair via therow()accessor. - Parallel regions honour
OMP_THREAD_LIMIT(viapam::safe_threads()); CRAN check machines set it to 2 andomp_get_max_threads()alone does not respect it.
Occurrence sources
-
occ: data frame of (cell, species) — SEXP-anchored, sorted once (MemOccSource). -
occ_file: cell-sorted “XPOC” binary pair file streamed in ~48 MiB chunks (FileOccSource);xpam_write_occ_bin()writes it. At 4e6 cells x 500 species the streamed path cuts RSS from ~3.1 GB to ~0.6 GB. -
occ_polygons: GDAL/OGR vector sources rasterised in bounded tiles byPolygonOccSource(GDALRasterizeGeometriesinto a per-feature MEM window) — no dense raster, no materialised pair table. Accepts:- a path (shapefile, GeoPackage, GeoJSON, … or an OGR connection string such as
duckdb:///db.duckdbwhen the GDAL build has the driver), - a character vector of paths, or a directory scanned for vector files — the per-dataset cell-sorted streams are k-way merged and deduplicated (
MergeOccSource);speciesis then required, - an in-memory
terra::SpatVector(bridged through a temporary GeoPackage).poly_layertakes one name per dataset or a single name applied to all;all_touchedselects the burn rule;occ_dumptees the stream the engine consumes — merged and deduplicated — into a reusable XPOC file (DumpOccSource).
- a path (shapefile, GeoPackage, GeoJSON, … or an OGR connection string such as
- Polygon SRS is reprojected to the env raster CRS when they differ; features with missing/unmatched fields or unusable geometries are counted and reported via
n_skipped(+ warning).
Sparse incidence surface
- New
pam_incidence(): the PAM itself as an R object. Streams any occurrence source through the engine and returns theunits x speciesincidence as aMatrix::dgCMatrix(format = "dgCMatrix", Matrix in Suggests) or a rawdata.frame(i, j)triplet table.space = "geo"is the streaming geographic PAM (raster cells as units, env files as grid template only — the scalable replacement forget_geo_pam());space = "env"gives the environmental incidence over the same bins aspam_env_engine(). Explicit scale gates: incidence export needs the bitmap or sort accumulator (the geo co-occurrence path retains no pairs), andnnz * 16B must fitmax_out_mbto marshal to R — beyond that the on-disk XPOC fromocc_dumpis the sparse PAM.
Native Jaccard backend
-
pam_jaccard(): pairwise Jaccard similarity between species straight from any occurrence source — no dense PAM, no RcppParallel.space = "geo"uses raster cells as incidence units (env_filessupplies only the grid template);space = "env"uses env bins. Accumulator: the shared bitset whenn_species * n_units/8fitsmax_bitset_mb; in geo space beyond the budget an O(n_species^2) co-occurrence matrix is accumulated from per-cell species runs of the cell-sorted pair stream (kernel = "cooc", counts returned ascooc). Semantics portfastJaccard::jaccard_fast: J = |A&B| / |A|B|, independence expectationpa*pb/(pa+pb-pa*pb)on empty unions,centered = TRUEsubtracts the expectation. -
pam_jaccard(threshold = tau)returns the similarity graph instead of the matrix: an exact prefix-filtered join (AllPairs-style — rare-first prefix indexing, size and count bounds, exact merge-join verification) emits theedgesdata.frame(i, j, J >= tau)with output-sensitive work. Same results as filtering the dense matrix; works for bothbymodes and all accumulators. On a 2,000-species x 20k-cell fixture it is ~80-280x faster than fastJaccard’s dense RcppParallel path and needs no 305 MB input matrix (benchmarks/docs/bench_jaccard.md). -
pam_jaccard(by = "site")transposes the question: ann_units x n_unitsmatrix of similarities between cells or env bins over the species they share. Requires the transposed bitset withinmax_bitset_mband the densen_units^2return withinmax_out_mb(default 4096 MB, ~22.6k units).
Package changes
- Package renamed
pam->xpam: the namepamis already taken on CRAN. Headers live insrc/*.h(not.hpp) becauseR CMD checkflags unlikely file names insrc/as a WARNING. - Internal refactor: the kernel’s heavy state moved to pure-C++ headers (
pam_bitset.h,pam_binning.h,pam_accumulate.h,pam_threads.h) with no Rcpp dependency;SystemRequirementsraised to C++17. - New
c_bin_assign_d(): D-dimensional grid binning over a matrix. -
pam_env()gains amax_bitset_mbmemory budget and reports the kernel used; accumulation fills a single shared bitset with lock-free atomic ORs; out-of-range (species, bin) codes are counted and warned. -
xpam_sim_env()/xpam_sim_ranges()/xpam_truth()/xpam_niche_bound(): internal deterministic generators and a transparent R-only oracle used to validate the engine (test-pam_sim.R). -
configurehardened:LIBSis cleared before probing and the GDAL link test uses onlygdal-config --libs, so ambient environment libraries (e.g. a user~/.R/Makevarsexporting-lRcppParallelintoR CMD INSTALL’s environment) can no longer silently disable GDAL.AC_PROG_CXXis also resolved before the link test instead of lazily inside it. - Fixed
url_exists()returningTRUEfor unresolvable hosts. - Benchmarks:
benchmarks/docs/bench_engine.md(incl. the 1/120-degree global sweep: 22.5e9 pairs streamed, ~15-24 GB RSS) andbenchmarks/docs/bench_jaccard.md.
xpam 0.2.0
- DESCRIPTION overhauled:
Authors@Rformat, CRAN-quality title and description,BugReportsURL,Suggestsfor testthat/knitr/rmarkdown. - Replaced
httr/stringr/magrittrdependencies with base R equivalents; addedcheckmatefor input validation. - Switched from magrittr pipe (
%>%) to base R pipe (|>). Minimum R version raised to 4.1.0. - Added
checkmate::assert_*guards inget_geo_pam()andurl_exists(). - Roxygen documentation rewritten for all exported and internal functions.
- Added testthat test suite (
tests/testthat/). - Added introductory vignette (
vignettes/pam-intro.Rmd). - Added
NEWS.md. - Added R CMD check CI workflow (ubuntu, macOS, windows).
- Fixed
get_rodentia_mexico()docstring (was incorrectly labelled “afrosoricida”).
xpam 0.1.0
- Initial release with
get_geo_pam(),get_rodentia_mexico(), andget_world_pca().