Simulation engine: axes sweeps + dynamics hook#81
Open
vahid-ahmadi wants to merge 1 commit into
Open
Conversation
Implement axes (parameter/input sweeps) and a Dynamics trait for behavioural-response passes, building on the existing branch primitive. - Axis::on_people / on_people_where / on_parameters + Simulation::run_axis run the engine across a linearly spaced range in parallel (rayon), returning per-step AxisStep results for MTR / cliff-edge / budget curves. - Dynamics trait + apply_dynamics thread behavioural passes between baseline and reform; LabourSupplyDynamics wraps the existing OBR labour-supply formulas, TakeUpDynamics models a deterministic benefit take-up campaign. Additive only; existing engine and main.rs behaviour unchanged. Adds 10 unit tests (monotone net income / income tax across an earnings sweep, parameter sweep raises tax, selective sweep, dynamics direction + no-op). Addresses #49. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses #49.
Scope
Two new, fully-tested engine capabilities, built on top of the existing
Simulation::branch+Comparisonprimitive (reused, not duplicated):Axes (parameter / input sweeps) —
src/engine/axes.rsMirrors PolicyEngine's "axes" concept. An
Axisis(name, min, max, count, setter):Axis::on_people(...)/Axis::on_people_where(..., select, ...)— sweep an input field (e.g. employment income £0→£200k) over all / selected people.Axis::on_parameters(...)— sweep a parameter value (e.g. the basic income-tax rate).Simulation::run_axis(&axis)linearly spaces the range, applies the setter per step, runs the engine in parallel with rayon, and returns oneAxisStep { index, value, results }per point — the per-step results that back marginal-tax-rate, cliff-edge, and budget-constraint charts.Dynamics hook —
src/engine/dynamics.rsA clean
Dynamicstrait for a behavioural-response pass applied between the baseline run and the reform run;apply_dynamics(passes, ...)threads passes in order over the input frame (empty = static run).LabourSupplyDynamics— formalises the existing OBR Slutsky-decompositionapply_labour_supply_responsesbehind the trait, so the labour-supply formulas finally have a hook. No logic duplicated; honourslabour_supply.enabled.TakeUpDynamics { target_rate, benefits }— a deterministic benefit take-up campaign that flipswould_claim_*flags for benefit units whosemigration_seedis belowtarget_rate(consistent with the engine's existing deterministic take-up gate).Additive only — existing engine behaviour and
main.rsare unchanged.Tests
10 new unit tests (
cargo test→ 201 passed, 0 failed across both test binaries):on_people_whereonly touches the selected household.value_atrange / single-step edge case.Remaining
Simulation::branch+Comparison); reused here.Dynamicstrait.apply_dynamicsordering wired intomain.rs(income → MTR → response → recompute) remain follow-up slices.🤖 Generated with Claude Code