Helpful error when a solver can't handle the PH quadratic proximal term (issue #762, part 1)#768
Helpful error when a solver can't handle the PH quadratic proximal term (issue #762, part 1)#768DLWoodruff wants to merge 2 commits into
Conversation
|
@tvalenciaz this addresses part 1 of #762 — please review it when you get a chance. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #768 +/- ##
=======================================
Coverage 74.31% 74.32%
=======================================
Files 166 166
Lines 21442 21477 +35
=======================================
+ Hits 15935 15962 +27
- Misses 5507 5515 +8 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
This looks good to me! I tried it on the instances that prompted the issue submission and it works well. I think during |
@DLWoodruff I thought we attach W and prox after iteration 0? If not, maybe we should just do that so the problem we solve at iteration 0 is effectively what the user passes us. This would be good for debugging, generally. |
…issue Pyomo#762) Progressive Hedging's proximal term makes the subproblem objective quadratic (unless --linearize-proximal-terms is used). A solver that cannot handle a quadratic objective then fails -- and for HiGHS on an MIQP the failure is cryptic (TerminationCondition=unknown). Detect this and tell the user what to do, via two complementary checks in iterk_loop: - Proactive: before the first proximal solve, if the solver reports via the legacy has_capability API that it cannot handle a quadratic objective (e.g. cbc, glpk), raise immediately with guidance. - Reactive: after the first proximal solve, if no subproblem anywhere produced a solution, raise with guidance. This covers solvers that do not expose has_capability (e.g. HiGHS via the APPSI / contrib.solver interfaces). The "no solution anywhere" test uses allreduce_or so the raise decision is identical on every rank. Both checks no-op unless a non-linearized proximal term is actually active, and the reactive check is limited to iteration 1 (if the first quadratic solve works, the solver supports quadratic objectives). Adds sputils.solver_quadratic_objective_capability (tri-state probe) and a solver-independent unit test, wired into run_coverage.bash and the CI workflow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…(issue Pyomo#762) cbc and glpk reject a quadratic objective by *raising* in the LP writer during the first proximal solve -- before the reactive "no solution anywhere" check can run -- and the proactive has_capability probe does not catch them in every Pyomo version / solver interface. Wrap the iter-1 solve so that a raise there is re-raised with the actionable --linearize-proximal-terms message (chaining the original exception so the real traceback is preserved). Factor the shared remediation text into a module-level _LINEARIZE_PROX_HINT used by all three checks. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4647505 to
4d79c7c
Compare
|
The PR now addresses Tomas's issues with cbc and glpk (although we wonder if the latest Pyomo was running). |
Part 1 of issue #762
When Progressive Hedging uses a quadratic proximal term and the solver cannot handle a quadratic objective, the run fails confusingly. For HiGHS on a problem with integers/binaries (an MIQP), the failure is the cryptic
status=unknown, TerminationCondition=unknown. This adds an actionable message.Approach
PH's proximal term makes the subproblem objective quadratic unless
--linearize-proximal-termsis set, so this is a quadratic-objective/solver mismatch. Pyomo's capability information is uneven (the legacyhas_capabilityAPI reports it for solvers like cbc/glpk, but the APPSI andpyomo.contrib.solverwrappers used for HiGHS don't expose it), so a single up-front check isn't enough. Two complementary checks inphbase.iterk_loopcover both cases:has_capability) that it cannot handle a quadratic objective, raise immediately with guidance. Catches e.g.cbc,glpkbefore wasting a solve.allreduce_or, so the raise decision is identical on every rank (no MPI desync).Both checks no-op unless a non-linearized proximal term is actually active, and the reactive check is limited to iteration 1 — if the first quadratic solve succeeds, the solver supports quadratic objectives, so a later failure is a genuine optimization issue, not a capability problem. The error message points the user at
--linearize-proximal-terms(and--linearize-binary-proximal-termsfor binaries).Changes
mpisppy/utils/sputils.py:solver_quadratic_objective_capability()— tri-state probe (True/False/None, whereNonemeans "unknown", never "unsupported").mpisppy/phbase.py:_prox_is_quadratic,_check_prox_solver_capability(proactive),_check_prox_solve_succeeded(reactive); wired intoiterk_loop.mpisppy/tests/test_prox_solver_compat.py: solver-independent unit tests (probe tri-state, both guards, MPI-consistency viaallreduce_or), wired intorun_coverage.bashand.github/workflows/test_pr_and_main.yml.Validation
test_ef_ph.py): pass, with no false positives on a quadratic-capable solver (one unrelated pre-existing failure,test_scenario_lpwriter_extension, fails identically onmain).glpk(no QP) atPHIterLimit=1now raisesSolver 'glpk' reports that it cannot handle a quadratic objective ... Re-run with --linearize-proximal-terms ...; the same run with--linearize-proximal-termscompletes.🤖 Generated with Claude Code