src.core.opt_sequential¶
Sequential multi-period budget optimization.
This module provides a robust alternative to simultaneous multi-period optimization. Instead of optimizing all periods at once (which can fail for numerical reasons), it optimizes one period at a time in sequence.
This approach is: - Guaranteed to converge (each period is a small, easy problem) - Fast (8 small problems << 1 large problem) - Respects ramp constraints naturally (previous period is the baseline) - Numerically stable (avoids high-dimensional optimization issues)
Trade-off: Sequential is greedy (not globally optimal) but robust (always works).
Module Contents¶
- src.core.opt_sequential.optimize_sequential_multiperiod(method: str, total_budget: float, budget_ranges: Dict[str, Tuple[float, float]], parameters: Dict[str, Tuple[float, float]], channels: List[str], n_periods: int, seasonal_effects: Dict[int, Dict[str, float]] | None = None, ramp_abs: Dict[str, float] | None = None, ramp_pct: Dict[str, float] | None = None, ramp_eps: float = 1e-06) Dict[int, Dict[str, float]]¶
Optimize budget across multiple periods sequentially.
Instead of solving one large optimization problem with n_periods × n_channels variables, this solves n_periods small problems with n_channels variables each.
Each period uses the previous period’s allocation to enforce ramp constraints.
- Parameters:
method – Response curve method (‘michaelis-menten’ or ‘sigmoid’).
total_budget – Total budget across all periods.
budget_ranges – Budget ranges (min, max) per channel.
parameters – Model parameters per channel.
channels – List of channel names.
n_periods – Number of periods to optimize.
seasonal_effects – Optional seasonal multipliers per period.
ramp_abs – Optional absolute ramp limits per channel.
ramp_pct – Optional percentage ramp limits per channel.
ramp_eps – Epsilon for percentage ramp calculations.
- Returns:
Dictionary mapping period index to channel budgets.
Example
>>> result = optimize_sequential_multiperiod( ... method='sigmoid', ... total_budget=1_000_000, ... budget_ranges={'google': (10000, 50000), 'fb': (5000, 30000)}, ... parameters={'google': (0.5, 10000), 'fb': (0.6, 15000)}, ... channels=['google', 'fb'], ... n_periods=13 ... )