Metadata-Version: 2.4
Name: oreblocks
Version: 0.6.1
Summary: Synthetic 3D ore-body block models of the MineLib nature and their scheduling: seeded deposit archetypes, bench structure, slope precedence, UPIT economics, an exact max-closure solver, MineLib .blocks/.prec/.upit/.cpit/.pcpsp read/write, the certified CPIT LP bound by the critical multiplier algorithm, TopoSort rounding heuristics and spatial-coherence metrics
Author: Felipe Santibanez-Leal
License: MIT
Project-URL: Repository, https://github.com/fsantibanezleal/CAOS_OreBlocks
Project-URL: Changelog, https://github.com/fsantibanezleal/CAOS_OreBlocks/blob/main/CHANGELOG.md
Project-URL: Issues, https://github.com/fsantibanezleal/CAOS_OreBlocks/issues
Keywords: mining,block-model,ore-body,ultimate-pit,UPIT,MineLib,open-pit,mine-planning,max-closure,synthetic-data,production-scheduling,CPIT,PCPSP,optimization,Bienstock-Zuckerberg,cutoff-grade,stochastic
Classifier: Development Status :: 3 - Alpha
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.26
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: ruff>=0.4; extra == "dev"
Requires-Dist: scipy>=1.11; extra == "dev"
Provides-Extra: milp
Requires-Dist: scipy>=1.11; extra == "milp"
Dynamic: license-file

# oreblocks

