Skip to content

Per-spoke solver for xhat spokes + close solver-options-redesign §4#806

Draft
DLWoodruff wants to merge 3 commits into
Pyomo:mainfrom
DLWoodruff:solver-work
Draft

Per-spoke solver for xhat spokes + close solver-options-redesign §4#806
DLWoodruff wants to merge 3 commits into
Pyomo:mainfrom
DLWoodruff:solver-work

Conversation

@DLWoodruff

Copy link
Copy Markdown
Collaborator

Draft. Bundles two related pieces of "solver work" on the solver-options surface.

1. Per-spoke solver for the xhat inner-bound spokes (code)

The outer-bound spokes already accept --<spoke>-solver-name, -solver-options, and -solver-options-file (lagrangian, reduced_costs, subgradient, relaxed_ph, ph_dual — all via Config.add_solver_specs(prefix)), and FWPH has its own --fwph-mip-solver-name / --fwph-qp-solver-name. The xhat inner-bound spokes did not: their *_args helpers never called add_solver_specs, and their factories never called apply_solver_specs.

This adds the full trio to the xhat spokes:

  • Registeradd_solver_specs("<prefix>") in xhatlooper_args, xhatshuffle_args, xhatspecific_args, xhatxbar_args, xhatlshaped_args.
  • Consumeapply_solver_specs("<prefix>", spoke, cfg) in the five matching spoke factories in cfg_vanilla.py.

apply_solver_specs updates iter0/iterk_solver_options in place (never reassigns), so each xhat factory's nested xhat_solver_options reference to iterk stays valid. Because the three flags register independently, "different options but the inherited solver" also works (supply only --<xhat>-solver-options).

So, e.g.:

generic_cylinders ... --solver-name gurobi --xhatshuffle --xhatshuffle-solver-name xpress

now runs the PH hub on gurobi and the xhatshuffle inner-bound spoke on xpress.

Regression tests added to mpisppy/tests/test_solver_options_layers.py (already wired into the coverage harness):

  • all five xhat *_args register the solver trio;
  • xhatshuffle_spoke routes per-spoke solver name + options (and the nested xhat_solver_options) into the spoke.

Corrects and will close #805 (whose original problem statement overstated the gap — the outer-bound spokes already had these flags).

2. solver_options_redesign.md §4 open questions closed (docs)

The solver-options redesign shipped a while ago (PRs #696#703). This marks §4's open questions #1#4 Resolved, matching the shipped implementation (#5 was already marked). No behavior change.

Notes / not done here

  • xhatlooper / xhatspecific now register the flags too, but those spokes aren't wired into generic_cylinders (they're used by other drivers) — intentional.
  • The doc's §1 "as-is" section and top "implementation in progress" status line are now stale (the redesign fully merged); left as a follow-up rather than rewritten here.

🤖 Generated with Claude Code

DLWoodruff and others added 3 commits July 16, 2026 14:36
Ratify the DLW decisions against the shipped implementation:
- #1 options-file: JSON only (no YAML); inline --solver-options overlays
  the file (load_solver_options_file / cfg_vanilla ordering).
- #2 spoke-override: flat key-level dict.update() onto the global set.

Open questions #3-#5 in §4 are untouched (still to be walked through).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- #3 after-iteration-N: file-only (starting_at_iter section); it
  overrides iterk per-key for iterations k >= N.
- #4 lagranger deprecation: shipped in PR Pyomo#699 as a rank-0-gated
  DeprecationWarning; removal timeline intentionally left open.

#1, #2 were resolved in the prior commit; #5 was already marked
resolved in the doc.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The outer-bound spokes (lagrangian, reduced_costs, subgradient, ph_dual,
relaxed_ph) already accept --<spoke>-solver-name / -solver-options /
-solver-options-file, but the xhat inner-bound spokes did not: their
*_args helpers never called add_solver_specs, and their factories never
called apply_solver_specs.

Register the full solver trio in xhatlooper_args, xhatshuffle_args,
xhatspecific_args, xhatxbar_args, xhatlshaped_args, and consume it in the
matching spoke factories. apply_solver_specs updates iter0/iterk_solver_
options in place, so the nested xhat_solver_options reference stays valid.

Because the three flags register independently, "options but not a
different solver" also works now (supply only --<xhat>-solver-options).

Adds regression tests to test_solver_options_layers.py:
- all five xhat *_args register the solver trio
- xhatshuffle_spoke routes per-spoke solver name + options into the spoke

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends mpi-sppy’s solver-options “per-spoke” configuration surface to the xhat inner-bound spokes (bringing them in line with existing outer-bound spokes), and updates the solver-options redesign design doc to mark several previously-open questions as resolved.

Changes:

  • Register per-spoke solver specification flags for xhat spokes by adding add_solver_specs("<xhat>") in the relevant Config *_args helpers.
  • Apply per-spoke solver specifications inside the corresponding xhat spoke factories via apply_solver_specs("<xhat>", spoke_dict, cfg).
  • Add regression tests verifying (a) xhat args register the solver trio and (b) xhatshuffle_spoke routes per-spoke solver name/options into the spoke options; plus doc updates resolving solver-options redesign §4 questions.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
mpisppy/utils/config.py Registers per-xhat-spoke solver flags via add_solver_specs() in the xhat *_args helpers.
mpisppy/utils/cfg_vanilla.py Ensures xhat spoke factories consume per-spoke solver specs by calling apply_solver_specs() before building xhat-specific option sub-dicts.
mpisppy/tests/test_solver_options_layers.py Adds regression tests for xhat per-spoke solver flag registration and routing (via xhatshuffle_spoke).
doc/designs/solver_options_redesign.md Marks solver-options redesign §4 questions as resolved and references the shipped implementation behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1254 to +1255
def _sc(*a, **k): # the foundation packages, never calls, this
raise AssertionError("scenario_creator should not be called")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

generic_cylinders: expose per-spoke --<spoke>-solver-name flags

2 participants