Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
37ec511
boot-sp PR-4: factor register_generic_args out of parse_args
DLWoodruff Jul 3, 2026
52cf93e
boot-sp PR-4: BatchExecutor -- groups of K ranks for the batch solves
DLWoodruff Jul 4, 2026
e2cd8c0
boot-sp PR-4: route the empirical estimators through the executor
DLWoodruff Jul 4, 2026
b6ce5c0
boot-sp PR-4: build a batch wheel from --boot-batch-config-file
DLWoodruff Jul 4, 2026
b4835ae
boot-sp PR-4: wire do_boot/config for K>1 (retire --boot-solver-*)
DLWoodruff Jul 4, 2026
3f01845
boot-sp PR-4: docs for the batch config file and groups of K
DLWoodruff Jul 4, 2026
7310458
boot-sp PR-4: runnable K>1 (groups-of-K) cylinders demo
DLWoodruff Jul 4, 2026
79eca98
boot-sp PR-4: cross-reference generic_cylinders on first mention in b…
DLWoodruff Jul 5, 2026
5066288
boot-sp PR-4: correct the batch-vs-candidate size claim
DLWoodruff Jul 5, 2026
7074a62
boot-sp PR-4: batch config examples are two alternative files, not one
DLWoodruff Jul 5, 2026
ccc918f
boot-sp PR-4: K divisibility rules, real wheel example, solver-thread…
DLWoodruff Jul 5, 2026
07ceecf
boot-sp PR-4: say "cylinders", not "wheel", in the prose
DLWoodruff Jul 5, 2026
8a61bd6
boot-sp PR-4: retitle 'Smoothed methods' (statdist stays in the body)
DLWoodruff Jul 5, 2026
0622caf
boot-sp PR-4: reorganize boot_sp.rst into a nested structure
DLWoodruff Jul 5, 2026
394899d
boot-sp PR-4: tidy the xhat_generator bullet (backticks, comma, wording)
DLWoodruff Jul 5, 2026
fa8e167
boot-sp PR-4: lead Examples with the dataset-file case; fix intro typo
DLWoodruff Jul 5, 2026
4a9fda1
boot-sp PR-4: note that M + N usually spans the whole dataset
DLWoodruff Jul 5, 2026
c90260f
boot-sp PR-4: say 'the model python module' owns the dataset
DLWoodruff Jul 5, 2026
4df59c8
boot-sp PR-4: clarify --boot-subsample-size (each bag from the N-reco…
DLWoodruff Jul 5, 2026
a61e10b
boot-sp PR-4: add --max-solver-threads 2 to the cylinder examples
DLWoodruff Jul 5, 2026
83010bc
boot-sp PR-4: state up front that smoothed methods are standalone-only
DLWoodruff Jul 5, 2026
da18d9a
boot-sp PR-4: de-duplicate 'disjoint' in the M+N sentence
DLWoodruff Jul 5, 2026
edadb2d
boot-sp PR-4: extend the review fixes to the K>1 paths
DLWoodruff Jul 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 38 additions & 14 deletions doc/designs/bootsp_merge_design.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ extended 2026-07-03 to state the end goal
PR-2 (statdist + smoothed) and PR-3 (the `generic_cylinders` integration, the
end goal — `--boot-*` group, `do_boot`, the positional layer with a strictly
disjoint M/N split, the `K = 1` batch executor) are implemented on the stacked
branches `bootsp-pr-b` / `bootsp-pr-c`.
branches `bootsp-pr-b` / `bootsp-pr-c`. PR-4 (the `K > 1` batch executor: a
`BatchExecutor` that groups the ranks and a wheel per group from
`--boot-batch-config-file`, retiring the interim `--boot-solver-*`) is
implemented on `bootsp-pr-d`; both endpoints are validated end to end — the
`G = 1` checkpoint (one group, a wheel per batch in sequence) and `G > 1`
(np = 4, K = 2).
**Author:** dlw (captured with Claude Code assistance)
**Last updated:** 2026-07-03

Expand Down Expand Up @@ -279,11 +284,13 @@ Behavior-preserving unless noted.
pool stream, and the sequential seed offsets used by the coverage
simulation reuse batch streams across replications (replication k on
rank r has the same stream as replication k+1 on rank r-1). The port
seeds every stream with a `(seed_offset, word)` pair
(`boot_sp._pool_rng` / `_batch_rng`), which numpy's `SeedSequence`
hashes into independent streams; no two streams coincide within a
run or across seed offsets, and `_extended_resample`'s special
`+ my_rank + 1` offset is retired.
seeds every stream with a `(seed_offset, word)` pair, which numpy's
`SeedSequence` hashes into independent streams; no two streams
coincide within a run or across seed offsets, and
`_extended_resample`'s special `+ my_rank + 1` offset is retired.
The pool/center stream is `boot_sp._pool_rng` (word 0) and the batch
streams come from `BatchExecutor.group_seed` (word `group_index + 1`,
which at `K = 1` is the rank, so the per-rank streams are unchanged).
12. **Real json booleans.** boot-sp's `cfg_from_json` accepts only the
strings `"True"`/`"False"` for bool options and crashes with an
`AttributeError` on a real json `true`/`false`; a json missing
Expand Down Expand Up @@ -613,10 +620,11 @@ given.
The **batch config** governs solve (2). It is *singular across batches* — you
resample the data, not re-tune per batch, so it is one config, never a per-batch
or `boot_*`-prefixed copy of the whole option surface — but it is **distinct
from the xhat-solve config**: a batch has `N` (or the subsample size) scenarios,
usually far more than the `M` candidate records, so its rho, iteration count,
and spoke mix are a different problem and must be set independently rather than
inherited from the xhat solve. Because it is a *full* `generic_cylinders`
from the xhat-solve config**: a batch is a resample of the data, with its own
scenario count (`N` for the classical and extended methods, the subsample size
for subsampling and bagging) set independently of the `M` candidate records, so
its rho, iteration count, and spoke mix are a different problem and must be set
independently rather than inherited from the xhat solve. Because it is a *full* `generic_cylinders`
configuration (solver, rho, which spokes, convergence, relative gap), it is
supplied as a **file** — `--boot-batch-config-file` (§9.5), parsed by the same
`Config` machinery — not as a growing set of `boot_*`-prefixed CLI flags or an
Expand All @@ -643,8 +651,22 @@ Note the two endpoints are the same mechanism: `K = 1` is `G = R` (one rank per
group, batches spread one-per-rank), and "serial cylinders per batch" is `K = R`
→ `G = 1` (one group of all `R` ranks, batches in sequence). So PR-4 is a single
executor with `--boot-ranks-per-batch` as its only new rank knob, and the
`G = 1` case is a development checkpoint, not a separate PR. The prerequisite
(#782) has landed, so PR-4 is unblocked.
`G = 1` case is a development checkpoint, not a separate PR.

*Implemented (PR-4).* A `BatchExecutor`
(`mpisppy/confidence_intervals/bootsp/batch_executor.py`) owns the rank
arithmetic and the collectives: it splits `R` ranks into `G = R // K` groups,
exposes each group's communicator (for the wheel / xhat-evaluation) and a
leaders-only communicator (for the cross-group `Gatherv`), and reproduces the
`K = 1` per-rank behavior bit-for-bit as its degenerate case (so the standalone
drivers are unchanged). The empirical estimators route their parallelism through
it. For `K > 1` the per-group wheel is built from `--boot-batch-config-file`
(`mpisppy/generic/boot_batch.py`), and its outer (decomposition) bound is read
back as `L_b`. Validated end to end on the `schultz_data` MIP: the `G = 1`
checkpoint and `G > 1` (np = 4, K = 2) both reproduce the exact value-at-`xhat`
of the `K = 1` EF path (the xhat-evaluation is K-invariant) while their outer
bound sits at or below the EF optimum, so the reported gap is conservative,
exactly as §9.4.1 predicts.

### 9.4.1 The per-batch value: inner bound minus outer bound

Expand Down Expand Up @@ -683,8 +705,10 @@ the estimators report a gap that the drivers floor at 0 (`ci_gap[0] = max(0,
…)`), which would turn a maximization interval into `[0, 0]`, and the coverage
harness's one-sided check assumes the same orientation. Per the repo-wide rule
that maximization either works or raises, this raises:
`boot_sp._require_minimization` is called from `solve_routine`, which every
batch goes through while every batch is an extensive form.
`boot_sp._require_minimization` is called from `solve_routine` (every extensive
form) and once from `do_boot` on a probe scenario, which is what covers
`K > 1`, where a batch is solved by a wheel and no extensive form is ever built
for `solve_routine` to inspect.
Supporting it properly means choosing how the gap is *reported* — mpi-sppy's MMW
estimator takes the magnitude, which would keep the gap non-negative in both
senses and leave the floors and coverage checks untouched — and threading the
Expand Down
Loading