ES
← Back to Portfolio
Mining & Optimization August 2026

PhaseFlow, Open-Pit Production Schedule with a Certified Bound

An open-pit production schedule, solved with a certified bound and animated year by year over the block model. PitForge answers which blocks are worth mining; PhaseFlow answers when, subject to slope precedence in every period and per-period mining and processing capacity, maximising discounted NPV. That is the constrained pit limit problem (CPIT). The trust anchor is the published MineLib newman1.cpit solved AS PUBLISHED, on its own six periods, its own eight percent discount rate and its own two capacities: it reproduces the ultimate pit optimum exactly (26,086,899) and its joint LP bound sits at 24,486,184 against the published 24,486,549. The bound needs no LP solver (critical multiplier algorithm, exact in O(mn log n) as parametric maximum closures), which is why the whole problem re-solves live in the browser. Two bounds run on every case and the difference between them is reported, because that difference is the part of a gap that belongs to the bound rather than to the plan.

What it solves
CPIT: when to mine each block, under per-period slope precedence and mining/processing capacity, maximising discounted NPV
The bound
Critical multiplier algorithm (Chicoisne et al. 2012, doi:10.1287/opre.1120.1050): the CPIT LP relaxation exactly in O(mn log n) as parametric maximum closures, no LP solver
Live lane
A TypeScript port re-solves the whole problem in the browser, so discount rate, capacities and slope angle move the answer; a parity test asserts it reproduces the Python bound
Mineability as a KPI
Components per period, largest-component share and narrowest mined run, reported per case; the pit wall carries the schedule colour at every frame (33% of what is visible from outside at the final frame, against 0% for a carve-away rendering)
Honest scope
No stockpiles (the blended-grade model is bilinear), no blending or general side constraints, no minimum-production constraints, no two-stage stochastic IP. Not for production mine planning
Engine and deploy
oreblocks (published separately on PyPI, consumed pinned; PhaseFlow declares no package of its own); React 19 + Vite SPA on GitHub Pages, MIT; part of the Faena hub
Architecture diagram of PhaseFlow, Open-Pit Production Schedule with a Certified Bound
#mining-optimization #mine-planning #scheduling #cpit #lagrangian-bound #max-flow #three-js #minelib #mining

Business Context

A production schedule is where a mine plan turns into money and into commitments: it sets the NPV the project is valued on, the equipment fleet that has to exist each year, and the feed the plant will actually see. The value of a certified bound is that it converts a number into a statement with a limit attached, so the discussion moves from whether an NPV is believable to how much value is provably still on the table. Reporting both bounds is the same discipline applied one level deeper: it tells you whether the remaining gap is a weakness in the plan or slack in the mathematics used to measure it. Spatial coherence matters for the same practical reason: a schedule that scatters a period into many small components is expensive or impossible to actually mine, and the app reports components per period, largest-component share and the narrowest mined run as first-class KPIs rather than leaving mineability to a reviewer eyeballing a picture.

Strategic Value

PhaseFlow is the scheduling step of the open-pit line, and it earns trust by being measurable against work that is not its own. It solves a published MineLib instance as published and puts its numbers beside the published ones, including the gap where it does worse. It computes its bound without an LP solver, which is what makes a genuine live lane possible rather than a replay. It runs two bounds on every case and reports their difference, so a gap can be attributed to the plan or to the bound. It treats spatial coherence as a KPI because the algorithm authors themselves predict block-level schedules scatter. And its learned lane is characterised rather than only measured: the obvious hypothesis for the surrogate worst case (0.344, on an orebody archetype) was REFUTED by the held-out deposits, and what survived is a scenario reading with a mechanism, shipped as a guard (discount rate at or above 0.15) that travels with the method in the artifact and in the selector rather than as a warning on a documentation page. The honest scope is stated in the product: no stockpiles, no blending, no minimum-production constraints, no two-stage stochastic integer programming, and not for production mine planning. The engine is the separately published oreblocks package, consumed pinned; the product declares no package of its own.

