lcdaGRASP 0.3.2
This release adds the reporting surface (lcda_metrics()) and the community-and-leader maps, and gives a version number to the four datasets that were merged after the v0.3.1 tag. Between v0.3.1 (commit 09cb457) and this release, six commits added new shipped data while DESCRIPTION still read 0.3.1, so two different contents were both installable as “0.3.1” and anyone installing from the v0.3.1 release did not get the data behind Section 5.5 of the companion paper. No algorithm behaviour changes here: the search itself is untouched, and every addition below is reporting and plotting.
New features
-
lcda_metrics()— one metric surface for everything the paper reports. Given a fitted result (and, optionally, a ground truth) it returns a tidy table with modularityQ, the NCE leader score in both its global and its community-conditioned form, recovery indices (NMI, ARI, Rand, VI, split-join), the number and size distribution of the communities, wall-clock runtime, and the search diagnostics (trace dispersion, best iteration, and how often the lexicographic tie-break onHwas decisive).level = "community"andlevel = "leader"give the per-community and per-leader breakdowns, including each community’s additive contribution toQ(they sum exactly toQ), its conductance and purity, and each leader’s within-community degree rank and percentile. Baselines that carry no leaders (anigraphcommunitiesobject, a bare membership vector) are accepted and scored the same way, with derived leaders clearly flagged, so a paper-style comparison table can be assembled from one function. (#45)node_score =reproduces the paper’s external leader validation on any graph: pass a per-vertex outside signal and the leaders are ranked within their own community by it, with the mean percentile and the top-1 / top-3 hit rates summarised in aleader_scorescope. The participation coefficient (the statistic the paper uses to characterise bridge nodes) and the ensemble overlap fraction are reported as well. -
Community-and-leader maps drawn by the package (#44):
-
lcda_plot_communities()runs the whole pipeline on a bare graph — detect communities, designate leaders, render the figure — in one call, and returns the fitted result so it can be piped intolcda_metrics(). -
plot()methods forlcda_grasp_result,lcda_gr_resultandlcda_ecg_resultplot a fitted result directly. -
ggplot2::autoplot()methods return the same figure as aggplotobject ( stays a Suggested dependency; the base-graphics path has no extra requirements). -
plot_partition()gainedlayout,leader_labels,legend,legend_max,vertex_size,leader_size,palette,shade_edges,mark_communitiesandmain. It now labels leaders, shades intra-community edges by community, greys the inter-community ones, draws a community/leader legend, and returns the layout and colours used so a companion figure can reuse them. The previous call signature still works.
-
lcda_grasp(),lcda_gr()andlcda_ecg()results now carryelapsed(wall-clock seconds, the runtime column of the paper’s timing tables) andgraph(the simplified graph the kernels actually saw). Because the result is self-contained,lcda_metrics(res)andplot(res)need no second argument. Theprint()methods report the runtime and point at both.elapsedtimes the search only, starting after theas_csr()conversion, so it is 0.3-2% smaller than timing the whole call from outside.
Two reporting choices worth knowing, both made so that no number is published where none was measured:
- The lexicographic metrics (
lex_decisive_n,lex_decisive_pct) are emitted only forlcda_gr(), the one algorithm that instruments the tie-break. Forlcda_grasp()andlcda_ecg()they are absent rather than reported as a measured-looking0. -
internal_densityis always structural (a proportion of the possible pairs, hence always in[0, 1]) even on a weighted graph, whereinternal_edgesandboundary_edgesare weight sums.Qandconductanceremain weight-aware.
Notes
-
Fitted results now hold a reference to their graph. This is what makes
lcda_metrics(res)andplot(res)work without a second argument, but it matters if yousaveRDS()a pool of results: the graph dominates the serialised size (measured onn = 20000: 1.60 MB of a 1.69 MB result). In memory it is free (R shares the object); on disk it is not. Drop it withres$graph <- NULLbefore saving a large pool, and pass the graph explicitly tolcda_metrics()/plot()afterwards. -
res$graphis the simplified graph (multi-edges collapsed, asas_csr()does), not necessarily the object you passed in. Metrics are computed on it deliberately, so thatQmatches the value the objective actually optimised.
New datasets (added after the v0.3.1 tag)
-
realnet_amazon— large real network with ground truth: Amazon-Computers co-purchase graph (recovery and runtime). -
vnmi_nprime— VNMI candidate-subset sizen'sensitivity sweep: modularity and local-search time vsn'across density regimes. -
realnet_coauthor— Coauthor-Physics (largest connected component, n = 34,493, 5 fields), the paper’s headline real network. -
openalex_leaders— leader validation against an external citation signal on an OpenAlex co-authorship graph.
The other 24 datasets carry the same numbers as the ones shipped in v0.3.1: their results objects are byte-for-byte identical (verified by serialising $results for all 28 datasets before and after the metadata repair below and comparing SHA-256: 28/28 unchanged), as is every meta field except network_source. They are not bit-identical as files, and their SHA-256 checksums in inst/extdata/SHA256SUMS have changed accordingly: the one provenance field that was false has been corrected in place (see Fixes below). No simulation was re-run for this release.
Provenance model
Dataset provenance now records three distinct facts instead of overloading one version string:
generated_by— the package version whose code produced the numbers. This is a historical fact and is never rewritten on a version bump. All 28 datasets currently report0.3.1, which is the truth: none of them were regenerated for this release.first_release— the release in which a file first shipped, recorded in the newinst/extdata/MANIFEST.csv(24 datasets at0.3.1, 4 at0.3.2).shipped_in— the version of the installed copy, i.e.packageVersion("lcdaGRASP").lcda_provenance()returns these three columns plusgenerated_onandsha256. The oldpkg_versioncolumn is renamedgenerated_by, because it never meant “the version you installed”.data-raw/999_manifest.RregeneratesMANIFEST.csvandSHA256SUMSwithout re-running any simulation;first_releaseis sticky once recorded.data-raw/00_helpers.Rnow stamps the git commit (meta$git_commit) into newly generated datasets, so future data pins an exact source state rather than a possibly-unbumped version string.The data-version test no longer demands that every dataset carry the current package version (an invariant that can only be met by rewriting metadata, or by re-running hours of simulation on every bump). It now enforces the honest invariants: no dataset generated by a future version, full coverage by both manifests, metadata agreement, and matching SHA-256 checksums.
MANIFEST.csvis itself listed inSHA256SUMS, so the release-identity manifest is covered by the same integrity check as the data it describes; anddata-raw/999_manifest.Rnow warns instead of silently falling back to the current version when it cannot reach git to derivefirst_release.
Fixes
-
meta$network_sourcewas a false constant in all 28 shipped datasets.data-raw/00_helpers.R::make_meta()hard-coded it to"Newman netdata collection (websites.umich.edu/~mejn) + igraph::make_graph('Zachary')"and collected every other argument intoextra. Every dataset therefore claimed the five classical benchmarks as its origin — including the synthetic LFR sweeps generated withnetworkx(lfr_robustness,largescale,lcda_ecg, …), the purely synthetic SBM study (pool_sensitivity), the Shchur et al. (2018) real networks (realnet_coauthor,realnet_amazon) and the OpenAlex extraction (openalex_leaders). The three generators that did pass a correctnetwork_sourcepassed it through..., where it was swallowed byextraand never reached the field readers see.Fixed at the source:
make_meta()now takesnetwork_sourceas a required formal argument with no default, aborts if it is missing, empty, or passed through..., and everydata-raw/*.Rgenerator supplies the network it actually ran on. The 28 shipped.rdsfiles were repaired in place by the one-offdata-raw/998_fix_network_source.R, which rewrites onlymeta$network_source(and drops the shadowedmeta$extra$network_sourcecopy) and aborts if anything else moves. Correcting a field that was false is not the same as restamping one that was true:generated_by/generated_onare untouched, exactly as in the 0.3.2 provenance model above.tests/testthat/test-data-network-source.Rlocks the invariants in: every dataset declares a non-empty source, the collection is not one constant, no synthetic or external dataset cites the benchmark collection, every benchmark-based dataset names a benchmark, nonetwork_sourcesurvives inmeta$extra, and every installed dataset is covered by the guard. Vignette
robustness-and-limits: the two uncertainty ribbons (NMI vs mixing, and leader spreading advantage) were silently missing. Bothsummarise()calls overwrote a column with its own mean before takingsd()of it, so the dispersion evaluated toNAandgeom_ribbon()dropped every row. The dispersion is now computed before the mean, and the bands render again.
lcdaGRASP 0.3.1
Fixes
-
lcda_ecg()now passes the chosencentralityto the repair and local-search steps (previously the consensus leader was always eigenvector-based). -
seed = NULL(andNA) is accepted and means “leave the RNG untouched”; invalid seeds are rejected with a clear message. -
data-raw/97_lcda_ecg.Rand the scripts that reused it now call the exportedlcda_ecg()instead of a private re-implementation, so the cachedlcda_ecg.rdsreflects the canonical function (incl.Q_consensus_weighted).
lcdaGRASP 0.3.0
New features
-
lcda_ecg()— ensemble-consensus community and leader detection. Turns the GRASP pool (the diverse partitions produced across iterations, previously discarded) into edge co-association weights in the spirit of Ensemble Clustering for Graphs (Poulin & Théberge, 2019), re-clusters for a consensus partition, and designates one leader per community from the pool’s leader-designation frequencies. On canonical LFR benchmarks it recovers the planted structure on par with ECG and outperforms Leiden, with its advantage concentrated at high mixing, while retaining the joint leader output and adding a per-node confidence map. Withoverlap = TRUEit additionally returns overlapping community memberships (and the bridge nodes) derived from the soft co-association. Returns anlcda_ecg_resultobject with aprint()method.
lcdaGRASP 0.2.0
- tidyverse-style refactor with
clilogging and averboseargument throughout; statistics return tibbles. -
lcda_data()accessor for precomputed datasets underinst/extdata/. - pkgdown site with nine vignettes.