Multistage feasible_xhat_creator (engine + aircond example)#766
Draft
DLWoodruff wants to merge 2 commits into
Draft
Multistage feasible_xhat_creator (engine + aircond example)#766DLWoodruff wants to merge 2 commits into
DLWoodruff wants to merge 2 commits into
Conversation
The in-cylinder mechanism is already multistage (_fix_nonants loops all nodes; _try_feasible_xhat only checks ROOT), so this needs no spoke or framework changes. New work is one engine (ef_xhat_nonants), one example (aircond_auxiliary, complete-recourse so no rounding), a doc revision, and a test. Captures the one genuinely new idea — inter-stage feasibility coupling: derive all node vectors from one coherent proxy solve, not independent per-node points. Construction-not-from-a-file by design; the CSV xhat-file path stays a separate input mechanism. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nd example)
The in-cylinder mechanism was already multistage (_fix_nonants loops all
nodes; _try_feasible_xhat only checks ROOT), so no spoke or framework
code changes. New:
- ef_xhat_nonants in xhat_helpers.py: solves one EF over a (proxy)
scenario set and returns {node_name: ndarray} over all non-leaf nodes,
ordered to match _fix_nonants. Reuses create_EF/ref_vars. (Refactors
the shared solve out of _solve_and_extract_root into _solve_model.)
- mpisppy/tests/examples/aircond_auxiliary.py: feasible_xhat_creator
using the expected-value tree (sigma_dev=0). aircond has relatively
complete recourse (Inventory absorbs imbalance as penalized
backorder), so any capacity-respecting plan is feasible to fix on
every path -- no rounding, the multistage analogue of farmer. Placed
beside the model so <module>_auxiliary discovery resolves.
- doc/src/feasible_xhat.rst: Multistage section -- the inter-stage
coupling principle (derive all node vectors from one coherent solve,
not independent per-node points) and the repair note (complete
recourse needs none; integer/coupled recourse needs a model-specific
path-feasible repair, not shipped).
- test_feasible_xhat.py: aircond end-to-end (build EV cache, pin on all
9 real stochastic scenarios, assert feasible). Already wired into the
coverage harness.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #766 +/- ##
=======================================
Coverage 74.13% 74.13%
=======================================
Files 166 166
Lines 21181 21193 +12
=======================================
+ Hits 15703 15712 +9
- Misses 5478 5481 +3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extends the
feasible_xhat_creatorconvention (seedoc/src/feasible_xhat.rst)to multistage problems. A model author can supply a candidate incumbent that
is feasible to fix in every real scenario's per-scenario subproblem; an xhat spoke
pins and evaluates it once before its main loop, via
--<xhatter>-try-feasible-xhat-first. Until now this was two-stage only.The headline: the in-cylinder mechanism was already multistage.
_fix_nonantsloops over every node of the scenario tree, and
_try_feasible_xhatonly validates"ROOT" in cache, so a multistage model returning a full-tree cache already workswith no spoke or framework changes. "Two-stage only" was a property of the
engines and docs, not the machinery. So this PR is small.
Design doc:
doc/designs/multistage_feasible_xhat_design.md.What's included
mpisppy/utils/xhat_helpers.py::ef_xhat_nonants— the multistage engine:solves one extensive form over a (proxy) scenario set and returns
{node_name: np.ndarray}over all non-leaf nodes, each array ordered to match_fix_nonants' per-node loop (built fromsputils.create_EF/ref_vars). Theshared solve is refactored out of
_solve_and_extract_rootinto_solve_model.The two-stage engines (
average_xhat_nonants,lp_xbar_nonants) are unchanged.mpisppy/tests/examples/aircond_auxiliary.py— a worked multistage example.Its
feasible_xhat_creatorsolves the expected-value tree (sigma_dev=0):same branching structure, deterministic mean demand. aircond has relatively
complete recourse (the free
Inventoryvariable absorbs any demand imbalance aspenalized backorder via material balance; the only hard constraint on the node
decisions is
RegularProd <= Capacity), so any capacity-respecting plan isfeasible to fix on every path — no rounding needed, the multistage analogue
of farmer. Placed beside the model (
mpisppy.tests.examples.aircond) so the<module>_auxiliarydiscovery resolves.doc/src/feasible_xhat.rst— a "Multistage" section covering the onegenuinely new idea, inter-stage feasibility coupling: the node vectors are
coupled along each path, so you cannot assemble a candidate from independent
per-node choices; derive them all from one feasible solve of a proxy tree with
the same node structure. Includes the repair note — relatively complete recourse
needs none; integer/tightly-coupled recourse needs a model-specific path-feasible
repair, which mpi-sppy does not ship (the model author's responsibility).
mpisppy/tests/test_feasible_xhat.py—TestAircondFeasibleXhatCreator:builds the expected-value cache (branching
[3,3], 9 scenarios, non-leaf nodesROOT/ROOT_0/ROOT_1/ROOT_2), then pins it on every real stochasticscenario and asserts each stays feasible. The test file is already wired into
run_coverage.bashandtest_pr_and_main.yml.Scope / non-goals
(
--xhat-from-file, Multi-stage xhat file: read and write (by-name CSV) #760). This example constructs the candidate in memory.docs as the model author's job).
ef_xhat_nonantsis additive.Testing
test_feasible_xhat.py: 28/28 pass (3 new aircond + 25 existing).ruff checkclean; docs build with no warnings onfeasible_xhat.🤖 Generated with Claude Code