Changes in version 1.0.3 Performance Simulated annealing - O(base::ceiling(base::log(stop.temp / start.temp) / base::log(cool.fact)) · n) time, O(n^2) space → O(base::ceiling(base::log(stop.temp / start.temp) / base::log(cool.fact)) · k) time, O(n^2) space. Swap evaluation now computes delta updates via unchanged indices (unch.idx), replacing the maintained link vector and matching the brute force update pattern. Changes in version 1.0.2 (2026-04-14) Arguments and value Renamed arguments - adj.mat → n.mat. The first argument of interest is n.mat, not necessarily a symmetric adjacency matrix of numeric, but a symmetric matrix of numeric corresponding to the symmetric matrix of associations (e.g., of zero-order polychoric correlation coefficients) computed from the set of items comprised in the original version of the said psychometric instrument. - method → algorithm. The third argument of interest is algorithm (rather than method), a character matching either “brute.force” or “simulated.annealing” corresponding to the combinatorial search algorithm. Removed arguments - absolute now always TRUE. - max.iter now always base::ceiling(base::log(stop.temp / start.temp) / base::log(cool.fact)). Renamed value - optimal.S → solution.character. - optimal.function.S → solution.numeric. Robustness and correctness - base::set.seed() no longer permanently alters the global RNG state. .Random.seed is now saved and restored via base::on.exit(). - Progress bars are now closed via base::on.exit(), ensuring cleanup even on early exit or error. - The diagonal of the input matrix is now explicitly set to zero before computation, preventing self-associations from inflating the objective. - NA/NaN values in the input matrix now trigger a warning with a count of affected entries before being replaced with zeros. - Input validation now checks for Inf values, non-numeric entries, non-square matrices, and matrices smaller than 2 × 2. - Scalar parameter validation now checks length, type, and NA status consistently across all parameters. - algorithm now uses base::match.arg() instead of manual %in% checking, supporting partial matching. - SA-specific parameters (start.temp, cool.fact, stop.temp, n.runs, seed) are now validated only when algorithm = "simulated.annealing". - Error messages now use call. = FALSE for cleaner console output. - k = 0 and k = n are now rejected during validation rather than handled as special cases inside the algorithm. - seed now explicitly accepts NULL to skip setting the RNG state. Performance Brute force - Subsets are now enumerated incrementally with delta updates to the objective function, replacing the previous approach of generating all candidate subsets in memory via utils::combn(). This reduces memory from O(C(n,k) × k) to O(n) and avoids recomputing the full objective at each step. - When k > n / 2, enumeration is performed over the smaller complement, reducing the number of combinations to evaluate. - The absolute value matrix is now precomputed once, rather than recomputed inside the objective function at every evaluation. - Brute force now detects intractable problems (C(n,k) exceeding .Machine$integer.max) and exits with a recommendation to use simulated annealing, rather than attempting to allocate the full combination matrix. Simulated annealing - Swap evaluation now runs in O(n) via a maintained link vector, replacing the previous full matrix subsetting at each step. - The complement set is now maintained incrementally via a logical membership vector, replacing repeated base::setdiff() calls. - Removed the hash environment that stored all visited subsets as character keys, eliminating unbounded memory growth over long runs. Changes in version 1.0.1 (2025-04-15) - Initial CRAN release.