Conversation
…into observer_gurobi_refactor
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #3698 +/- ##
==========================================
- Coverage 89.48% 89.47% -0.01%
==========================================
Files 904 906 +2
Lines 105385 105473 +88
==========================================
+ Hits 94299 94368 +69
- Misses 11086 11105 +19
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:
|
…into observer_gurobi_refactor
jsiirola
left a comment
There was a problem hiding this comment.
Finally getting back to this. I think there are still a number of open questions from previous reviews, plus a new one:
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| class GurobiDirectSolutionLoader(GurobiDirectSolutionLoaderBase): |
There was a problem hiding this comment.
I am struggling with the design here. I think that the SolutionLoader is filling multiple roles:
- it is the definitive "mapping object" between the Pyomo and Gurobi models
- it knows something about it's own validity (for persistent)
- it has the logic for translating the values back and forth
- it knows when to delete the Gurobi model
I feel like the the persistent interface should just hold on to the SolutionLoader as the definitive "mapping object" between the Pyomo and Gurobi models? That would resolve the issue around premature deletion of the Gurobi model. But it would make invalidation more complicated (because each solution would have the same loader?).
I wonder: would a better design be for a mapping object that currently does 99% of the current SolutionLoader? It would be the "owner" of the Gurobi model reference, know the translation keys, and know an "id" for the current solution. The SolutionLoader would then be a thin wrapper that stored the (mapper, solution_id). Invalidating a SolutionLoader would only require incrementing the solution id in the mapper object (much in the same way that we handle stale for variables). The mapping object could also be used for things like callbacks, too (see @emma58's comment below).
|
I created issues for the unresolved comments. One is minor (handling |
jsiirola
left a comment
There was a problem hiding this comment.
I was going to approve and leave all these comments to a future PR, but I think there is a significant bug that should be resolved before merging: there is inconsistent use var vs id(var) in gurobi_persistent: it looks liek the _pyomo_var_to_solver_var_map has moved to a ComponentMap, but there are still numerous cases where we are storing / looking things up by id().
| def _get_rc_all_vars(self): | ||
| pvars, gvars = self._get_var_lists() | ||
| vals = self._solver_model.getAttr("Rc", gvars) | ||
| return ComponentMap((i, val) for i, val in zip(pvars, vals)) | ||
|
|
||
| def _get_rc_subset_vars(self, vars_to_load): | ||
| var_map = self._get_var_map() | ||
| gvars = [var_map[i] for i in vars_to_load] | ||
| vals = self._solver_model.getAttr("Rc", gvars) | ||
| return ComponentMap(zip(vars_to_load, vals)) |
There was a problem hiding this comment.
Does it make sense to merge these into get_reduced_costs similar to what was done with get_primals?
There was a problem hiding this comment.
I don't think so. There is not really any duplicate code for the reduced costs.
It's not actually a bug. With That being said, it does need fixed, so I'll fix it now. Tests would have caught most of these if it had been a real bug. |
Actually, it is a bug - with I had found/fixed it back when we were working on performance in |
|
Okay, this should be good to go, assuming tests pass. |
Summary/Motivation:
This PR refactors the gurobi interfaces to achieve two goals:
Changes proposed in this PR:
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: