pyomo icon indicating copy to clipboard operation
pyomo copied to clipboard

[PEP] Redesign of Pyomo Solvers

Open michaelbynum opened this issue 6 years ago • 18 comments

I would like to start redesigning the solver interfaces in Pyomo.

Motivation

  1. The current solver interfaces are more complex than necessary.
  2. The current solver interfaces have many inconsistencies.
  3. The current solver interfaces do not allow the solution of a model/block with constraints that use variables which live elsewhere.

Preliminary Design Decisions (to be updated with time)

  • When solving a model/block, the model is defined by the set of active components and any components used by those active components. This means that variables are handed to the solver if and only if they are used in an active constraint or objective.

Implementation

  • I intend to develop new solver interfaces alongside the existing ones. I do not intend to remove existing solver interfaces. Once the new solver interfaces are sufficiently mature, we can rename/archive the old interfaces.
  • I intend to start with a couple simple solver interfaces and get feedback before proceeding further.

Thoughts? Concerns?

Related Issues

  • #1169
  • #1490
  • #1776 🇺🇸
  • #2845
  • #3064
  • #3110
  • #3243
  • #3448
  • #3450
  • #3557 - specifically reevaluating load_solutions behavior.

michaelbynum avatar May 23 '19 17:05 michaelbynum

I think you should reduce the scope of this PEP. The third bullet point is an orthogonal and controversial issue. There is no need to have it possibly get in the way the other (much needed) changes.

ghackebeil avatar May 23 '19 17:05 ghackebeil

Regarding the third bullet Gabe references, can you clarify? Is said variable at least below the current block in the model component hierarchy? If it's not in the hierarchy, then I agree with Gabe that this is highly controversial.

jwatsonnm avatar May 23 '19 17:05 jwatsonnm

I updated the motivation in the pep to have numbers.

It would be good to document the cases where "Bullet 3" is required. I also admit that the first time I heard that we needed to support solves where variables live outside the hierarchy, I thought this was very strange because it breaks encapsulation of sub-models. Having said that, I would like to see a use case where this is required to be convinced one way or another.

carldlaird avatar May 23 '19 17:05 carldlaird

@ghackebeil @jwatsonnm I will open a separate PEP for (3).

michaelbynum avatar May 23 '19 17:05 michaelbynum

@ghackebeil @jwatsonnm @carldlaird Let's move the discussion of (3) to #1032.

michaelbynum avatar May 23 '19 18:05 michaelbynum

Now that the controversy has moved to #1032, I predict that everyone will think the new PEP with only items one and two is non-controversial great idea and that you should proceed with your plan to create a couple of examples.

DLWoodruff avatar May 25 '19 02:05 DLWoodruff

I am adding a performance label to this PEP. I believe that a redesign of the base solver API is a prerequisite before we can (effectively) tackle things like reworking the writers / readers / persistent APIs.

jsiirola avatar Nov 26 '19 17:11 jsiirola

