Overview and Workflow
Use the scenario planner when you want to compare whole plans rather than run a single low-level optimisation call.
The planner combines typed scenario specifications, a Python comparison service
and retained evidence bundles. Use abacus.scenarios for new scenario code.
Application wrappers are separate projects.
If you need the low-level optimiser instead, see Budget Optimisation.
For the supported entry points and current limits, see Supported Surface.
What the planner compares
The retained planner supports three scenario types:
| Scenario type | Purpose | Public spec |
|---|---|---|
| Current | Use observed history as a reference plan | CurrentScenarioSpec |
| Manual allocation | Simulate a user-defined future plan | ManualAllocationScenarioSpec |
| Fixed-budget optimised | Optimise a future plan at a fixed budget | FixedBudgetOptimizedScenarioSpec |
FE and CRE support historical and manual scenarios for complete fitted-unit panels. Fixed-budget optimisation remains unavailable for these presets. See the estimator support matrix.
Planner units versus optimiser units
The most important distinction is budget units.
| Surface | Public budget contract |
|---|---|
PanelBudgetOptimizerWrapper | Per-period spend |
abacus.scenarios.ScenarioPlanner | Total spend over the whole scenario horizon |
For example, if a four-period scenario has a total budget of 900_000, the
planner converts that to per-period units internally before it calls the
wrapper or response sampler.
Requested and evaluated windows
Each scenario has a requested window from start_date to end_date.
For simulated scenarios, the evaluated window can be longer than the requested
window when you set include_carryover=True. AMMM3 extends the synthetic
future path so lagged adstock effects can continue after the requested end
date.
The planner reports both windows in the metadata output.
Historical overlap for current scenarios
CurrentScenarioSpec is strict about history.
Its requested window must overlap observed data. AMMM3 does not reinterpret a future-only window as “use the latest history instead”.
Typical workflow
The common workflow is:
- Fit
PanelMMM. - Build one or more scenario specs.
- Run
abacus.scenarios.ScenarioPlanner.compare(...)or a versioned scenario recipe against the fitted run directory. - Inspect the comparison tables, save workspaces, and export the planning outputs you need.
Minimal example
from abacus.scenarios import (
CurrentScenarioSpec,
ManualAllocationScenarioSpec,
ScenarioPlanner,
)
planner = ScenarioPlanner(mmm)
comparison = planner.compare(
[
CurrentScenarioSpec(
name="Current baseline",
start_date="2025-01-06",
end_date="2025-02-24",
),
ManualAllocationScenarioSpec(
name="Manual plan",
start_date="2025-03-03",
end_date="2025-03-24",
noise_level=0.0,
include_carryover=False,
allocation={
"channel_1": 420_000.0,
"channel_2": 280_000.0,
"channel_3": 200_000.0,
},
),
]
)
For the full API, see Python API.
How the planner differs from post-model summaries
The scenario planner does not reuse mmm.summary tables directly. Instead, it
builds comparison tables that are specific to planning:
totalschannelscontributions_over_timeallocationsmetadata
See Comparison Outputs.
Common pitfalls
- Mixing up total horizon spend and per-period spend
- Using a future-only window in
CurrentScenarioSpec - Forgetting that carryover can extend the evaluated window