Severity: Medium (performance)
Under the default CSA preset (far_update_mode="crowding_aware"), every observation in a committed generation builds a fresh distance workspace and recomputes all O(n²) pairwise bank distances, though at most one entry changes per step.
Locations — src/variopt/algorithms/population/csa/banking/update/logic.py:287-298,465-490 + banking/queries.py
_clearing_occupancy-equivalent crowding counts / niche scores are recomputed from scratch per observation via a fresh BankDistanceWorkspace, giving O(m·n²) diversity-metric calls per generation — this is the subsystem's hot loop when the diversity metric is expensive (e.g. molecular similarity).
Related, smaller instance of the same pattern: recluster (banking/update/logic.py:199-202, O(n²) distances + scipy linkage) runs at the end of every batch even when no entry changed, and advance_growth_state in multiplicative_decay mode (banking/growth/logic.py:357-395) recomputes minimum_pairwise_distance O(n²) on every tell.
Fix direction
Hoist one distance workspace to apply_bank_update_batch scope and invalidate only the rows/columns of replaced indices, rather than rebuilding per observation. Skip recluster when changed_indices is empty and reuse the batch distance workspace where possible.
Severity: Medium (performance)
Under the default CSA preset (
far_update_mode="crowding_aware"), every observation in a committed generation builds a fresh distance workspace and recomputes all O(n²) pairwise bank distances, though at most one entry changes per step.Locations —
src/variopt/algorithms/population/csa/banking/update/logic.py:287-298,465-490+banking/queries.py_clearing_occupancy-equivalent crowding counts / niche scores are recomputed from scratch per observation via a freshBankDistanceWorkspace, giving O(m·n²) diversity-metric calls per generation — this is the subsystem's hot loop when the diversity metric is expensive (e.g. molecular similarity).Related, smaller instance of the same pattern:
recluster(banking/update/logic.py:199-202, O(n²) distances + scipy linkage) runs at the end of every batch even when no entry changed, andadvance_growth_stateinmultiplicative_decaymode (banking/growth/logic.py:357-395) recomputesminimum_pairwise_distanceO(n²) on every tell.Fix direction
Hoist one distance workspace to
apply_bank_update_batchscope and invalidate only the rows/columns of replaced indices, rather than rebuilding per observation. Skipreclusterwhenchanged_indicesis empty and reuse the batch distance workspace where possible.