mixle.analysis.objective module¶
J6 – priced-liability and hard-constraint assembly for a MILP-based selection objective: wiring, not new physics (work-plan Sec.7-J, the grand synthesis).
A general pattern for any per-item binary-selection MILP (mixle.stochastic_opt.
two_stage_stochastic_plan() is this module’s worked instantiation, turning grade uncertainty – IC-1
Posterior.samples – into a CVaR-penalized block-extraction decision): several independent
“pricing” tasks each want to add one more externality term or hard constraint to the same objective
without knowing about each other – J2’s monte_carlo_npv (revenue/cost DCF), a G9-style no-mine/
buffer zone, a K6-style public-health exposure cost, an L6-style carbon/emissions price, an N6-style
biodiversity offset (mixle.analysis.biodiversity.habitat_offset_liability/no_net_loss_constraint,
already landed and explicitly written against this module’s shape). None of those tasks are this
module’s dependency – this is the reverse: J6 is the pluggable framework they register priced
terms/constraints INTO, so the dependency edge runs G9/K6/L6/N6 -> J6, never J6 -> them
(workstream-J.md J6 header note). That means this module only fixes the shape a priced term or a
hard constraint must have to plug in; it derives none of the underlying cost models itself
(Non-goals).
Two pieces:
priced_liabilities()– nets a plan’s per-block environmental/health/carbon externalities (remediation, health, carbon) into one additive per-block dollar array ("total") plus the raw per-term breakdown, in exactly the shapemixle.stochastic_opt.risk_adjusted_plan()consumes via itsliabilitiesparameter (liabilities["total"], subtracted from per-block revenue before the MILP solves) – and the same shape any other priced term (N6’shabitat_offset_liability, or a future workstream’s) adds itself into, without ever importing this module.
hard_constraints()– assembles theconstraintsdict risk_adjusted_plan consumes: an optional hardno_mine_mask(G9 no-mine/buffer polygons – blocks forced tox_b = 0) and an optional list of linear activitycaps(K6 exposure budgets, L6 water budgets –coeffs @ x <= boundrows over the block decision vector), normalizing any">="-sense cap into the solver’s standard<=convention.
- hard_constraints(*, no_mine_mask=None, caps=None)[source]
Assemble the
constraintsdictmixle.stochastic_opt.risk_adjusted_plan()consumes.no_mine_mask: an optional boolean array-like, lengthn_blocks.Trueentries are a G9-style no-mine/buffer-zone polygon’s enclosed blocks – hard-fixed tox_b = 0(stronger than an inequality row: those blocks can never be selected, regardless of the rest of the objective).caps: an optional list of linear activity caps – a K6 exposure budget, an L6 water budget, or any othercoeffs @ x <sense> boundrow over the block decision vector. Each entry is a dict with"coeffs"(length-n_blocksarray-like) and"bound"(float), plus an optional"sense"("<="by default;">="is negated into the solver’s standard<=form sorisk_adjusted_plannever has to special-case it). This is the samecoeffs/bound/sensefield namingmixle.analysis.biodiversity.no_net_loss_constraint()already uses for its own linear-constraint payload.
Returns a dict with whichever of
"no_mine_mask"/"caps"were supplied (both are omitted, i.e. an empty dict, when neither argument is given – meaning no hard constraint at all).- Raises:
ValueError – if
no_mine_maskis not a genuine 1-D boolean array (data that is merely truthy under an implicit bool cast, e.g. a float array or a NaN entry, is rejected rather than silently coerced), if any cap’s"coeffs"is not a finite 1-D array, if any cap’s"bound"is not finite, or if a cap’s"sense"is not"<="/">=".- Parameters:
- Return type:
- priced_liabilities(plan, *, carbon_price, health_cost, remediation_cost)[source]
Net a plan’s per-block environmental/health/carbon liabilities into one additive dollar array.
planis a mapping or attribute-bearing object exposing three per-block, length-n_blocksarray-likes:grade: the block grade (or other geology/complexity proxy) fed toremediation_cost– a G9-style environmental remediation-cost model keyed on what is actually mined.exposure: the block’s public-health exposure proxy fed tohealth_cost– a K6-style health-cost model.emissions: the block’s carbon-equivalent emissions, priced directly atcarbon_price(an L6-style market/regulatory carbon price is a multiplier, not a fitted cost model, so no callable is needed for it).
Returns a dict with per-block arrays
"remediation","health","carbon", their elementwise sum"total"(the single per-block liabilitymixle.stochastic_opt.risk_adjusted_plan()nets out of revenue), and the scalar roll-ups"remediation_total"/"health_total"/"carbon_total"/"grand_total"for reporting.Every
planfield is validated BEFORE it is handed to a cost callable (MXR-080-1573). The callables are opaque user code: a model that ignores its argument, saturates, or returns a constant turns a NaN grade or an infinite exposure into a perfectly ordinary finite cost, so the invalid source evidence disappears and the resulting liability record carries no trace that the plan it was priced from was malformed.grade/exposureare checked for finiteness only, not sign – both are declared as arbitrary geology/complexity and exposure proxies, so a negative value is a legitimate reading; it is only the prices that carry the non-negativity convention.Every assembled output is likewise validated after the fact: three individually finite per-block costs near the float64 ceiling can overflow
total, and finite per-block totals can overflowgrand_total’s reduction, publishing an infinite liability from a record that claims to be validated (MXR-080-1573).- Raises:
ValueError – if
carbon_price,plan’semissions, or either cost callable’s return value is non-finite or negative – a negative liability would net out of revenue as a profit increase rather than a cost, and a NaN would propagate unguarded into the objective – ifplan’sgrade/exposureis non-finite, if any ofplan’sgrade/exposure/emissionsor a cost callable’s return value has the wrong shape, or if the netted per-blocktotalor any scalar roll-up is not representable in float64.- Parameters:
- Return type: