Skip to content

Route combinatorial ACO/GA parallel dispatch through GenerationRunner - #125

Merged
fundthmcalculus merged 1 commit into
mainfrom
refactor/combinatorial-generation-runner
Aug 24, 2026
Merged

Route combinatorial ACO/GA parallel dispatch through GenerationRunner#125
fundthmcalculus merged 1 commit into
mainfrom
refactor/combinatorial-generation-runner

Conversation

@fundthmcalculus

Copy link
Copy Markdown
Owner

Summary

  • combinatorial/{aco,aco_mst,ga}.py each hand-rolled their own spawn_streams/use_stream/joblib.delayed dispatch, duplicating what the continuous solvers already factored into core/parallel.GenerationRunner (the copy-fixed-data-once path from the perf work) — they just never adopted it.
  • Each solver now builds a fixed tuple of its run-constant data (distance matrix, desirability/config, individuals_per_job) and calls GenerationRunner.run() with only the per-generation varying argument (tau_alpha for the two ACO variants, the genome + its values for GA) instead of re-pickling everything to workers every generation.
  • Each per-individual worker (run_ant/run_ant_mst/run_ga) is wrapped in a new module-level _run_*_batch helper so it stays picklable for the "processes" backend.
  • Purely a dispatch-mechanism change — the per-individual logic itself is untouched, and GenerationRunner provides the same per-task RNG-stream isolation the old inline spawn_streams/use_stream did.

Test plan

  • New 9-test determinism sweep across all three solvers (aco-tsp, aco-mst, ga-tsp) at n_jobs in {1, 3} in tests/test_determinism.py — same seed reproduces identically, different seeds diverge
  • Manual smoke test confirming the "processes" backend still pickles cleanly for all three solvers
  • flake8 ./src ./tests — clean
  • MYPYPATH=src mypy -p optimizers — clean
  • black --check . — clean
  • Full suite passing (185 tests)

🤖 Generated with Claude Code

https://claude.ai/code/session_011r9W1JZRSoayjyLin4ZBPZ

combinatorial/{aco,aco_mst,ga}.py each hand-rolled their own
spawn_streams/use_stream/joblib.delayed dispatch, duplicating what
continuous solvers already factored into core/parallel.GenerationRunner
(the copy-fixed-data-once path from the perf work, report item #2) --
they just never adopted it.

Each solver now builds a `fixed` tuple of its run-constant data
(distance matrix, desirability/config, individuals_per_job) and calls
GenerationRunner.run() with only the per-generation varying argument
(tau_alpha for the two ACO variants, the genome + its values for GA),
instead of re-pickling everything to workers every generation under a
manual joblib.delayed loop. Each per-individual worker function
(run_ant/run_ant_mst/run_ga) is wrapped in a new module-level
_run_*_batch helper so it stays picklable for the "processes" backend.

Purely a dispatch-mechanism change -- the per-individual logic
(run_ant/run_ant_mst/run_ga) is untouched, and GenerationRunner
provides the same per-task RNG-stream isolation the old inline
spawn_streams/use_stream did.

Verified: a 9-test determinism sweep across all three solvers
(aco-tsp, aco-mst, ga-tsp) at n_jobs in {1, 3} -- same seed reproduces
identically, different seeds diverge -- plus a manual smoke test
confirming the "processes" backend still pickles cleanly for all
three. flake8/mypy/black clean; full suite passing (185 tests).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011r9W1JZRSoayjyLin4ZBPZ
@fundthmcalculus
fundthmcalculus force-pushed the refactor/combinatorial-generation-runner branch from df63a0d to ab659d2 Compare August 24, 2026 17:06
@fundthmcalculus
fundthmcalculus merged commit 4d81121 into main Aug 24, 2026
1 check passed
@fundthmcalculus
fundthmcalculus deleted the refactor/combinatorial-generation-runner branch August 24, 2026 17:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant