Pyomo.DoE: fix trace/Cholesky initialization consistency#3867
Conversation
|
@smondal13 @sscini @slilonfe5 @snarasi2 @djlaky I found a small bug in how we initialize the Cholesky factorization when the FIM at the initial point needs "inertia correction". This PR fixes the initialization inconsistency. This PR also proposes an interface to allow for more advanced solver options when diagnosing initialization issues for the Pyomo.DoE (dynamic) optimization formulation. Edit: This is a work in progress right now. I am not 100% happy with the proposed changes. |
|
@sscini @blnicho @mrmundt @smondal13 @slilonfe5 This is ready for review. This PR is now narrowly targeted at fixing a Pyomo.DoE FIM initialization issue. |
| def _compute_cholesky_jitter(self, min_eig): | ||
| """ | ||
| Compute diagonal regularization for Cholesky initialization. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| min_eig: float | ||
| Minimum eigenvalue of the current FIM estimate. | ||
|
|
||
| Returns | ||
| ------- | ||
| float | ||
| Nonnegative diagonal shift needed so the minimum eigenvalue | ||
| is at least ``_SMALL_TOLERANCE_DEFINITENESS``. | ||
| """ | ||
| return max(0.0, _SMALL_TOLERANCE_DEFINITENESS - float(min_eig)) |
There was a problem hiding this comment.
Is there a reason to have this as a method on the DesignOfExperiments class instead of a standalone utility function? It isn't using anything from the class instance.
Also, it's a 1-line method that is only being used once on L555. Why did you even abstract this out as a separate method?
Co-authored-by: Bethany Nicholson <blnicho@users.noreply.github.com>
…/pyomo into fix-doe-initialization
|
Tests now pass! (I had failures on tests that were being skipped in my local environment.) |
blnicho
left a comment
There was a problem hiding this comment.
@adowling2 I have one minor question but I'm also fine with merging as-is.
| bad_message in doe_object.results["Termination Message"] | ||
| ) | ||
| except: | ||
| except Exception: |
There was a problem hiding this comment.
Is there a more specific exception type that can be used here?
There was a problem hiding this comment.
I'll push back and say that it doesn't matter for this test suite. This is a catch-all for, "In case anything else goes wrong while trying to run cyipopt."
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3867 +/- ##
=======================================
Coverage 90.10% 90.11%
=======================================
Files 909 909
Lines 108551 108579 +28
=======================================
+ Hits 97813 97848 +35
+ Misses 10738 10731 -7
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Fixes # .
Summary/Motivation:
This PR
adds advanced debugging/inspection controls forfixes a trace-objective initialization inconsistency that can produce large residuals in Cholesky-related constraints at the start of the final NLP solve.pyomo.contrib.doe.DesignOfExperiments.run_doe()while preserving default behavior for typical usersThe motivating workflow showed:
inability to usemax_iter=0for final-model probing because scenario solves reused the same solver options,fim,L,fim_inv,L_inv, andcov_trace.Changes proposed in this PR:
Added an advancedrun_config(ConfigBlock/dict) argument torun_doe(model=None, results_file=None, run_config=None):scenario_solver_optionsfinal_solver_optionsfinal_solveinspection.enabledinspection.top_constraintsImplemented scoped solver option application:scenario-generation and square-initialization solves can use different options from the final optimization solve.Added optional structured residual reporting utility:reports top violated active constraints with fields:constraint_namebodylower_boundupper_boundviolationconstraint_typeAdded assemble-and-inspect path (final_solve=False) to inspect assembled NLP state without running final optimization._initialize_cholesky_from_fim()to re-synchronizeL,L_inv,fim_inv, andcov_tracefrom current FIM immediately before final solve / inspection.Updated docstrings and added advanced usage documentation + example path inreactor_example.py.test_doe_initialization.pyfor jitter behavior and FIM synchronization.Backward compatibility:
Default usage (run_doe()with norun_config) remains unchanged.Advanced functionality is available only whenrun_configis provided.Testing:
I ran:
pytest -q pyomo/contrib/doe/tests/test_doe_debug.pyResult:8 passedpytest -q pyomo/contrib/doe/tests/test_doe_solve.py -k "rooney_biegler_fd_central_solve"Result:1 passed, 17 deselectedpython3 -m unittest -q pyomo.contrib.doe.tests.test_doe_initialization3 skippedin the current interpreter because SciPy/numpy are unavailable therepython3 -m py_compile pyomo/contrib/doe/doe.py pyomo/contrib/doe/tests/test_doe_initialization.pyNew/updated tests cover:
Outstanding Tasks (before removing WIP):
Finalize proposed interface for advanced initialization diagnosticsDecide the best way to document the proposed interface. Are examples sufficient or should we build out the Pyomo documentation?Run black@adowling2 carefully reviews proposed changesWhy the strikethought?
The original version of this PR included a new interface to
run_doe()that makes debugging the initialization and, more broadly, solver failures easier. We decided that the newrun_doe()interface added too much complexity and exposed some inconsistencies in other parts of the Pyomo solver interface. (This led to a real-time Codex experiment documented in #3871.) To expedite this current PR, I decided to remove these contributions and strike through the above parts of the PR text. These contributions are still available in the git history. Thus, this current PR only contributes a targeted patch to the Pyomo FIM initialization.Legal Acknowledgement
By contributing to this software project, I have read the contribution guide and agree to the following terms and conditions for my contribution: