-
Notifications
You must be signed in to change notification settings - Fork 541
pyomo.doe adding more verbose output for sensitivity analysis #3525
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
smondal13
wants to merge
30
commits into
Pyomo:main
Choose a base branch
from
smondal13:adding_eigen_values
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+300
−25
Open
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
2f35d58
added eigenvalues and determinant of the FIM
smondal13 0327879
added trace as a output in compute_FIM_full_factorial()
smondal13 eb78589
added eigvalsh for calculating
smondal13 5b2e90e
changed the method to calculate the minimum eigenvalues
smondal13 f3b0f7c
Merge branch 'Pyomo:main' into adding_eigen_values
smondal13 701947b
Added img_thereshold instead of the embedded constant for imaginary v…
smondal13 114a86e
Alex suggested some objectives and tests
smondal13 cb694be
Added `IMG_THRESHOLD` instead of embedded variable
smondal13 0a938ac
Added FIM test metrics for doe.py
smondal13 acf06f0
Changed the ``isclose() `` method to ``==``
smondal13 41a6272
Changed back to ``isclose()``
smondal13 b55786f
Added todo list
smondal13 46f75c1
Merge branch 'Pyomo:main' into adding_eigen_values
smondal13 3cc77ef
imported `_SMALL_TOLERANCE_IMG` from `doe.py` and used it in the `com…
smondal13 3ca1c4e
Deleted comment "Alex said..."
smondal13 7c2535f
added 1e-6 as the _SMALL_TOLERANCE_IMG
smondal13 5216672
Deleted the figures that was generated by runnig the example
smondal13 708a21d
adding unittest
smondal13 39f26e6
Merge branch 'Pyomo:main' into adding_eigen_values
smondal13 e9e83b6
to test doe , added the "doe_test_example.py" script, which returns a…
smondal13 7064966
The test_example file is not required. It is deleted. in `test_doe_FI…
smondal13 a475ada
Merge branch 'Pyomo:main' into adding_eigen_values
smondal13 5011800
Coding with Alex about `compute_FIM_metrics` funciton.
smondal13 b9ea35b
Merge branch 'adding_eigen_values' of github.com:smondal13/pyomo into…
smondal13 6d26fdf
Changed the test file to test the new function and added logging for …
smondal13 32079fe
added working test code for _compute_FIM_metric function and _check_F…
smondal13 e1842cf
Splitted the test files into 2 separate files. Commented out the code…
smondal13 898e87f
Deleted TODO: "make static method", and the chunk of code in `compute…
smondal13 ec2a361
Added `Returns` in the `compute_FIM_full_factorial()` docstring. Thou…
smondal13 f0da48e
Merge branch 'main' into adding_eigen_values
smondal13 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# ___________________________________________________________________________ | ||
# | ||
# Pyomo: Python Optimization Modeling Objects | ||
# Copyright (c) 2008-2025 | ||
# National Technology and Engineering Solutions of Sandia, LLC | ||
# Under the terms of Contract DE-NA0003525 with National Technology and | ||
# Engineering Solutions of Sandia, LLC, the U.S. Government retains certain | ||
# rights in this software. | ||
# This software is distributed under the 3-clause BSD License. | ||
# ___________________________________________________________________________ | ||
from pyomo.common.dependencies import ( | ||
numpy as np, | ||
numpy_available, | ||
) | ||
|
||
import pyomo.common.unittest as unittest | ||
from pyomo.contrib.doe.doe import ( | ||
_SMALL_TOLERANCE_IMG, | ||
_compute_FIM_metrics, | ||
) | ||
|
||
|
||
@unittest.skipIf(not numpy_available, "Numpy is not available") | ||
class TestComputeFIMMetrics(unittest.TestCase): | ||
def test_compute_FIM_metrics(self): | ||
# Create a sample Fisher Information Matrix (FIM) | ||
FIM = np.array([[10, 2], [2, 3]]) | ||
|
||
det_FIM, trace_FIM, E_vals, E_vecs, D_opt, A_opt, E_opt, ME_opt = ( | ||
_compute_FIM_metrics(FIM) | ||
) | ||
|
||
# expected results | ||
det_expected = np.linalg.det(FIM) | ||
D_opt_expected = np.log10(det_expected) | ||
|
||
trace_expected = np.trace(FIM) | ||
A_opt_expected = np.log10(trace_expected) | ||
|
||
E_vals_expected, E_vecs_expected = np.linalg.eig(FIM) | ||
min_eigval = np.min(E_vals_expected.real) | ||
if min_eigval <= 0: | ||
E_opt_expected = np.nan | ||
else: | ||
E_opt_expected = np.log10(min_eigval) | ||
|
||
cond_expected = np.linalg.cond(FIM) | ||
|
||
ME_opt_expected = np.log10(cond_expected) | ||
|
||
# Test results | ||
self.assertEqual(det_FIM, det_expected) | ||
self.assertEqual(trace_FIM, trace_expected) | ||
self.assertTrue(np.allclose(E_vals, E_vals_expected)) | ||
self.assertTrue(np.allclose(E_vecs, E_vecs_expected)) | ||
self.assertEqual(D_opt, D_opt_expected) | ||
self.assertEqual(A_opt, A_opt_expected) | ||
self.assertEqual(E_opt, E_opt_expected) | ||
self.assertEqual(ME_opt, ME_opt_expected) | ||
|
||
|
||
class TestFIMWarning(unittest.TestCase): | ||
def test_FIM_eigenvalue_warning(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
# Create a matrix with an imaginary component large enough to trigger the warning | ||
FIM = np.array([[6, 5j], [5j, 7]]) | ||
with self.assertLogs("pyomo.contrib.doe", level="WARNING") as cm: | ||
_compute_FIM_metrics(FIM) | ||
expected_warning = f"Eigenvalue has imaginary component greater than {_SMALL_TOLERANCE_IMG}, contact developers if this issue persists." | ||
self.assertIn(expected_warning, cm.output[0]) | ||
|
||
|
||
if __name__ == "__main__": | ||
unittest.main() |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# ___________________________________________________________________________ | ||
# | ||
# Pyomo: Python Optimization Modeling Objects | ||
# Copyright (c) 2008-2025 | ||
# National Technology and Engineering Solutions of Sandia, LLC | ||
# Under the terms of Contract DE-NA0003525 with National Technology and | ||
# Engineering Solutions of Sandia, LLC, the U.S. Government retains certain | ||
# rights in this software. | ||
# This software is distributed under the 3-clause BSD License. | ||
# ___________________________________________________________________________ | ||
from pyomo.common.dependencies import ( | ||
numpy as np, | ||
numpy_available, | ||
) | ||
|
||
import pyomo.common.unittest as unittest | ||
from pyomo.contrib.doe import DesignOfExperiments | ||
|
||
# Not need? from pyomo.contrib.doe.tests import doe_test_example | ||
from pyomo.contrib.doe.doe import ( | ||
_SMALL_TOLERANCE_DEFINITENESS, | ||
_SMALL_TOLERANCE_SYMMETRY, | ||
) | ||
|
||
|
||
@unittest.skipIf(not numpy_available, "Numpy is not available") | ||
class TestDesignOfExperimentsCheckFIM(unittest.TestCase): | ||
"""Test the check_FIM method of the DesignOfExperiments class.""" | ||
|
||
def test_check_FIM_valid(self): | ||
"""Test case where the FIM is valid (square, positive definite, symmetric).""" | ||
FIM = np.array([[4, 1], [1, 3]]) | ||
try: | ||
# Call the static method directly | ||
DesignOfExperiments._check_FIM(FIM) | ||
except ValueError as e: | ||
self.fail(f"Unexpected error: {e}") | ||
|
||
def test_check_FIM_non_square(self): | ||
"""Test case where the FIM is not square.""" | ||
FIM = np.array([[4, 1], [1, 3], [2, 1]]) | ||
with self.assertRaisesRegex(ValueError, "FIM must be a square matrix"): | ||
DesignOfExperiments._check_FIM(FIM) | ||
|
||
def test_check_FIM_non_positive_definite(self): | ||
"""Test case where the FIM is not positive definite.""" | ||
FIM = np.array([[1, 0], [0, -2]]) | ||
with self.assertRaisesRegex( | ||
ValueError, | ||
r"FIM provided is not positive definite. It has one or more negative eigenvalue\(s\) less than -{:.1e}".format( | ||
_SMALL_TOLERANCE_DEFINITENESS | ||
), | ||
): | ||
DesignOfExperiments._check_FIM(FIM) | ||
|
||
def test_check_FIM_non_symmetric(self): | ||
"""Test case where the FIM is not symmetric.""" | ||
FIM = np.array([[4, 1], [0, 3]]) | ||
with self.assertRaisesRegex( | ||
ValueError, | ||
"FIM provided is not symmetric using absolute tolerance {}".format( | ||
_SMALL_TOLERANCE_SYMMETRY | ||
), | ||
): | ||
DesignOfExperiments._check_FIM(FIM) | ||
|
||
|
||
if __name__ == "__main__": | ||
unittest.main() |
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will you ever get to this warning? Or will _check_FIM throw an error first?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adowling2
_check_FIM()
will not trigger this warning._check_FIM()
only checks whether the FIM is square, symmetric, and positive definite. Although this method checks for the symmetry of the FIM with a tolerance, and it is unlikely that the FIM will have large imaginary eigenvalues, we have kept the warning there just in case there is a large imaginary eigenvalue.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@smondal13 Thank you.
@blnicho @mrmundt Is there a best practice for testing this warning message is properly thrown?