Archived on the master Performance Proposals Issue (#1430). Not closing as this is also marked as a PEP.

jsiirola avatar May 08 '20 22:05 jsiirola

It would be very useful to users to define one or more base protocols or base classes that all solvers inherit from. Many solvers like the BARON shell interface inherit from opt.base.solvers.OptSolver. However, several solver managers including GAMS and AsynchronousActionManager and MindtPySolver do not. This causes problems like #2757, where users expect options= to work and it doesn't.

It would be best to factor out some standard behavior, like supporting the options= keyword to set .options.

Also, for example, all solvers seem to implement a solve method, and many have a license_is_valid method. Defining such methods in an abstract base class or protocol would help users keep track of what solvers can even do.

alexchandel avatar Aug 30 '23 18:08 alexchandel

@alexchandel - Agreed. All of those considerations are on our list.

mrmundt avatar Aug 30 '23 18:08 mrmundt

I would add to this—because the "results" of a Pyomo solver are part of the solver's API—to standardize at least SOME of the SolverResults structure across all solvers.

In particular, indicate in universal fashion whether the result was a solution, or infeasible/failure. See #2942 for an example where this behavior is inconsistent between solvers, preventing universal client code from being written.

alexchandel avatar Aug 30 '23 19:08 alexchandel

I would add an additional motivation for base classes is the recent emergence of powerful Python type checkers like Pylance/Pyright and mypy. Unfortunately some of Pyomo is extremely dynamic, and currently difficult for type checkers to work out (e.g. #2078, #2821, #2938). However, it would be nice for the construction SolverFactory(backend.str()) to be known to return a subclass of a known base class with a .solve() method, and similarly for SolverManagerFactory(backend.str()).

alexchandel avatar Aug 30 '23 19:08 alexchandel

Additionally, the Pyomo solver interface needs a common exception for when a Solver is not available. Observe the extremely different behavior when calling solve() on two solvers, neither of which is available:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/alex/test/test.py", line 3370, in start
    main()
…
  File "/Users/alex/test/.venv/lib/python3.11/site-packages/pyomo/solvers/plugins/solvers/GAMS.py", line 766, in solve
    self.available()
  File "/Users/alex/test/.venv/lib/python3.11/site-packages/pyomo/solvers/plugins/solvers/GAMS.py", line 654, in available
    raise NameError(
NameError: No 'gams' command found on system PATH - GAMS shell solver functionality is not available.
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/alex/test/test.py", line 3370, in start
    main()
…
  File "/Users/alex/test/.venv/lib/python3.11/site-packages/pyomo/opt/base/solvers.py", line 533, in solve
    self.available(exception_flag=True)
  File "/Users/alex/test/.venv/lib/python3.11/site-packages/pyomo/opt/solver/shellcmd.py", line 141, in available
    raise ApplicationError(msg % self.name)
pyomo.common.errors.ApplicationError: No executable found for solver 'baron'

alexchandel avatar Aug 30 '23 22:08 alexchandel

Linking to issue #728. It would be nice if this utility for extracting info from the Ipopt log could be incorporated into the redesigned Ipopt interface.

blnicho avatar Nov 14 '23 19:11 blnicho

Linking to issue #7

mrmundt avatar Jan 03 '24 19:01 mrmundt

To do for Part 2:

  • [ ] Adjust pyomo.contrib.solver.sol_reader to be an actual parser (e.g., not pass back and forth Results objects)
  • [ ] Address the idea of shifting solver_options and name to two different values such as interface and algorithm (see https://github.com/Pyomo/pyomo/pull/3137#discussion_r1492898399, https://github.com/Pyomo/pyomo/pull/3137#discussion_r1492986691)
  • [ ] Explore changing configs to be MixIns rather than inherit from a base class
  • [ ] Move _VarAndNamedExprCollector to inherit from StreamBasedExpressionVisitor (see https://github.com/Pyomo/pyomo/pull/3137#discussion_r1492935431)
  • [ ] Explore making Availability its own class rather than a class-level enum (see https://github.com/Pyomo/pyomo/pull/3137#discussion_r1492988651)
  • [ ] Create a general SubprocessXXX system (see https://github.com/Pyomo/pyomo/pull/3137#discussion_r1492994771)
  • [ ] (ipopt) Do not make directory if we don't need it (see https://github.com/Pyomo/pyomo/pull/3137#discussion_r1493002317)
  • [ ] Remove hard-coded constants for time_limit (https://github.com/Pyomo/pyomo/pull/3137#discussion_r1493003607)
  • [ ] Avoid using TeeStream (see https://github.com/Pyomo/pyomo/pull/3137#discussion_r1493004547)
  • [ ] Refactor Ipopt.solve into not such a horribly monstrous method (already underway in mrmundt:solver-refactor-pt2)
  • [ ] Clear up confusion about abstract methods vs. their implementations
  • [ ] Standardize solver options (see #3154 )

mrmundt avatar Feb 21 '24 16:02 mrmundt

I think the second bullet should be two different things:

  1. shift name and type to two different values such as interface and algorithm, and
  2. Generalize (and perhaps rename?) solver_options to handle case where multiple subsolvers are involved, all of which could have their own options.

emma58 avatar Feb 21 '24 16:02 emma58