Skip to content

Rework SolutionLoader#3701

Merged
michaelbynum merged 64 commits intoPyomo:mainfrom
michaelbynum:solver_api
Apr 27, 2026
Merged

Rework SolutionLoader#3701
michaelbynum merged 64 commits intoPyomo:mainfrom
michaelbynum:solver_api

Conversation

@michaelbynum
Copy link
Copy Markdown
Contributor

@michaelbynum michaelbynum commented Aug 13, 2025

Summary/Motivation:

This PR updates the solution loader in pyomo/contrib/solver based on recent design discussions.

Changes proposed in this PR:

  • add get_number_of_solutions method
  • add get_solution_ids method
  • add load_solution method
  • add load_import_suffixes method
  • add solution() to provide (through a view or a context manager) access to solutions from the solution pool

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:

  1. I agree my contributions are submitted under the BSD license.
  2. I represent I am authorized to make the contributions and grant the license. If my employer has rights to intellectual property that includes these contributions, I represent that I have received permission to make contributions and grant the required license on behalf of that employer.

@michaelbynum michaelbynum changed the title Rework SolutionLoader [Depends on #3698] Rework SolutionLoader Aug 13, 2025
@codecov
Copy link
Copy Markdown

codecov Bot commented Aug 14, 2025

Codecov Report

❌ Patch coverage is 98.37662% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.96%. Comparing base (3ef2be1) to head (cafea40).
⚠️ Report is 65 commits behind head on main.

Files with missing lines Patch % Lines
pyomo/contrib/solver/common/solution_loader.py 97.64% 2 Missing ⚠️
pyomo/contrib/solver/solvers/gms_sol_reader.py 90.90% 1 Missing ⚠️
...ontrib/solver/solvers/gurobi/gurobi_direct_base.py 96.87% 1 Missing ⚠️
pyomo/contrib/solver/solvers/highs.py 94.44% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3701      +/-   ##
==========================================
+ Coverage   89.93%   89.96%   +0.03%     
==========================================
  Files         902      903       +1     
  Lines      106454   106604     +150     
==========================================
+ Hits        95744    95911     +167     
+ Misses      10710    10693      -17     
Flag Coverage Δ
builders 29.20% <46.10%> (+0.01%) ⬆️
default 86.27% <98.37%> (?)
expensive 35.66% <46.10%> (?)
linux 87.42% <98.05%> (-2.01%) ⬇️
linux_other 87.42% <98.05%> (+0.02%) ⬆️
oldsolvers 28.14% <46.10%> (+0.01%) ⬆️
osx 82.76% <97.07%> (+0.02%) ⬆️
win 85.85% <98.05%> (+0.03%) ⬆️
win_other 85.85% <98.05%> (+0.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jsiirola
Copy link
Copy Markdown
Member

@michaelbynum, @mrmundt: I implemented the things that @michaelbynum and I discussed. Once either/both of you look it over, then I think we can merge.

class PersistentSolutionLoader(SolutionLoaderBase):
"""
import_suffixes = {}
for suffix in self._pyomo_model.component_objects(
Copy link
Copy Markdown
Contributor Author

@michaelbynum michaelbynum Apr 26, 2026

Choose a reason for hiding this comment

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

We should probably make _pyomo_model an attribute on the SolutionLoader class. Right now, this just assumes the derived classes create the attribute.

Comment thread pyomo/contrib/solver/solvers/knitro/solution.py Outdated
Comment on lines -27 to -40
class GDXFileData:
"""
Defines the data types found within a .gdx file
"""

def __init__(self) -> None:
self.primals: List[float] = []
self.duals: List[float] = []
self.var_suffixes: Dict[str, Dict[int, Any]] = {}
self.con_suffixes: Dict[str, Dict[Any]] = {}
self.obj_suffixes: Dict[str, Dict[int, Any]] = {}
self.problem_suffixes: Dict[str, List[Any]] = {}
self.other: List[str] = []

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't remember deleting this. Did you change this, @jsiirola?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I see - this class was not being used. Thanks.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Right - I was going through and updating type hints to Python 3.10+, which caused those lines to be added to the PR's "patch" - and they were uncovered. I dug around, and that class is never used (I think it was left over from when the LP writer was used as a base for the rewrite of the GAMS writer). Removing it seemed right.

Copy link
Copy Markdown
Contributor Author

@michaelbynum michaelbynum left a comment

Choose a reason for hiding this comment

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

I think this looks great. Thanks for all the effort you put into this, @jsiirola. I love the new solution loader view and context manager. That was a great idea. I'm also glad you updated the ASL and Ipopt solution loaders to generalize the reduced costs.

@michaelbynum
Copy link
Copy Markdown
Contributor Author

Okay, I'm happy to hit merge if tests pass.

@michaelbynum michaelbynum merged commit 81ec316 into Pyomo:main Apr 27, 2026
35 checks passed
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.

5 participants