[Depends on #3991] Adding method for multistart initialization of nonlinear models. - #3994
[Depends on #3991] Adding method for multistart initialization of nonlinear models.#3994stephenscini wants to merge 45 commits into
Conversation
|
Opening PR, but still in active development. Dependent on #3991 first as it includes those changes. |
|
Note for 7/21 Dev meeting Method implemented with support for new solver interface. All original tests passing locally. Tasks before ready for review:
|
stephenscini
left a comment
There was a problem hiding this comment.
Went through and added some questions in the code for design meeting.
| from pyomo.core.expr.compare import assertExpressionsEqual | ||
| from pyomo.core.expr.numeric_expr import LinearExpression | ||
|
|
||
| from pyomo.contrib.multistart.multi import MultiStart |
There was a problem hiding this comment.
I received an error message when I added the solver to the new SolverFactory that it needed to be in this list. This would mean it is tested with the other solvers from contrib/solver and I am not sure that if that is expected? If so, will all contrib solvers need to eventually be switched over or should the opt/solvers still be the best location.
In this case, I wanted to update it to use these solvers so thought it would also go here. Maybe Legacy?
|
|
||
| def rand(val, lb, ub): | ||
| return random.uniform(lb, ub) # uniform distribution between lb and ub | ||
| def rand(val, lb, ub, rng): |
There was a problem hiding this comment.
Previously, there was not a set way I could find to make the solver result reproducible, so I made the default random generator np.random with the current RNG interface.
I wanted to otherwise leave the established strategies alone, but could also make all random strategies support the different random generator options? Kept all newer options under rand_vector to use a vectorized approach.
|
|
||
| if config.strategy == "rand_vector": | ||
|
|
||
| if len(eligible_vars) == 0: |
There was a problem hiding this comment.
Before, if all the variables are unbounded, it would not reset them but just give the warning. I thought it would be better to error out.
| logger = logging.getLogger('pyomo.contrib.multistart') | ||
|
|
||
|
|
||
| @document_configdict() |
There was a problem hiding this comment.
Made changes so it is now loaded as a solver for the new SolverFactory since I wanted to use the new solver interfaces like the other devel/initialization methods, and from discussion with Bethany. Causing testing errors but would like to discuss best way to do this if other method preferred.
| def version(self): | ||
| """Get solver version | ||
| TODO: This is a solver wrapper, unsure how to define version in this case.""" | ||
|
|
There was a problem hiding this comment.
Currently no versions for this. If old was v0.0, would this be v0.1?
| """, | ||
| ), | ||
| ) | ||
| self.solver = self.declare( |
There was a problem hiding this comment.
Should I make this have different solver acceptances like MindtPy where there are supported categories, or make it so it accepts the solver object? How consistent should the contrib solvers that accept other solvers be with handling internal solver?
| visibility=visibility, | ||
| ) | ||
|
|
||
| self.strategy = self.declare( |
There was a problem hiding this comment.
Could/should this also support a user supplying a list of initial points? Thinking of obj_at_theta in parmest. Goal in my head is to make as generalized as possible.
| raise RuntimeError( | ||
| "Multistart solver is unable to handle model with multiple active objectives." | ||
| ) | ||
| if obj is None: |
There was a problem hiding this comment.
Previously it was restricted from using square models or constant objectives in the multistart solver. Is there a valid reason for this or can it be removed? Is there a case where a model would have no objective or would that cause a different error? Removing would make more sense in my opinion.
| description="Tolerance on HCS objective value equality. Defaults to Python float equality precision.", | ||
| ), | ||
| ) | ||
| self.break_on_solution = self.declare( |
There was a problem hiding this comment.
For initialization, I thought this made sense, other thought would be implementing a SolutionLimit argument like Gurobi.
| ) | ||
| # If we are looking for the first feasible solution, then return immediately | ||
| if config.break_on_solution: | ||
| return best_result |
There was a problem hiding this comment.
Would it be a good idea to have this return a dictionary or something instead of just the best result if someone wanted to inspect? Or is this better for a user to set up? Should a user be able to access subsolver information too?
|
Had discussion with Bethany and Michael. Main takeaway points:
|
Fixes # .
Summary/Motivation:
Additional method in devel/initialization to use multistart optimization as a way for initializing nonliner models.
Changes proposed in this PR:
AI-Use Disclosure
AI tools contributed to the development of this PR
Review process (select ONE):
Notes for reviewers (optional):
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: