geneexpr dataset: 100 genes, 20 conditions, a
GO semantic similarity matrix and ground-truth biological process
labels. Generated by data-raw/generate_geneexpr.R with a fixed
seed. Use data(geneexpr) to load.vignette("moc-gapbk-intro") has been
extended to cover the geneexpr dataset, side-by-side Pareto-front
plots with ggplot2 + patchwork, and ground-truth validation via
the Adjusted Rand Index.geneexpr dataset.ggplot2, patchwork, and usethis have been added to Suggests
to support the new graphics and the data-raw build script.codecov.yml, the test-coverage.yaml GitHub Actions workflow,
and the Codecov badge from the README. Tests still run on every
push through the R-CMD-check.yaml workflow.This release rewrites the Pareto Local Search (PLS) and Path-Relinking (PR) modules. The acceptance rules are now expressed as batched, vectorised operations rather than per-candidate sequential decisions.
Equivalence note. Numerical results are no longer bit-identical to
0.2.x under the same set.seed(). The new acceptance rule is the
textbook PLS rule (Dubois-Lacoste et al., 2015): the whole neighborhood
of the current incumbent is evaluated jointly and a single
non-dominated sort decides which solutions survive. Pareto-front
quality is preserved on the internal benchmark.
for (i in seq_len(num_neighborhood)) loop, which used to
generate and evaluate one neighbor at a time, has been replaced by a
batched construction: all candidate neighbors are built in one matrix
allocation, all their Xie-Beni objectives are computed in a single
vectorised pass and a single fastNonDominatedSorting() decides
which ones survive.merge() to locate the perturbed solution in the dominance table has
been removed. The replacement uses rowSums(A != B) == 0L on integer
matrices.explored flag is now tracked on a logical vector parallel to
the archive matrix, eliminating the repeated
as.data.frame()/subset()/cbind() round-trips in the original
while-loop body.generate.groups() and calculate.ranking.crowding() are no longer
called from inside the neighborhood loop. They are called only at
the end, on the final archive, to reshape the return value.10 * pop_size + 50) to
avoid pathological oscillations when the archive churns.parallel::makeCluster() is now reused
across all PR pairs in one generation, with the squared distance
matrices exported once.s_initial and s_guide are computed
with setdiff() on integer vectors instead of data.frames.calculate.ranking.crowding() call inside the while-loop
has been replaced by .pr_pick_best(), which evaluates both
Xie-Beni objectives on the batch of intermediate solutions in one
vectorised pass and picks a rank-1 representative. The previous code
ran calculate.ranking.crowding() (two ranking passes, one crowding
distance, several data.frame coercions) for every step of the path.rbind() calls on a growing data frame.calculate.objective.functions(): the inner sum and the
medoid-to-medoid minimum are computed as sum() over a matrix slice
and min(diag(sub) <- Inf) over a (k x k) submatrix, both C-level
primitives. The cached dist_sq attribute makes the squaring step a
one-time cost.calculate.ranking.crowding(): crowding sums use .rowSums()
directly. calculate.objectives.range() uses a single range() per
column instead of two apply() scans.singletons.repair(): when a single medoid is replaced, only that
individual's group assignment is recomputed; the rest of the
population is left untouched.generate.crossover.k.points(): the per-column random draw is now a
single runif(num_k) plus a vectorised ifelse() over both
children.generate.mutation.random.controller(): mutation decisions are made
in one runif(pop_size) draw; only the surviving individuals enter
the per-row body.verify.feasibility(): duplicated medoids are replaced from the
complement set (setdiff(seq_len(num_objects), row)) rather than by
blind resampling, which converges in fewer iterations.population.P is now allocated directly as matrix(0L, ...)
instead of the t(sapply(..., function(u) array(rep(0, num_k))))
pattern.apply(A, 1, function(x) all(x == B)) row-matching helper is
superseded by the vectorised row_equals(), which uses rowSums()
on a tiled comparison matrix.This release rewrites the hot inner loops of the algorithm using vectorised R primitives. Numerical results are bit-identical to 0.2.0 under the same random seed; only the runtime changes.
generate.groups(): the original nested for-loop is replaced by a
single max.col(-dmatrix[, medoids]) call, which runs in C.calculate.objective.functions(): the original triple for-loop over
individuals, clusters and objects is replaced by a single matrix
slice plus sum(). The minimum medoid-to-medoid squared distance
is now obtained from a (k x k) submatrix with diag(sub) <- Inf and
min(sub), also vectorised.singletons.delete() and singletons.repair() use tabulate()
to count cluster sizes in C instead of which() + length() in R.singletons.repair() no longer resets the column index to 1 on
every replacement; it now retries on the same column up to
num_objects attempts, eliminating an O(n^2) worst case.moc.gapbk() precomputes the element-wise squared distance matrix
for each input matrix once and caches it via an attribute, instead
of squaring entries inside the inner loop on every call.while iteration.rbind() calls on a growing data frame.apply(A, 1, function(x) all(x == B)) with vectorised
rowSums(A != B) == 0L.New README.Rmd (dynamic, generates README.md via
devtools::build_readme()) with CRAN, R-CMD-check, pkgdown,
Codecov, lifecycle and license badges.
Added GitHub Actions workflows under .github/workflows/:
R-CMD-check.yaml on Ubuntu (devel, release, oldrel-1), macOS
and Windows.pkgdown.yaml that deploys the documentation site to
gh-pages.test-coverage.yaml that pushes coverage to Codecov.Added _pkgdown.yml (Bootstrap 5, cosmo theme, navbar, structured
reference index, OpenGraph metadata, ORCID link).
Added codecov.yml with informational thresholds.
Added CODE_OF_CONDUCT.md (Contributor Covenant 2.1) and
.github/CONTRIBUTING.md, .github/pull_request_template.md,
.github/ISSUE_TEMPLATE/{bug_report,feature_request}.md.
Added a hex-style package logo at man/figures/logo.png.
Added the Language: en-US field to DESCRIPTION.
Updated .Rbuildignore and .gitignore.
Moved amap from Imports to Suggests.
moc.gabk() to moc.gapbk()
to match the package name. The previous name is preserved as a
deprecated alias that emits a warning and forwards its arguments to
moc.gapbk().doMPI from the dependency list.nsga2R, foreach, doParallel, parallel, utils, stats and
amap are now declared with explicit importFrom directives.registerDoParallel() is now called with its namespace prefix.Author: field has been removed from DESCRIPTION in favor of a
single Authors@R: declaration.cph) has been added for the maintainer.R/main.R has been split into thematic files.singletons.repair().parallel::makeCluster() now uses on.exit(parallel::stopCluster()).tests/testthat/ with smoke tests.vignettes/moc-gapbk-intro.Rmd introductory vignette.README.md, NEWS.md and cran-comments.md.