You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Breaking: estimateMissSBM()'s control must now be built with the new missSBM_param()
(one named, defaulted argument per option) instead of a raw list(...), which
now errors with a message pointing at the replacement.
missSBM_fit now exposes split(), merge(), candidates_split() and candidates_merge()
as instance methods, previously inlined in missSBM_collection's exploration logic; same
search algorithm, now independently testable.
new polish(control) (missSBM_fit and missSBM_collection): node-swap refinement after VEM
convergence, fixing individually misclassified nodes that split()/merge() cannot reach.
requesting more blocks than a network actually supports can make VEM collapse one or more
classes; this used to be silent, and split/merge exploration's own repair of it could
silently corrupt vBlocks's bookkeeping (duplicated/missing entries, non-smooth ICL/ELBO in plot()). Now fixed and made visible: missSBM_fit$repair(control) recovers a collapsed fit ;
new occupiedBlocks/ degenerate fields expose any remaining collapse; bestModel skips degenerate models when possible and plot() marks them with a distinct point
shape; estimateMissSBM()'s new stopOnDegenerate/maxConsecutiveDegenerate controls
(default TRUE/2) stop forward exploration from growing further into a persistently unsupported range.
new estimate_chain() (missSBM_collection) / warmChain control (default FALSE, opt-in):
initializes each model by splitting the already-converged, smaller neighbor instead of an
independent cold clustering, substantially reducing collapse in practice, at the cost of
fitting vBlocks sequentially rather than in parallel.
replace the NLopt/CCSAQ optimizer for the covariate connectivity parameters with a builtin
Newton-Raphson solver (the M-step objective is concave, so it converges reliably in a handful
of iterations); nloptr is no longer a dependency
fix partlyObservedNetwork$imputation(): the fill value for missing dyads was biased low by
including not-yet-imputed entries in its own computation. Known side effect: doubleStandardSampling_fit's initial psi bootstrap can degenerate when the fill value exactly
matches the empirical observed edge rate (refined away by the VEM loop that follows)
Minor changes
profiled estimateMissSBM() and fixed several hot-path inefficiencies: avoidable dense * sparse promotion overhead, a redundant recomputation of the dense imputed-network
matrix, and an ifelse() evaluating both of its branches unconditionally. Roughly 3x faster
on our benchmark, bit-identical results
estimateMissSBM() now sorts/de-duplicates vBlocks if needed (with a warning), since
exploration and chaining both assume it is strictly increasing.
estimateMissSBM()'s control drops the exploration field: nobody used "forward"/ "backward" alone at that level, only "both"/"none", so iterates now doubles as the
on/off switch (0 disables exploration entirely). missSBM_collection$explore() no longer
reads a stored exploration control field either; its direction argument (default "both")
is now a plain per-call parameter, still available for advanced/internal use.
cap the number of merge candidates tried during backward exploration
(control$maxMergeCandidates, default 30) instead of always trying every pair
fix a crash and a closed-form algebra bug in the "degree" sampling design; parameter recovery
for this design can still be biased under heavy missingness (known limitation)
fix a consistency bug in missSBM_fit$doVEM()'s step-back: only the SBM was restored, not the
sampling model or the current imputation
speed up getCovarArray() and kmeans_missSBM()'s seeding
remove unused src/utils.h
missSBM_fit's polish(), repair(), candidates_split() and candidates_merge() gain the
same default control as doVEM(), so they can be called standalone without building a full
control list first; missSBM_collection's calls (which always pass an explicit control list)
are unaffected ; missSBM_collection's estimate()/polish()/explore() now share a control
list stored at construction, no longer requiring control on every call.
Factored missSBM_collection's explore_forward()/explore_backward() into a shared private explore_direction(), and missSBM_fit's candidates_split()/candidates_merge()'s trial-fit
loop into a shared private trial_fit_candidates(); verified bit-identical output on the same
fixed-seed scenario used throughout this changelog to diagnose VEM collapse