The Challenge

Knowing which blocks are worth mining is only half of an open-pit plan. The other half is when: a schedule that respects slope precedence in every period, stays inside the mining and processing capacity of each year, and maximises discounted value. That is the constrained pit limit problem, and it is NP-hard, so nobody solves it to proven optimality at real size. The consequence is that a scheduling tool can report any NPV it likes and sound convincing, because without a bound there is nothing to compare the number against. Reporting a gap does not fix this on its own either: a gap is the distance between a plan and a bound, so a loose bound makes a good plan look bad and hides which half of the number is actually the problem. And a schedule that looks optimal on a spreadsheet can be unmineable in practice if the periods scatter into disconnected fragments across the pit.

Our Approach

PhaseFlow anchors itself to a published instance solved as published. The MineLib newman1.cpit case runs on its own six periods, its own eight percent discount rate and its own two capacities, and the results sit next to the published ones (Jelvez, Morales and Nancel-Penard, MPES 2018): the ultimate pit optimum reproduces exactly at 26,086,899, the joint LP bound lands at 24,486,184 against a published 24,486,549 PCPSP LP bound, and the shipped optimality gap is 2.49 percent against a published 1.26 percent, which is stated rather than smoothed over. The check that the bound is real is its ORDERING: a CPIT LP bound must sit below a PCPSP LP bound because PCPSP is the richer problem, and it does, by 365 units in 24.5 million. The bound needs no LP solver at all: the critical multiplier algorithm (Chicoisne et al. 2012) solves the CPIT LP relaxation exactly in O(mn log n) as a sequence of parametric maximum closures, which is exactly why a TypeScript port can re-solve the whole problem live in the browser with a parity test asserting it reproduces the Python bound. Two bounds run on every case: a certified but LOOSE one that relaxes the resources one at a time, and the JOINT Bienstock-Zuckerberg bound; the app shows both and names which one it used, because the difference between them is the part of a reported gap that belongs to the bound rather than to the plan. On a single-resource instance the two agree to machine precision, which is the strongest correctness check in the repository. A learned expected-time surrogate produces an ExTS-quality schedule with no LP solve, which is what makes an uncertainty ensemble affordable, and it is split by DEPOSIT seed rather than by row.

Key Performance Indicators

KPIBaselineResultImpact
A published instance, solved as publishedInvent a scenario and report an NPV with nothing to compare it againstMineLib newman1.cpit on its own 6 periods, 8% rate and 2 capacities: ultimate pit 26,086,899 (exact match), joint LP bound 24,486,184 vs published 24,486,549; gap 2.49% vs a published 1.26%, stated not smoothedThe numbers are checkable against work that is not mine, including where mine is worse
Two bounds, and the difference between themOne bound, so a reported gap mixes a weak plan with a loose boundA certified-but-loose one-resource-at-a-time bound AND the joint Bienstock-Zuckerberg bound on every case, both shown with the one used named; they agree to machine precision on a single-resource instanceA gap can be attributed to the plan or to the mathematics measuring it
A refuted hypothesis, shipped as a guardReport a worst case as a footnote and never say when it happensThe surrogate worst case is 0.344; the orebody-archetype explanation was refuted by the held-out deposits, and the surviving scenario reading ships as a rule (discount rate >= 0.15) that catches 5 of 5 held-out failures, with no unflagged case below 93%The caveat travels with the method where it is chosen, not on a docs page

Architecture

phaseflow pipeline

phaseflow pipeline

Technology Stack

Python oreblocks NumPy TypeScript React Vite three.js MineLib

In action

A short tour of the live app: the real interface, recorded from the deployed site.

PhaseFlow, Open-Pit Production Schedule with a Certified Bound in action

Application Screenshots

PhaseFlow, Open-Pit Production Schedule with a Certified Bound
PhaseFlow, Open-Pit Production Schedule with a Certified Bound