chc.allocation¶
Stability tier: experimental.
A media budget spread over channels: one spend a period for each channel, within its box, for the most return, carryover counted in and out.
allocate plans periods periods of spend on chc.response.Channel\ s. Each
channel runs at one rate a period, between its lower and upper rates, and the rates spend
the budget. A plan's worth is what its spend returns on the channels: the adstock the history
leaves runs into the plan's periods, and the plan's spend runs on for each kernel's length after
them with nothing spent, so a channel whose carryover is long is not undervalued for the periods
the plan ends before its return does.
Exact where every curve is concave. A channel's worth is its coefficient times the curve summed
over periods whose adstock is affine in the rate, so it is concave in the rate when the curve is
concave and the coefficient not negative, and the channels add. At a price mu per currency unit
each channel then runs where the slope of its worth meets periods * mu, or at an end of its
box, and mu is where the rates spend the budget. The price moves every rate the same way, so a
bisection on it is exact; where a channel is linear its rate jumps at one price, and the plan
spends the last of the budget on the rates either side of it, both of which are best there.
An S-shaped curve is planned by branch and bound. Where a curve starts convex the worth is not
concave, and the bisection's plan on each curve's concave envelope (chc.response.Envelope)
returns less on the curves than the best: two Hill curves of slope 3 and scales 1 and 1.01 at a
budget of 1.6 are planned 1.27/0.33 for 0.705 there, where 1.6 on the first returns 512/637, 0.804.
So the rates are searched in boxes (Udell and Boyd 2016). A box of a channel's rate is an interval
of each period's adstock, and the curve's envelope over that interval is the chord from its floor
to where it touches the curve, or to its cap where that comes first, and the curve beyond: concave
in the rate, above the worth, and equal to it at both ends. The bisection on those envelopes bounds
every plan in the box, and its plan, read on the curves, is a plan. The box of the largest bound
is cut first, on the channel whose envelope stands furthest above its curve at the plan, at its
rate, where both halves' envelopes meet the curve. Allocation.bound is the largest bound
left when every bound is within the search's tolerance of the best plan's worth, or once the next
cut would plan past max_boxes boxes, 500 by default; on concave curves it is the worth. The
tolerance is the caller's: the larger of atol and rtol of the first box's bound, a share
1e-9 by default, but never below 64 epsilons of the dtype the curves are read in, of that
bound, where the gap is rounding that no cut closes. Allocation.stopped says which,
Allocation.limit what stopped the search, and Allocation.boxes how many boxes
were planned; a search the cap stops logs a warning (chc_event="allocation_cap") with its
gap. Rates that jump at one price, on chords of one slope, are filled one at a time, so at most
one channel is left inside its chord, where the curve is below the envelope. With kernels of
length one, floors at zero and caps past the tangencies, that bounds the gap of the first box
before any is cut: the largest
periods * coefficient * nonconvexity (chc.response.Saturation.nonconvexity), Shapley
and Folkman's lemma for one constraint (Aubin and Ekeland 1976; Udell and Boyd 2016). It is all but
reached: four equal Hill curves of slope 3 at three scales leave a gap of 0.1544 against 0.1547.
The price is the budget's shadow price on the planned channels: the return one more currency unit of budget buys, spread the way the plan spends it. It is where the channels running inside their boxes meet; a channel at its cap returns more a unit and one at its floor less. On S-shaped curves it is read on the curves at the plan, in the caller's box: the slope of the channel below its cap where one more unit returns the most, the same in whichever box the search found the plan.
A goal in place of a budget. budget_for finds the budget that meets a goal, and plans
it: the least budget that gains a return (ReturnTarget), the budget at which one more unit
returns a given amount (MarginalReturnTarget), or the most budget whose plan returns a
given amount a unit on average, a target return on ad spend (ReturnOnSpendTarget). A
plan's gain is what its spend adds, worth - idle, where idle is what the channels return
with nothing spent in the plan: the history's carryover alone. As the price falls every rate rises,
so the plans for every budget lie on one path, and each goal is a point on it. On S-shaped curves
each plan is allocate's search at its budget; those plans lie on no one path, and the
budget is found over them.
A split for several readings of the channels. Tests that never bent a curve fit several
families alike, and the families part where the plan goes. minimax_allocate takes each
reading of every channel and chooses the split whose worst regret over them is least: the regret
under a reading is its best return at the budget over the split's, both on its curves, the best
its allocate plan's. A reading's regret is convex in the split where its curves are
concave, so the worst is too, and cutting planes (Kelley 1960) close on it from below while the
splits they propose close on it from above; the two ends are the certificate. The worst regret is
the least of the readings' gains over their bests, negated, so it is the worst share below at one
reading, each gain read against the reading's best, and on S-shaped curves it is searched in boxes
as that share is.
A split that gains in the worst share of a posterior's draws. A fit's draws are readings too,
many and alike, and over them the worst case is one draw. cvar_allocate takes the readings
and a reference split, the plan in place, and chooses the split whose mean gain over the reference
in the worst level share of the readings is the most: the gain's conditional value at risk
(Rockafellar and Uryasev 2000). Every gain is read on the curves, and the reference gains nothing
under any reading, so the split never does worse in that share than keeping it; at level = 1
it is the split for the mean return. The share's mean gain is concave in the split where the curves
are, and the same cutting planes close on it from above. On S-shaped curves the rates are
searched in boxes, as allocate searches them: in each box the planes are the tangents of
each curve's envelope over the box, which stand above the curve, so they bound the share's mean
gain in the box from above, and each split they propose, read on the curves, is a candidate, the
reference among them. Every reading's curves of a channel are read and bounded together, by one
compiled program for each structure of curve among them.
What a wrong channel costs the plan. A plan made on channels whose parameters are off by d
loses d' W d / 2 of the worth the true channels' plan returns, to second order:
decision_weight is that W, the decision weight of an experiment's value of information
(chc.experiment) with this allocation as the decision. The rates inside their boxes meet at
one price, so an error moves them along the budget, each by its slope's response to the error, less
the share of the whole that keeps the budget spent; W weighs those moves by each worth's
curvature. An experiment that leaves the parameters with covariance S leaves an expected regret
of tr(W S) / 2 (AllocationWeight.expected_regret).
Geos and channels together. allocate_geos plans one budget over a grid of cells, every
geo's channels, each cell a channel of its own with its curve, carryover and history. Besides each
cell's box, Totals bound what each geo spends over the plan, and what each channel spends
across the geos. At the best plan a cell inside its box returns, a currency unit, the budget's price
plus its geo's and its channel's: a total's price is what one more currency unit of room in it
returns, positive where it binds at its most, negative at its least, nothing where it does not bind.
A plan made in two steps, the budget split over the geos first and each geo's share over its
channels after, is one plan of the grid, so it never returns more. The best plan is found by cutting
planes on the cells' worths (Kelley 1960) under a linear program, whose value bounds every plan from
above while the plans it proposes approach from below; where every cell inside its box is strictly
concave, Newton's method on the binding totals' prices then makes the plan exact. The program's
duals name the totals that bind only to within its gap, so a total a hair from binding may be named
wrongly: one whose price comes out on the wrong side is released and one the plan breaks is bound,
until the plan meets the conditions that make it the best. On S-shaped curves the rates are
searched in boxes, as allocate searches them, the totals rows of each box's program: the
planes on each cell's envelope over the box bound every plan in it, and their plan, read on the
curves, is a plan. budget_for_geos finds the budget that meets a goal over the grid: on
concave curves the best plan's gain is concave in the budget and its slope is the budget's price,
so Newton's method on the budget meets a return target or a return on spend in a few plans, and a
marginal target is one plan, the budget left free and each unit of it charged the target's return.
A channel bought nationally. A channel bought once for every geo, as national media allotted
by population is, has one spend a period, of which each geo's cell spends a fixed share
(National). Both geo planners then choose that national spend, within its own box, in
place of its cells' rates. Its worth is its cells' summed, each reading its share, so it is
concave where their curves are; it counts in the budget and in its channel's total whole, and in
each geo's total by the geo's share. Inside its box it returns, a currency unit, the budget's price
plus its channel's and each geo's weighted by the geo's share. On S-shaped cells its worth over a
box of the national spend is bounded by its cells' envelopes over the box, summed: concave, above
the worth and equal to it at both ends of the box, so the box search cuts it as it cuts a cell.
HONEST SCOPE:
- The channels are read as given: a fitted channel's error goes straight into the plan. Where the
channels come from an experiment (
chc.lift.fit_lift), a plan that runs a channel past the adstock the tests covered reads the family's shape, not the experiment. - One rate a period for each channel, not a schedule: with a response that does not change with the period, only the history's carryover at the start and the tail at the end make periods differ.
- The tail is counted with nothing spent after the plan. Spend that continues after it would take the tail further up the curve, so a long kernel's tail is valued at its most.
chc.response.Rickeris not monotone, and a negative coefficient turns a concave curve convex; the bisection proves nothing for either, and both are refused.- On an S-shaped curve the best plan's gain rises with the budget but need not be concave in it, so a goal is met over searched plans by Brent's method on the budget: a return target where the gain crosses it, the least budget to the search's tolerance, and a target return on ad spend where the gain less the target a unit falls through nothing past its peak, not proved the most.
- On S-shaped curves every plan and split here is the best only to the search's tolerance, a share
1e-9of its scale by default and never finer than 64 epsilons of the dtype, or as near asmax_boxesboxes come, 500 by default; a goal's, at each budget it tries. Sums of S-shaped curves under a budget are NP-hard to plan (Udell and Boyd 2016), so nothing short of that cap bounds the count of boxes, and many channels near their thresholds at once can reach it; the gap is then reported as it stands. Each box ofallocate's costs one bisection of the price, as a plan on concave curves does; each ofcvar_allocate's andminimax_allocate's up to 30 rounds of planes, every one a read of each reading on its envelopes and its curves and a linear program over the planes kept, one row a reading for every split tried; each ofallocate_geos' as many rounds of planes as close it, up to 500, every one a linear program over the planes on its cells and the totals. The bound on the first box's gap holds only as stated above: a longer kernel runs each period at its own adstock, and a floor or a cap inside a chord holds its channel there, each with an excess of its own. - A split for several readings is robust to the readings it is given and to no other: it hedges between the families the tests could not tell apart, not against one none of them is.
- A split for the worst share weighs every reading alike, as draws of a posterior are, and its share is of the readings, a probability only as far as they are a posterior's draws. Where they disagree on which way the budget should move, no move may gain on average in the worst share, and the split is then the reference.
- The decision weight is local: second order in the error, at the plan on the channels as given,
and a channel held at an end of its box carries no weight. One that would leave its end under a
small error costs more than
Wsays, aschc.experiment's pinned levers do. It is read on concave curves only. chc.mmm.prescribeplans a budget over a continuous plant whose adstock is a state; this plans discrete channels, which that plant does not describe.- Over geos and channels, a plan with a cell inside its box on a straight stretch of its curve (a linear curve, or an envelope's chord in a box of a search) is the cutting planes', within the search's tolerance of the bound or as near as 500 rounds come; its rates are as near the best as that gap allows, not exact to rounding, and its prices are the last program's duals, which certify the bound but need not be the best plan's where the program is degenerate and several prices nearly certify it. A searched plan is priced on the curves at the plan instead, by the prices that miss the conditions for the best plan least, the totals' misses first: its rates meet their prices only to the search's tolerance. In a search Newton's method on the prices stops at its first step that does not shrink the totals' miss: a chord holds its cell at an end of it at every price but its slope, and at that price the rate jumps across it, which a line search would circle. Where every geo's spend and every channel's are fixed, the split of the price between the geos' totals and the channels' is the one the solver reaches, or on S-shaped curves the one least in the sum of the prices' sizes; the sum each cell meets is the same however it is split. In single precision, JAX's default, Newton's method does not close and the cutting planes' plan comes back: its worth and bound are good to single precision, its rates only as near as the gap allows.
- A goal over geos and channels on an S-shaped curve is met where the searched plans' gain crosses it, not proved the least or the most budget: under totals the best plan's gain need not rise with the budget.
- A national channel's shares are the caller's and held fixed: the plan chooses how much to buy, not where it lands. Its bound over a box of its spend, the sum of its cells' envelopes, can stand above the sum's own envelope, so on S-shaped cells it may take more boxes than one cell's.
SearchStatus = Literal['closed', 'cap']
module-attribute
¶
Why a plan's search for the best stopped: closed, its bound within the search's tolerance of
its worth; cap, with the gap open at a limit (SearchLimit).
SearchLimit = Literal['max_boxes', 'rounds', 'unsolved']
module-attribute
¶
What stopped a search with its gap open: max_boxes, the caller's cap, where the next box's
split would plan past it; rounds, the 500 rounds of a box's cutting planes where no cut of the
box is left to close it: the one box of concave curves of cvar_allocate,
minimax_allocate and allocate_geos, or a box of allocate_geos' whose plan
holds every cell at an end of its interval; unsolved, a linear program HiGHS left unsolved
there, at its iteration limit or with its optimality conditions unmet, which ends that box's
planes.
Allocation
dataclass
¶
A plan's spend a period for each channel, what it returns, and what the budget is worth.
Attributes:
| Name | Type | Description |
|---|---|---|
spend |
ndarray
|
|
worth |
float
|
the channels' return on the plan over its periods and each kernel's length after. |
bound |
float
|
no plan in the box at the budget returns more on the channels; |
price |
float
|
the return on one more currency unit of budget: on concave curves the budget's shadow price, on S-shaped curves read on the curves at the plan, where the unit goes to the channel below its cap that returns the most a unit. |
budget |
float
|
what the plan spends over its periods. |
idle |
float
|
what the channels return over the same periods with nothing spent in the plan, the history's carryover alone. |
stopped |
SearchStatus
|
whether |
boxes |
int
|
how many boxes of the rates were planned: 1 for a plan on concave curves. |
gap |
float
|
|
relative_gap |
float
|
|
tolerance |
float
|
the gap the search closes at: the larger of |
floored |
bool
|
whether that floor, the dtype's rounding, raised the tolerance above the caller's. |
limit |
SearchLimit | None
|
what stopped a search with its gap open ( |
compile_seconds |
float
|
the seconds JAX spent compiling during the call: tracing, lowering and the backend's compile, none where every program was compiled before. |
search_seconds |
float
|
the rest of the call's seconds. Both are recorded, not promised. |
gain
property
¶
What the plan's spend adds to the channels' return: worth - idle.
ReturnTarget
dataclass
¶
The least budget whose plan gains amount, in the channels' units.
MarginalReturnTarget
dataclass
¶
The budget at which one more currency unit returns per_unit: below it a unit returns
more, past it less. On revenue, per_unit = 1 is where spend stops paying for itself.
ReturnOnSpendTarget
dataclass
¶
The most budget whose plan gains per_unit for each currency unit it spends: a target
return on ad spend, read on the gain.
MinimaxAllocation
dataclass
¶
A split chosen for the least worst regret over several readings of the channels.
Attributes:
| Name | Type | Description |
|---|---|---|
spend |
ndarray
|
|
best |
ndarray
|
|
regret |
ndarray
|
|
worst |
float
|
the largest regret, the split's. |
bound |
float
|
no split in the box at the budget has a worst regret below this, so
|
stopped |
SearchStatus
|
whether |
boxes |
int
|
how many boxes of the rates were searched: 1 where every curve is concave. |
gap |
float
|
|
relative_gap |
float
|
|
tolerance |
float
|
the gap the search closes at: the larger of |
floored |
bool
|
whether that floor, the dtype's rounding, raised the tolerance above the caller's. |
limit |
SearchLimit | None
|
what stopped the search with its gap open ( |
unsolved |
tuple[int, ...]
|
the iterations of each linear program HiGHS left unsolved, in the order they were solved; each left its box the bound of the programs before it. |
compile_seconds |
float
|
the seconds JAX spent compiling during the call, each reading's plan included: tracing, lowering and the backend's compile, none where every program was compiled before. |
search_seconds |
float
|
the rest of the call's seconds. Both are recorded, not promised. |
CvarAllocation
dataclass
¶
A split chosen for the most mean gain over a reference in the worst share of the readings.
Attributes:
| Name | Type | Description |
|---|---|---|
spend |
ndarray
|
|
gain |
ndarray
|
|
cvar |
float
|
the mean of the worst |
bound |
float
|
no split in the box at the budget has a |
stopped |
SearchStatus
|
whether |
boxes |
int
|
how many boxes of the rates were searched: 1 where every curve is concave. |
gap |
float
|
|
relative_gap |
float
|
|
tolerance |
float
|
the gap the search closes at: the larger of |
floored |
bool
|
whether that floor, the dtype's rounding, raised the tolerance above the caller's. |
limit |
SearchLimit | None
|
what stopped the search with its gap open ( |
unsolved |
tuple[int, ...]
|
the iterations of each linear program HiGHS left unsolved, in the order they were solved; each left its box the bound of the programs before it. |
readings |
int
|
how many readings the split was chosen over. |
compile_seconds |
float
|
the seconds JAX spent compiling during the call: tracing, lowering and the backend's compile, none where every program was compiled before. |
search_seconds |
float
|
the rest of the call's seconds. Both are recorded, not promised. |
AllocationWeight
dataclass
¶
How much a plan loses when the channels it is made on are wrong. Experimental.
Attributes:
| Name | Type | Description |
|---|---|---|
parameters |
tuple[str, ...]
|
|
matrix |
ndarray
|
|
allocation |
Allocation
|
the plan on the channels as given. |
pinned |
tuple[int, ...]
|
the channels held at an end of their box, whose parameters carry no weight. |
expected_regret(covariance)
¶
tr(W S) / 2 at covariance = S: what a plan made on estimates with that
covariance loses on average, to second order.
Raises:
| Type | Description |
|---|---|
ValueError
|
when |
Totals
dataclass
¶
Bounds on what each of several groups of cells spends over the plan, every period
together: least[k] <= periods * (group k's rates summed) <= most[k].
allocate_geos takes one for the geos, a geo's channels a group, and one for the
channels, a channel across the geos a group. A fixed spend is least == most; most may
be infinite, and a least of zero binds nothing a box does not.
Raises:
| Type | Description |
|---|---|
ValueError
|
on bounds that are not one |
National
dataclass
¶
A channel bought once for every geo: one spend a period, of which each geo's cell spends its share, as national media allotted by population is.
allocate_geos and budget_for_geos take one for each national channel, keyed by
the channel's column in the grid. The plan chooses the national spend a period, between
lower and upper; geo g's cell of the channel spends shares[g] of it and reads
that on its own curve, carryover and history. The cells have no box of their own.
Attributes:
| Name | Type | Description |
|---|---|---|
shares |
ndarray
|
|
lower, |
upper
|
the least and the most national spend a period. |
Raises:
| Type | Description |
|---|---|
ValueError
|
shares that are not one a geo, each positive and finite, summing to 1 within
as many epsilons as there are shares: rounding, as shares a population divides into
leave; bounds that are not finite with |
GeoAllocation
dataclass
¶
A plan's spend a period for each geo's channels, what it returns, and what each constraint is worth.
Attributes:
| Name | Type | Description |
|---|---|---|
spend |
ndarray
|
|
worth |
float
|
the cells' return on the plan over its periods and each kernel's length after. |
bound |
float
|
no plan meeting the constraints and spending as much returns more on the cells;
|
price |
float
|
the return on one more currency unit of budget; |
geo_prices |
ndarray
|
|
channel_prices |
ndarray
|
|
budget |
float
|
what the plan spends over its periods. |
idle |
float
|
what the cells return over the same periods with nothing spent in the plan, the history's carryover alone. |
stopped |
SearchStatus
|
whether |
boxes |
int
|
how many boxes of the rates were planned: 1 where every curve is concave. |
gap |
float
|
|
relative_gap |
float
|
|
tolerance |
float
|
the gap the search closes at: the larger of |
floored |
bool
|
whether that floor, the dtype's rounding, raised the tolerance above the caller's. |
limit |
SearchLimit | None
|
what stopped the search with its gap open ( |
compile_seconds |
float
|
the seconds JAX spent compiling during the call: tracing, lowering and the backend's compile, none where every program was compiled before. |
search_seconds |
float
|
the rest of the call's seconds. Both are recorded, not promised. |
gain
property
¶
What the plan's spend adds to the cells' return: worth - idle.
allocate(channels, budget, periods, *, lower, upper, history=None, rtol=1e-09, atol=0.0, max_boxes=500)
¶
Spend budget over periods at one rate a period for each channel, for the most return.
Exact where every curve is concave; on S-shaped curves the best to the tolerance rtol and
atol set, by branch and bound (see the module).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
channels
|
Sequence[Channel]
|
the channels, each read as given. |
required |
budget
|
float
|
what the plan spends over its periods, every channel together. |
required |
periods
|
int
|
how many periods the plan runs. |
required |
lower, upper
|
|
required | |
history
|
ArrayLike | None
|
|
None
|
rtol
|
float
|
the share of the first box's bound the search closes the gap to. |
1e-09
|
atol
|
float
|
the gap the search closes to, in the channels' units. The search stops at the
larger of the two, but not below 64 epsilons of the dtype the curves are read in, of
the first box's bound: there the gap is rounding ( |
0.0
|
max_boxes
|
int
|
the most boxes the search plans. A box is cut only where its halves fit within the count. |
500
|
Raises:
| Type | Description |
|---|---|
TypeError
|
a channel is not a |
ValueError
|
a curve the bisection cannot certify on (see the module's scope), a negative
coefficient, a box or history of the wrong shape, a box with |
budget_for(channels, goal, periods, *, lower, upper, history=None, rtol=1e-09, atol=0.0, max_boxes=500)
¶
The budget that meets goal, and the plan allocate makes with it.
A plan's gain is Allocation.gain, what its spend adds to the channels' return over its
periods and each kernel's length after. Where every curve is concave, as the budget grows every
rate rises along one path of plans, and each goal is a point on it:
ReturnTarget: the least budget whose plan gainsamount. The gain rises along the path, so the budget is exact.MarginalReturnTarget: the rates at which each channel's slope meetsper_unit, or the end of its box it presses on. Where a channel's return is linear with that slope, its least rate.ReturnOnSpendTarget: the most budget whose gain isper_unittimes the budget or more. The gain lessper_unita unit is concave in the budget and peaks at the marginal target's budget, so past that budget it falls, and the most budget is where it falls through nothing. The average can rise before the peak, where a floor holds spend on a channel that returns little a unit, so it can meet the target at a smaller budget too; that one is not returned.
Where a curve is S-shaped the plans are allocate's search at each budget, and no one
path holds them; the best plan's gain still rises with the budget, but it need not be concave
in it. A return target is met by Brent's method on the budget, between the floors and the caps,
where the searched plan's gain crosses it: the least budget, since that gain rises. A marginal
target is the budget of the best plan with the budget free and each currency unit charged
per_unit, searched in boxes as allocate searches a budget: no budget gains more less
its charge, so below it a unit returns more on average and past it less. A return on spend is
met where the searched gain less per_unit a unit falls through nothing past that peak, by
Brent's method; refused where the peak falls short, but past the peak the gain need not fall
all the way, and the budget is not proved the most.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
channels, periods, lower, upper, history
|
as |
required | |
goal
|
Goal
|
what the budget must meet. |
required |
rtol, atol, max_boxes
|
each plan's search's, as |
required |
Raises:
| Type | Description |
|---|---|
TypeError
|
|
ValueError
|
what |
minimax_allocate(readings, budget, periods, *, lower, upper, history=None, rtol=1e-09, atol=0.0, max_boxes=500)
¶
Spend budget for the least worst regret over readings of the channels.
Each reading is a whole set of channels, one a column, as allocate takes them: the same
channels read another way, by another curve family, say. The regret of a split under a reading
is the reading's best return at the budget over the split's, both on its curves, the best being
the return of allocate's plan for the reading. The split returned has the least worst
regret, to the tolerance rtol and atol set, or as near as 500 rounds of cutting planes
come on concave curves and max_boxes boxes of the rates past them;
MinimaxAllocation.stopped says which, and MinimaxAllocation.limit what stopped
it. A program HiGHS leaves unsolved, one it stalls on stopped by an iteration limit, leaves its
box the bound of the programs before it.
The worst regret is the least of the readings' gains over their bests, negated: the worst share
cvar_allocate maximises, at one reading of them, each gain read against the reading's
best in place of a reference's return. It is searched as cvar_allocate searches that
share, from every reading's own plan. A reading's regret is convex in the split where its curves
are concave, so the worst is too: the cutting planes are every reading's tangents at every split
tried, the linear program over them bounds the worst regret from below, and each split it
proposes is tried next. Where a curve is S-shaped the rates are searched in boxes, each box's
planes cut on each curve's envelope over the box, which stands above the curve, so they bound
every split in the box. MinimaxAllocation.bound is read from HiGHS's duals on each
program as written and rounded down, not HiGHS's objective, which can stand above the program's
least; worst is the best split's, so the gap between them is what the split may still be
from the least worst regret. A reading's own plan returns its best, so no worst regret is below
nothing where each best is exact; on S-shaped curves, below the least of the readings' own
searches' gaps, negated. A reading's own search that stops at its cap logs a warning as
allocate does.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
readings
|
Sequence[Sequence[Channel]]
|
the readings, each with one channel a column; at least one. |
required |
budget, periods, lower, upper, history
|
as |
required | |
rtol
|
float
|
the share of the largest best return the search closes the gap to, and each reading's own plan's search the share of its first box's bound. |
1e-09
|
atol
|
float
|
the gap the search closes to, in the channels' units, and each reading's own plan's
search. The search stops at the larger of the two, but not below 64 epsilons of the
dtype the curves are read in, of the largest best return: there the gap is rounding
( |
0.0
|
max_boxes
|
int
|
the most boxes the search plans, and each reading's own plan's search. A box is cut only where its halves fit within the count. |
500
|
Raises:
| Type | Description |
|---|---|
(TypeError, ValueError)
|
what |
cvar_allocate(readings, budget, periods, *, level, against, lower, upper, history=None, rtol=1e-09, atol=0.0, max_boxes=500)
¶
Spend budget for the most mean gain over against in the worst level share of
readings of the channels: the gain's conditional value at risk.
Each reading is a whole set of channels, one a column, as minimax_allocate takes them: a
posterior's draws, say, weighed alike. A split's gain under a reading is its return less the
reference's, both on the reading's curves, and the split returned has the most mean gain over
the worst level share of the readings, to the tolerance rtol and atol set, or as
near as 500 rounds of cutting planes come on concave curves and max_boxes boxes of the
rates past them; CvarAllocation.stopped says which, and CvarAllocation.limit
what stopped it. A program HiGHS leaves unsolved, one it stalls on stopped by an iteration
limit, leaves its box the bound of the programs before it. The reference spends the budget in
the box and gains nothing under any reading, so the split returned never does worse in that
share than keeping it. At level = 1 the split has the most mean gain, the posterior's
expected return; as the level falls it moves only as far as the worst readings agree it gains.
The mean of the worst share is max_eta eta - E[(eta - gain)_+] / level (Rockafellar and
Uryasev 2000), concave in the split where every curve is concave. The cutting planes (Kelley
1960) are every reading's tangent at every split tried, starting from the reference, and the
linear program over them bounds the most from above; its solution, moved onto the budget, is
the next split tried.
Where a curve starts convex the rates are searched in boxes, as allocate searches them
(Udell and Boyd 2016). In a box the planes are cut on each curve's envelope over the box, which
stands above the curve and is concave in the rate, so the program bounds every split in the box,
and each split it proposes, read on the curves, is a candidate. The box of the largest bound is
cut first, on the channel whose envelope stands furthest above its curve at the box's best
split on the envelopes, each reading weighed as the worst share weighs it there, since the
share's mean gain on the envelopes exceeds the curves' by no more than that weighed excess
(the risk envelope's dual). A box's planes stop after 30 rounds, or once their bound is within
half the box's gap to the best split of its best on the envelopes, and the box is cut instead;
a box's planes bound its halves too, so they carry over, those the last program left slack
dropped. Two Hill curves of slope 3 at scales 1 and 1.01, a budget of 1.6 and the reference all
on the first: on the envelopes the planes propose [1.27, 0.33], which returns 0.705 against
the reference's 0.804, and the search closes on the reference, its cvar 0.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
readings
|
Sequence[Sequence[Channel]]
|
the readings, each with one channel a column; at least one. |
required |
budget, periods, lower, upper, history
|
as |
required | |
level
|
float
|
the share of the readings, the worst, whose mean gain the split maximises, in
|
required |
against
|
ArrayLike
|
|
required |
rtol
|
float
|
the share of the reference's largest return the search closes the gap to. |
1e-09
|
atol
|
float
|
the gap the search closes to, in the channels' units. The search stops at the
larger of the two, but not below 64 epsilons of the dtype the curves are read in, of
the reference's largest return: there the gap is rounding
( |
0.0
|
max_boxes
|
int
|
the most boxes the search plans. A box is cut only where its halves fit within the count. |
500
|
Raises:
| Type | Description |
|---|---|
(TypeError, ValueError)
|
what |
decision_weight(channels, budget, periods, *, lower, upper, history=None)
¶
How much allocate's plan loses when the channels it is made on are wrong.
Experimental.
The arguments are allocate's, and so is the plan. Each channel's parameters are its
inexact leaves, the kernel's, the curve's and the coefficient. Inside their boxes the rates meet
at the budget's price, V_c'(u_c) = periods * price; an error d_c in channel c moves
its rate by g_c d_c / h_c, g_c the slope's gradient in its parameters and h_c the
worth's curvature -V_c'', and the price moves every rate back by the share (1/h_c) /
sum(1/h) of the total, so the budget stays spent. The first-order loss is nil, since the
slopes are equal and the moves sum to nothing, and the second is du' diag(h) du / 2, which
is d' W d / 2. validation/allocation_decision_weight.mac holds it to the Hessian of the
realised loss for two exponential and two Michaelis-Menten channels.
Raises:
| Type | Description |
|---|---|
(TypeError, ValueError)
|
as |
allocate_geos(cells, budget, periods, *, lower, upper, geo_totals=None, channel_totals=None, national=None, history=None, rtol=1e-09, atol=0.0, max_boxes=500)
¶
Spend budget over periods on every geo's channels at once, for the most return.
Each cell, one geo's channel, runs at one rate a period as allocate's channels do, its
worth counted the same way, carryover in from its history and out after the plan. The budget is
spent exactly; each geo's spend over the plan, its channels together, stays within
geo_totals, and each channel's, its geos together, within channel_totals.
A channel bought once for every geo (National) is one rate, its national spend a
period, within its own box: each geo's cell spends its share of it. The plan chooses that rate
as it chooses a cell's. Its worth is its cells' summed, each reading its share, and it counts in
the budget and its channel's total whole and in each geo's total by the geo's share. Inside its
box it returns, a currency unit, the budget's price plus its channel's and each geo's weighted
by the geo's share.
The plan is found by cutting planes on the cells' worths, each bounded above by its tangents
under a linear program, until the program's bound is within the tolerance rtol and atol
set of the best plan it has proposed, or after 500 rounds, or at a program HiGHS leaves
unsolved, one it stalls on stopped by an iteration limit; a first program left so is refused.
Where every cell inside its box is then strictly concave, Newton's method on the prices of the
totals that bind closes the budget and those totals with each cell's rate exact at its prices;
a step that does not bring them closer is replaced by the least of the dual, convex in the
prices, along it. A total whose price comes out on the wrong side is released and one the plan
breaks is bound, until each binding total's price has its side's sign and the others hold: the
conditions for the best plan on concave worths.
Otherwise the cutting planes' best plan is returned, with the least bound their programs gave.
Each program's bound is read from HiGHS's duals and rounded up, not HiGHS's objective, which
can fall below the program's most.
Where a curve is S-shaped the rates are searched in boxes, as allocate searches them
(Udell and Boyd 2016). In a box each cell's worth is bounded by its envelope over the box,
concave in the rate, above the curve and equal to it at both ends, and the planes on those
envelopes bound every plan in the box, under the same totals; their plan, read on the curves,
is a plan. The box of the largest bound is cut first, on the cell inside its interval whose
envelope stands furthest above its curve at the box's plan, at its rate there, so that both
halves hold that plan. GeoAllocation.bound is the largest bound left when every bound is
within the tolerance of the best plan's worth, or once the next cut would plan past
max_boxes boxes; GeoAllocation.stopped says which, and a search the cap stops logs a
warning (chc_event="allocation_cap") with its gap. A national channel's worth over a box of
its spend is bounded by its cells' envelopes over the box, summed, and it is cut as a cell is.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cells
|
Sequence[Sequence[Channel]]
|
one row a geo, each with the same channels in the same order. |
required |
budget, periods
|
as |
required | |
lower, upper
|
|
required | |
geo_totals
|
Totals | None
|
what each geo spends over the plan, its channels together; no bound when omitted. |
None
|
channel_totals
|
Totals | None
|
what each channel spends over the plan, its geos together; no bound when omitted. |
None
|
national
|
Mapping[int, National] | None
|
the channels bought once for every geo, each by its column in the grid; none when omitted. |
None
|
history
|
ArrayLike | None
|
|
None
|
rtol, atol, max_boxes
|
as |
required |
Raises:
| Type | Description |
|---|---|
TypeError
|
a cell is not a |
ValueError
|
what |
budget_for_geos(cells, goal, periods, *, lower, upper, geo_totals=None, channel_totals=None, national=None, history=None, rtol=1e-09, atol=0.0, max_boxes=500)
¶
The budget that meets goal over every geo's channels, and the plan
allocate_geos makes with it.
The budgets run from the least to the most a plan within the boxes and the totals spends. On concave curves the best plan's gain is concave in the budget, and its slope there is the budget's price; each step below is one plan. Under totals the gain can fall past some budget: a cap on a geo and one on a channel can leave the last of the budget only to cells that return less than the spend they take from a cell in both.
ReturnTarget: the least budget whose plan gainsamount, by Newton's method on the budget from the least, whose steps a concave gain keeps short of the target. Refused above the most any plan gains, the plan with nothing charged for its spend.MarginalReturnTarget: one plan, its budget left free and each currency unit it spends chargedper_unitof return: every cell inside its box then returnsper_unita unit plus its totals' prices, a national channelper_unitplus its channel's and each geo's weighted by its share, and the budget is what the plan spends, an end of the budgets where the price stays on one side ofper_unitacross them.ReturnOnSpendTarget: the most budget whose gain isper_unittimes the budget or more. The gain lessper_unita unit is concave in the budget and peaks where the price isper_unit, so past that budget it falls, and the most budget is where it falls through nothing: Newton's method from the most budget.
On an S-shaped curve each plan is allocate_geos' search at its budget, and the best
plan's gain need not be concave in the budget: a return target and a return on spend are met
where that gain crosses them, by Brent's method between budgets either side, and neither is
proved the least or the most. The marginal target's plan is searched with its budget free.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cells, periods, lower, upper, geo_totals, channel_totals, national, history
|
as
|
required | |
goal
|
Goal
|
what the budget must meet. |
required |
rtol, atol, max_boxes
|
each plan's search's, as |
required |
Raises:
| Type | Description |
|---|---|
TypeError
|
|
ValueError
|
what |