Isomorph2026/isomorph-supply-chain-benchmark
ISOMORPH Full The full ISOMORPH dataset release: 49 rollouts spanning two baselines, 27 mixture scenarios, and 20 Latin-hypercube UQ perturbations. We release multivariate logistics time-series data generated by a digital-twin (DT) simulator of a multi-echelon supply chain with an explicit routing network, with the underlying dynamics formulated as a Markov chain. All runs use seed 2025 and horizon T = 52,560. Overview The simulator advances a directed routing… See the full description on the dataset page: https://huggingface.co/datasets/Isomorph2026/isomorph-supply-chain-benchmark.
ISOMORPH Full
The full ISOMORPH dataset release: 49 rollouts spanning two baselines, 27 mixture scenarios, and 20 Latin-hypercube UQ perturbations. We release multivariate logistics time-series data generated by a digital-twin (DT) simulator of a multi-echelon supply chain with an explicit routing network, with the underlying dynamics formulated as a Markov chain. All runs use seed 2025 and horizon T = 52,560.
Overview
The simulator advances a directed routing graph of factories, intermediate warehouses, and a customer-facing destination forward in discrete time. At each step, random Poisson customer demand arrives at the destination, is served from on-hand stock, and triggers replenishment along the network. The network is a directed graph $G=(\mathcal{N},\mathcal{E})$ with three node roles (factories, warehouses, destination), integer per-edge transit times $\taue$, and per-step volume capacities $Ke Ve$; Dijkstra's algorithm routes every shipment. The dynamics form a Markov chain $\xi{t+1} = \Psi(\xit, yt, Lt)$, where $\Psi$ is a deterministic transition map and $(yt, Lt)$ are the only random inputs (Poisson customer demand and Gaussian source lead times). The demand intensity is a five-component sum: yearly seasonality, weekly seasonality, AR(1) drift, per-item bursts, and a shared macro shock that lifts every item's intensity simultaneously. The state vector $\xit$ records on-hand stock, backlog, outstanding orders, in-transit shipments, and a smoothed demand estimate at every location for every item. All released rollouts run on the same 13-node US topology (3 sources, 9 warehouses across 5 tiers, NYC destination).
Contents
The C=50 baseline scenario is reachable via two manifest rows: output_item50 (the standalone baseline) and output_mixture/baseline (the reference point for the mixture sweeps). Both describe the same simulator configuration.
Approximate on-disk size: ~99 GB.
Mixture scenarios (27)
Six one-at-a-time sweeps plus two compound runs, all on the C = 50 catalogue. Each sweep varies one or two knobs; the rest stay at baseline. Per-row settings are in manifest.csv.
The bold setting in each sweep is the baseline configuration for that knob (drift's baseline is φ^AR ≈ 0.9993; the other five sweeps have a 1.0 multiplier). All six baseline-equivalent settings produce the same simulation and share a single output_mixture/baseline rollout, so the 30 sweep cells materialise as 25 distinct sweep rollouts plus the shared baseline. With 2 compound scenarios, the mixture family contains 27 directories in total.
Compound scenarios:
UQ perturbations (20)
K = 20 Latin-hypercube samples over three demand-side knobs:
phi_ARin [0.95, 0.999], applied to bothphi_loandphi_hirho_Gin [0.5, 2.0], applied to bothshock_count_scaleandshock_height_scalerho_Bin [0.5, 2.0], applied to bothburst_rate_scaleandburst_height_scale
Sampler: scipy.stats.qmc.LatinHypercube(d=3, seed=2025). Per-sample values are in manifest.csv rows where family = uq.
Manifest schema
manifest.csv has one row per rollout and the following columns:
Every cell is populated; knobs that the rollout did not perturb are filled with the simulator default (1.0 for the *_scale knobs and the baseline phi_lo = 0.999, phi_hi = 0.9996 for the AR(1) range). Each row is therefore a complete snapshot of the simulator configuration that produced the rollout.
Three additional simulator knobs are held fixed across all 49 rollouts and are therefore omitted from the manifest: seasonal_scale = 1.0, base_lambda_lo = 80.0, base_lambda_hi = 250.0. The exact values used by each rollout are still recorded in its scenario.json file.
File schema
Directory layout:
isomorph_full/
├── manifest.csv # one row per rollout
├── README.md
├── LICENSE
├── output_item50/ # baseline, C = 50
│ ├── daily_records.parquet
│ ├── shipments.parquet
│ ├── service_summary.parquet
│ ├── inventory_history.parquet
│ ├── backlog_history.parquet
│ ├── intransit_history.parquet
│ ├── demand_signals.npy
│ ├── demand_signals_cols.txt
│ ├── scenario.json
│ ├── edge_list.parquet
│ ├── edge_utilisation.npy
│ └── edge_saturation.npy
├── output_item200/ # baseline, C = 200 (same files as above)
├── output_mixture/<scenario>/seed2025/ # 27 mixture rollouts (same files as above)
└── output_uq/perturb_kNN/seed2025/ # 20 LHS rollouts (same files as above)Each rollout directory contains the following files. T is the run horizon (52,560 for released rollouts), C is the catalogue size, and E is the number of edges in the network.
Quick load
import pandas as pd
manifest = pd.read_csv("manifest.csv")
# Pull all mixture rollouts
mix = manifest[manifest.family == "mixture"]
# Pull all UQ rollouts
uq = manifest[manifest.family == "uq"]
# Load a rollout (tabular files are Parquet)
row = mix.iloc[0]
records = pd.read_parquet(f"{row.path}/daily_records.parquet")Reproducing from source
Each manifest.csv row maps to a single simulator CLI call. See ../../Isomorph_release/README.md sections 1, 2, and 4.
Licence
CC-BY-4.0 (see LICENSE).
