This repository is the reproducible research artifact for the paper:
Kriging-informed coverage sampling: An Integer Programming Approach to Optimizing Information Collection
It contains:
- the SK surrogate (a maximal-coverage-style IP) solved with Gurobi
- the CIC (“confident information coverage”) objective evaluation using Kriging
- baselines (small-instance exact enumeration + random search)
- scripts to reproduce the computational experiments and the IGHM example
Run these from the repo root (the folder that contains
kics/,scripts/, etc.)
conda create -n kics python=3.11 -y
conda activate kics
python -m pip install -r requirements.txtpython -m pip install -e .python -m pip install -r requirements-gurobi.txt
python -c "import gurobipy as gp; print('gurobi version:', gp.gurobi.version())"If you see a license/version mismatch like:
Version number is 13.0, license is for version 12.0
then you installed the wrong major version of gurobipy. Fix by pinning to your license major version (see Troubleshooting below).
python scripts/run_ighm_example.py --data data/ighm_1.json --k 5 --radius 3.0kics/— the core library (IGHM loader, variogram, kriging proxy, SK solver, grid experiments)scripts/— runnable entrypoints used for experimentsdata/ighm_1.json— a small IGHM example instancetests/— unit tests (Gurobi tests are skipped ifgurobipyis unavailable)
The IGHM JSON format is the same one used in the project codebase. It is a JSON object keyed by cell id, where each cell stores:
x,y: coordinatesgain: information gain weight for that cellsuitability: a dict mapping sensor/zoom keys (e.g.,SA_Z3) to suitability values in[0,1]
Example (one cell):
{
"1": {
"x": -79.10,
"y": -26.19,
"gain": 0.54,
"suitability": {"SA_Z1": 0.339, "SA_Z3": 0.19, "...": 0.01}
}
}The loader is kics.ighm.load_ighm_json, implemented via pandas.read_json.
This script:
- loads an IGHM instance (
--data) - solves the SK surrogate IP (MCLP form) with Gurobi using a coverage radius (
--radiusor--auto-radius) - evaluates the chosen samples under the CIC objective (kriging variance thresholded by
--accept)
A. Run SK with a fixed coverage radius
python scripts/run_ighm_example.py --data data/ighm_1.json --k 5 --radius 3.0B. Auto-compute a radius from the variogram + CIC threshold
This finds an h such that gamma(h) <= accept under the spherical semivariogram.
python scripts/run_ighm_example.py --data data/ighm_1.json --k 5 --auto-radius --no-range-cutoff --penalty-mode suitability --delta 1.1This should give the following results: === SK (Gurobi) === status: OPTIMAL radius: 3.0 k: 5 SK surrogate objective: 44.446035 True CIC objective (kriging eval): 16.837096 samples: [13, 328, 360, 401, 507]
Core:
--data PATH: path to an IGHM JSON file (quote the path if it contains spaces)--k INT: number of samples to select--radius FLOAT: coverage radius used in the SK surrogate (neighborhood definition)--auto-radius: computeradiusby solvinggamma(h) <= acceptforh
Variogram / CIC thresholding (KrigingParams):
--range FLOAT: variogram range parameterr--sill FLOAT: structured component of the sill (total sill isnugget + sill)--nugget FLOAT: nugget--accept FLOAT: CIC threshold (epsilon_0): cell is “covered” if variance <= accept--delta FLOAT: penalty base (>1), used by the resolution penalty
CIC evaluation mode:
--penalty-mode zoom|suitabilityzoom(default): uses the zoom integer parsed from keys likeSA_Z3; appliesdelta^(lambda_star - lambda_q)suitability: legacy behavior; uses the max suitability value in[0,1]; appliesdelta^(1 - max_suit_value)
--no-range-cutoff- if provided: all samples are used in the kriging proxy evaluation (no distance cutoff)
- otherwise: only samples within
--rangeare used; if none are in range the code returns a large variance sentinel
This script runs the synthetic grid experiments and writes a CSV.
Important: --grid-sizes expects space-separated integers, not a Python list.
python scripts/run_grid_experiments.py --grid-sizes 5 10 15 20 --reps 10 --out grid_results.csvKey args:
--grid-sizes INT [INT ...]: grid sizesg(a g×g grid)--reps INT: number of replicates per grid size--processes INT: multiprocessing pool size (0 disables multiprocessing)--out PATH: output CSV path
The CSV includes (when applicable): SS (exact), random search baselines, SK surrogate objective, SK “true” CIC objective, and a local-search improvement.
Use this when you want to confirm:
gurobipyimports- a model can be created/optimized
- the license is recognized
python scripts/self_test_gurobi.pyThe SK surrogate objective (the MIP objective) can match across implementations while the true CIC score differs if:
-
Range cutoff differs
- cutoff ON: only samples within
rangecontribute - cutoff OFF: all samples contribute (variogram saturates, but samples remain in the system)
- cutoff ON: only samples within
-
Penalty definition differs
zoom: uses the zoom integer from keys like*_Z3suitability: uses max suitability value in[0,1](legacy)
-
Multiple optimal SK solutions exist
Different sample sets can yield the same SK objective but different CIC (“true”) objective.
Run unit tests:
pytest -qNotes:
- Gurobi-dependent tests are skipped if
gurobipycannot be imported. - If you want to run only non-Gurobi tests:
pytest -q -k "not gurobi"You didn’t install the repo as a package. From the repo root:
python -m pip install -e .zsh treats [...] as a filename pattern. For --grid-sizes, pass space-separated ints:
python scripts/run_grid_experiments.py --grid-sizes 3 3 3Your gurobipy major version does not match your license major version.
Fix (example for a v12 license):
python -m pip uninstall -y gurobipy
python -m pip install "gurobipy>=12,<13"
python -c "import gurobipy as gp; print(gp.gurobi.version())"