[![CI](https://img.shields.io/github/actions/workflow/status/fsantibanezleal/CAOS_OreBlocks/ci.yml?branch=main&label=CI)](https://github.com/fsantibanezleal/CAOS_OreBlocks/actions)
[![License](https://img.shields.io/github/license/fsantibanezleal/CAOS_OreBlocks)](LICENSE)
[![Version](https://img.shields.io/github/v/tag/fsantibanezleal/CAOS_OreBlocks?label=version&sort=semver)](https://github.com/fsantibanezleal/CAOS_OreBlocks/tags)
[![DOI](https://img.shields.io/badge/DOI-10.5281%2Fzenodo.21512088-blue)](https://doi.org/10.5281/zenodo.21512088)

Software note (CC-BY-4.0): *"oreblocks: License-Free Synthetic Ore-Body Block Models with a Stamped Exact
Ultimate-Pit Optimum"*, concept DOI [10.5281/zenodo.21512088](https://doi.org/10.5281/zenodo.21512088) (source in
[`manuscripts/ore-body-twins/`](manuscripts/ore-body-twins/)). It gives the deposit archetypes, the exact
max-closure ultimate-pit solver, and an independent LP cross-check to machine precision (~1e-15).

**Synthetic 3-D ore-body block models of the MineLib nature, and their scheduling**, seeded deposit
archetypes with per-block grades, bench (level) structure, slope precedence, UPIT economics with
per-block optimal destination, an **exact max-closure solver**, extraction states with **loading
faces**, MineLib `.blocks/.prec/.upit/.cpit/.pcpsp` **read/write**, the **certified CPIT LP bound**
by the critical multiplier algorithm, the **TopoSort** rounding heuristics, and **spatial-coherence**
metrics. Deterministic given a seed; every generated instance is clearly labelled SYNTHETIC.

Why: per-block ground truth on real mines is licensed or proprietary (MineLib grants academic
download only, no redistribution). oreblocks generates instances of the same *nature*, 3-D
benches, grades, precedence, net values, with a **stamped exact optimum**, so solvers, dispatch
simulators and teaching apps get license-free realistic instances with known-by-construction
answers.

## Install

```bash
pip install oreblocks
```

## Quickstart: a MineLib-format twin with a stamped optimum

```python
from oreblocks import make_twin

twin = make_twin("porphyry", dims=(20, 20, 10), seed=42)
print(twin.upit.pit_value, twin.upit.n_in_pit)   # the EXACT optimum, stamped
twin.write("out/")   # -> twin-*.blocks / .prec / .upit / .meta.json (MineLib format)
```

The emitted triplet is byte-consumable by any MineLib UPIT reader. Cross-validated against an
independent TypeScript min-cut engine (CAOS PitForge, which reproduces the published newman1 /
zuck_small / kd optima): relative disagreement ~1e-11 on a 4,000-block twin.

## Scheduling: which blocks, and WHEN

The ultimate pit says which blocks are worth mining. The **constrained pit limit problem** (CPIT)
says when: assign every block a period so slope precedence holds in every period, per-period
capacities hold, and discounted value is maximised. It is NP-hard, so what ships is a **certified
upper bound** plus **feasible schedules**, with the gap between them reported rather than hidden.

```python
import oreblocks as ob

inst = ob.read_cpit("newman1.cpit")                    # periods, discount rate, capacities
prec = ob.read_prec("newman1.prec", inst.n_blocks)
result, relaxations = ob.solve_cpit(inst, prec)        # bound, schedule, local search
print(f"{result.npv:,.0f}  bound {result.bound:,.0f}  gap {result.gap_pct:.2f}%")

controls = ob.run_controls(inst, prec, result)         # duality, bound, order invariance
assert controls.all_pass
```

The bound needs **no LP solver**. Chicoisne et al. 2012 (Operations Research 60(3):517-528,
[doi:10.1287/opre.1120.1050](https://doi.org/10.1287/opre.1120.1050), Theorem 3.1) show the CPIT LP
relaxation is solved exactly in `O(mn log n)` for one resource per period, as a sequence of
parametric nested pits, which are maximum closures, which this package already computes exactly.

On the published `newman1.cpit` with its two resources, Algorithm 4 (one resource relaxed at a time)
returns **24 487 410** and the joint Bienstock-Zuckerberg bound (`cpit_bz_bound`) returns
**24 486 184**, which is the CPIT LP upper bound MineLib publishes for that instance. On
`newman1.pcpsp`, where the model also chooses each block's destination, `pcpsp_lp_bound` returns
**24 486 549**, the published PCPSP LP upper bound (Jelvez, Morales and Nancel-Penard 2018, Table 3).
The PCPSP bound sits above the CPIT one because PCPSP is the richer problem.

Full detail, including the three file-format traps and the explicit list of what is not implemented
(stockpiles, blending, minimum-production constraints, two-stage stochastic scheduling):
**[docs/scheduling.md](docs/scheduling.md)**.

## Pieces

| Module | What |
|---|---|
| `BlockGrid` | regular grid; LEVELS increase upward (the MineLib convention) |
| `make_deposit` | seeded archetypes: `porphyry`, `vein`, `layered`, `core_halo` (trend + correlated noise) |
| `Econ` / `block_values` | UPIT net value at the optimal destination (floating cutoff = the max) |
| `build_precedence` | slope-cone template one level up (45° cubic → the classic 9-point), CSR |
| `solve_upit` | exact Picard max-closure → Dinic min-cut; closure + value-identity self-checks |
| `extraction_state` / `loading_faces` | top-down bench extraction + seeded k-means shovel faces (grade at face, ore fraction, tonnes), the bridge to haulage simulators |
| `write_minelib` / `read_*` | the `.blocks/.prec/.upit` triplet + a meta sidecar with the stamped optimum |
| `read_cpit` / `read_pcpsp` / `write_*` | the MineLib scheduling files, with the forbidden-destination sentinel |
| `cpit_lp_relaxation` / `cpit_bound_two_resources` | the critical multiplier bound (exact LP for one resource), Algorithm 4 |
| `cpit_bz_bound` | the joint LP bound over every resource, Bienstock-Zuckerberg |
| `toposort_schedule` | GrTS, GeTS (successor-set weights) and ExTS (LP expected times) |
| `improve_schedule` / `exact_local_search` | shift local search; the exact C-PIT[D] re-solve |
| `sliding_window_schedule` | Cullenbine, Wood and Newman 2011, LP-guided candidate set |
| `destination_toposort` / `exact_destination_local_search` / `pcpsp_lp_bound` | PCPSP: destination choice, OPBSP-[D], the PCPSP LP bound |
| `enforce_min_width` / `schedule_coherence` | capacity-feasible sliver absorption; components and widths per period |
| `perturb_values` / `evaluate_across` | a correlated, mean-preserving value ensemble and the robust choice |

## Convention notes

- Levels (z) increase **upward**: level 0 is the deepest bench: exactly how published MineLib
  instances index (verified against newman1). Depth-down viewers flip with `z_down = nz-1-level`.
- `.blocks` free columns written by oreblocks are documented in the meta sidecar:
  `grade (mass fraction) · tonnage (t) · density (t/m³)`.
- Nothing here downloads or redistributes published MineLib data.

## Used by

- **minehaulsim** (haulage DES): geology-grounded scenarios: loading faces with grade/bench.
- **CAOS PitForge**: license-free synthetic twins next to the published-instance lane.

## License

MIT, as `LICENSE` and `pyproject.toml` state.
