mixle.blending module¶
Blending: minimum-cost mixture of several sources hitting a target attribute window.
A blend draws quantity w_s from each of several sources (stockpiles, batches, parcels), each
with its own per-attribute grade and unit cost, to hit a target window on the combined material’s
attributes – spec_lo[e] <= (sum_s w_s grades[s,e]) / sum_s w_s <= spec_hi[e] for every attribute
e – at minimum blending cost. Fixing the total blended quantity to the requested demand
linearizes the otherwise-fractional ratio constraint into a pair of linear inequalities, so the whole
problem is a linear (or, with a minimum-parcel floor per source, mixed-integer) program solved by
mixle.relations.branch_and_bound_milp(). When the spec window cannot be met by any blend of the
given sources, mixle.relations.irreducible_infeasible_subset() names the conflicting
constraint rows – which attribute window, high or low, is unmeetable – rather than just reporting
“infeasible”.
This is the classic blending problem of operations research: fuel/petroleum blending (octane rating), feed formulation (protein/nutrient content), alloy composition, and ore blending & grade control (the worked example below) all reduce to the identical LP/MILP – sources, a per-attribute grade matrix, and a target window, nothing domain-specific in the construction itself.
>>> import numpy as np
>>> grades = np.array([[0.50], [0.55], [0.65], [0.70]]) # Fe fraction per stockpile
>>> costs = np.array([10.0, 12.0, 15.0, 18.0])
>>> avail = np.array([1000.0, 1000.0, 1000.0, 1000.0])
>>> cost, tonnage = blend_to_spec(grades, costs, [0.58], [0.62], avail, 1000.0)
- blend_to_spec(grades, costs, spec_lo, spec_hi, avail, demand, *, min_parcel=None)[source]
Minimum-cost blend hitting a target attribute window, drawing quantity from several sources.
gradesis(n_sources, n_elements),costs/availare lengthn_sources,spec_lo/spec_hiare lengthn_elements. The blend must totaldemandunits and, for every attributee,spec_lo[e] <= blended_grade[e] <= spec_hi[e]. Solved as an LP by default (branch_and_bound_milpwith no integer variables -> the HiGHS relaxation); passmin_parcelto additionally require that any source actually drawn from contributes at least that many units (a discrete parcel-draw floor), which turns it into a MILP.Returns
(min blend cost, per-source tonnage). RaisesValueError– naming the conflicting constraint rows frommixle.relations.irreducible_infeasible_subset()– when no blend of the given sources can meet the spec window at the requested tonnage.
- blend_feasibility(grades, spec_lo, spec_hi, avail, demand)[source]
Whether some blend of the sources can meet the spec window at
demandunits, cost aside.Returns
Nonewhen feasible. Otherwise returns the row indices of an irreducible infeasible subset (mixle.relations.irreducible_infeasible_subset()) of the linearized spec-window / total-quantity system – the minimal set of conflicting constraints, i.e. which attribute’s window (and whether its floor or ceiling) cannot be reached given the sources on hand.