nullcat (development version)
New
row_groupsandcol_groupsarguments randomize within groups of rows and/or columns. The matrix is split into blocks (every combination of a row group and a column group) and each block is randomized independently, so values never leave their block. For fixed-margin algorithms this gives a constrained null model, e.g. one in which each region keeps its own species pool. Supported by every algorithm,nullcat(),quantize(),curvecat(),swapcat(),tswapcat(), the batch functions,trace_cat(),suggest_n_iter(), and thevegancommsim functions. Inquantize(), strata are defined once for the whole matrix and quantitative values are reassigned within each block. When groups are used,n_iteris applied to every block, andtrace_cat()/suggest_n_iter()trace the grouped randomization as a whole, suggesting the number of iterations per block.nullcat_batch()andquantize_batch()also accept a matrix of groups with one column per replicate, using columnrfor replicater.New function
tile_groups()generates random tilings of sites, one per column, for spatially constrained null models: passed to the batch functions, each replicate is randomized within the tiles of a different, randomly placed and oriented tiling, so sites are pooled with their neighbors. Planar coordinates use a regular hexagonal grid. With longitude/latitude coordinates, tiles are the Voronoi cells of a randomly rotated Fibonacci lattice on the sphere: equal in area to hexagons of the givenspacing(in meters), but varying in shape between irregular hexagons and near-squares. Either way, two sites share a tile in about half of the tilings at a distance of0.42 * spacing.New function
group_sizes()returns the average size of each row’s group across a grouping vector or matrix, to check pool sizes before randomizing (e.g. while choosing a tilespacing).wt_rowandwt_colare deprecated. Weighting which pairs of rows or columns exchange values does not change the null distribution thatcurvecatandswapcatconverge to, only how quickly they mix: with weights that connect all rows (e.g. distance-decay kernels), results converge to the unconstrained null asn_itergrows. The only lasting effect of a weight matrix is to separate rows that are not connected by any chain of nonzero weights, so weight matrices are now converted torow_groups/col_groups(the connected components of their nonzero entries) with a warning; if the weights connect everything they have no effect, and if they have no off-diagonal entries an error is raised. This also fixes a bug: underquantize(fixed = "cell"), row weights were ignored on half the iterations, so values could move between supposedly separated groups.quantize_prep()(and soquantize()and its relatives) now warns whenfixed = "cell"and some rows or columns have all their values in a single stratum. Such rows and columns can never change under cell mode, because cells only move by trading places with cells of a different stratum. Usingzero_stratum = TRUEor atransformusually separates low values into their own strata.Bug fix: with a single row or column, or
n_iter = 0, the sequential algorithms (curvecat,swapcat,tswapcat) returned the input categories even whenoutput = "index"was requested, soquantize(fixed = "cell")scrambled values for such matrices. They now return the identity index.Documentation corrections:
curvecatandswapcatconverge to the same (uniform) null distribution, buttswapcatdoes not; its redraw-until-valid design biases sampling toward matrices with many available swaps (Miklós & Podani 2004).
nullcat 0.2.0
CRAN release: 2026-04-06
- New feature: weighted pair sampling via
wt_rowandwt_colparameters. Enables spatially, phylogenetically, or trait-constrained null models by weighting which pairs of rows or columns exchange tokens during randomization. Supported for all sequential algorithms (curvecat, swapcat, tswapcat) and flows through to quantize(), batch functions, trace diagnostics, and vegan integration.
