Ensemble rng redesign - #1252
Conversation
…ding Introduce EnsembleContext, generate_trajectory_seeds, and default_rng_func to support deterministic, thread-count-independent ensemble solves via seed/rng/rng_func kwargs on solve(). Per-trajectory seeds are pre-generated from a master RNG/seed and forwarded to solvers guarded by the supports_solve_rng trait. Includes 5-arg prob_func support, per-task JumpProblem isolation via task_local_storage(), master_rng sanitization for distributed modes, and worker_id propagation through solve_batch. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Run runic formatter on basic_ensemble_solve.jl. Add SDE+Jump problem definition and K2 test section covering safetycopy=false with SDE, SSA, ODE+Jump, and SDE+Jump across EnsembleThreads and EnsembleDistributed. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
This is currently marked WIP as I need to carefully review all the new tests still, and because it shouldn't be merged till the listed prerequisite PRs are handled with package releases. |
Add SDE+Jump to SOLVER_PAIRS (test A) and serial/threaded equivalence (test C) for complete 5-pathway coverage matching the v4 test plan. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add prob_func-level distinct stream tests (StableRNG end-to-end, all 4 algorithms) - Add solver-level distinct stream tests (jump first-times, SDE endpoints) - Add EnsembleSplitThreads and EnsembleDistributed to cross-algorithm equivalence - Expand different-seeds test to all 5 problem types - Restructure and renumber tests for logical flow (15 sections, 86 tests) - Remove unused STOCHASTIC_PAIRS constant Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix @inferred regression: use Val-dispatch + function barrier so Core.Compiler.return_type sees concrete types in batch_func closure. Val(::Bool) infers as abstract Val; explicit if/else with Val literals gives Union{Val{true},Val{false}} enabling union splitting. - Add 3-mode solve dispatch (:rng, :seed, :none) for JumpProblem explicit-RNG compatibility: when supports_solve_rng is false but prob is AbstractJumpProblem, pass seed kwarg to enable per-trajectory reseeding via JP v9's resetted_jump_problem. - Add type assertion for task_local_storage access in EnsembleThreads to preserve inference through tmap's Core.Compiler.return_type. - Add test section 5b for explicit JumpProblem RNG (Xoshiro). - Document prob_func type preservation constraint in docstring. - Fix 3 runic lambda indentation issues in test file. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… 5-arg examples - Rename _prob_func_has_rng → _prob_func_is_5arg for clarity (Val version too) - Fix comment referencing _solve_rng_mode in __solve (variable moved to dispatch) - Expand _invoke_prob_func / _invoke_solve comments with dispatch details - Add 5-arg prob_func example to EnsembleProblem docstring - Fix misleading "one source of truth" comment in batch_func Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move closing parens to own lines for named tuples and function calls - Rephrase comment to avoid typos-flagged word Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The deprecated EnsembleProblem(::Vector{<:Problem}) stores a Vector as
prob.prob, not an AbstractSciMLProblem. Add a general fallback so
supports_solve_rng does not error on non-problem types.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tests that prob_func + remake on JumpProblems correctly propagates parameter changes and does not cause race conditions from aliased fields on EnsembleThreads. Covers both safetycopy=true and false. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…tness Forward seed to inner solves for deprecated EnsembleProblem(::Vector) path by treating AbstractVector like AbstractJumpProblem for RNG mode selection. Fix 5-arg prob_func docstring to clarify it works without rng/seed too. Replace integer endpoint != checks with continuous-valued time comparisons to avoid potential spurious collisions in SSA tests. Fix stale comment about JumpProblem u0 in make_eprob. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
@ChrisRackauckas assuming tests pass now this is good with me. I think it would be better to merge and release this before making the JumpProcesses v10 release. This should be setup to work correctly/safely with JumpProcesses v9 too. |
|
DiffEqGPU.jl should be aligned with this as well, since it hooks into the non-public API part here so I think this'll break it. |
DiffEqGPU CPU offload path calls SciMLBase.solve_batch with 5 positional args (without ensemble_rng_state). Add fallback methods for all four ensemble algorithm types that forward to the 6-arg version with a no-op RNG state. Uses Returns(nothing) for rng_func to avoid calling Random.default_rng(). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
I tried to add a shim to keep the old behavior for DiffEqGPU. I don't have any real GPU coding knowledge, so wouldn't feel comfortable that I could handle that ok at this point (I would have to essentially just trust an AI, which I don't think is a good approach here). I will open a PR to DiffEqGPU to see if I can get it to run CI vs. this branch to confirm its tests still pass with it. |
Breaking change: prob_func(prob, i, repeat) → prob_func(prob, ctx) and
output_func(sol, i) → output_func(sol, ctx) where ctx::EnsembleContext.
Redesign EnsembleContext{S,R,M} to include sim_id, repeat, rng, sim_seed,
worker_id, and master_rng fields. Eliminate numargs-based arity detection
that blocked trim and static compilation. Use Accessors.jl @set for
type-stable immutable struct updates in batch_func.
Renamed: global_trajectory_id → sim_id, trajectory_seed → sim_seed,
generate_trajectory_seeds → generate_sim_seeds. Removed _invoke_prob_func
and _prob_func_is_5arg entirely.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
@ChrisRackauckas how does this look now? |
|
I can followup to have DiffEqGPU support the new prob_func and output_func signatures once this gets released. |
Resolve conflict in ensemble_problems.jl by accepting v3 removal of the deprecated vector-of-problems EnsembleProblem constructor. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@ChrisRackauckas should be set to merge to v3. |
Ensemble-level RNG management for reproducible per-trajectory seeding
This PR adds deterministic, thread-count-independent reproducibility to ensemble solves. Passing
seedorrngto an ensemblesolvepre-generates per-trajectory seeds from a master RNG, then seeds each trajectory'sTaskLocalRNGbefore solving. Results are identical regardless of thread count, batch size, or ensemble algorithm.New kwargs on ensemble
solveseed: Master seed (integer). Pre-generates deterministic per-trajectory seeds.rng: Master RNG (e.g.Xoshiro). Takes priority overseed.rng_func: Custom per-trajectory RNG factory(ctx::EnsembleContext) -> AbstractRNG. Defaults todefault_rng_funcwhich seeds theTaskLocalRNG.New exported type
EnsembleContext{S, R}: Passed torng_funcand the optional 5-argprob_func. Fields:global_trajectory_id,worker_id,trajectory_seed,master_rng.Usage examples
Basic reproducible ensemble solve:
5-arg
prob_funcwith explicit RNG access:Custom
rng_funcwith StableRNG:Master RNG instead of seed:
Implementation details
rng_funcis always called to seed each trajectory. Therngkwarg is forwarded to innersolveonly whensupports_solve_rng(prob, alg)returnstrue. Non-DE solvers that don't acceptrngstill benefit from the already-seededTaskLocalRNG.prob_funcdetection: When any method ofprob.prob_funchas ≥5 arguments (detected vianumargs), the form(prob, i, repeat, rng, ctx)is used.threadid()-indexeddeepcopyarray withtask_local_storage()-based per-task copies, which is safe under Julia's M:N threading model. Only active whensafetycopy = falseresulting in one JumpProblem deepcopy per thread.master_rngsanitization:master_rngis set tonothingbeforepmapcaptures the closure inEnsembleDistributedandEnsembleSplitThreads, avoiding serialization of potentially non-serializable RNG objects.worker_idpropagation:EnsembleDistributedandEnsembleSplitThreadspassworker_id = myid()throughsolve_batchtobatch_func, soctx.worker_idcorrectly reflects the distributed worker pid.Prerequisite PRs (should be merged and released in order before this PR for testing purposes)
ensemble_rng_redesign), NON-BREAKING: Merge after steps 2–4 are released.