Solvers

After formulating a multilevel problem, PAO users will generally need to (1) transform the model to a standard form, and (2) apply an optimizer to solve the problem. The examples in the previous sections illustrate that step (1) is often optional; PAO automates the applications of several model transformations, particularly for problems formulated with Pyomo. The following section summarizes the solvers available in PAO, and describes how PAO manages solvers. Section Model Transformations describes model transformations in PAO.

Summary of PAO Solvers

The following summarizes the current solvers available in PAO:

  • pao.mpr.FA, pao.pyomo.FA

    PAO solver for Multilevel Problem Representations that define linear bilevel problems. Solver uses big-M relaxations discussed by Fortuny- Amat and McCarl (1981).

  • pao.mpr.MIBS, pao.pyomo.MIBS

    PAO solver for Multilevel Problem Representations using the COIN-OR MibS solver by Tahernejad, Ralphs, and DeNegre (2020).

  • pao.mpr.PCCG, pao.pyomo.PCCG

    PAO solver for Multilevel Problem Representations that define linear bilevel problems. Solver uses projected column constraint generation algorithm described by Yue et al. (2017).

  • pao.mpr.REG, pao.pyomo.REG

    PAO solver for Multilevel Problem Representations that define linear bilevel problems. Solver uses regularization discussed by Scheel and Scholtes (2000) and Ralph and Wright (2004).

The following table summarize key features of the problems these solvers can be applied to:

  Solver
Problem Feature FA REG PCCG MibS
Equation Structure Linear Y Y Y Y
Bilinear Y Y Y Y
Nonlinear        
Upper-Level Variables Integer Y   Y Y
Real Y Y Y Y
Lower-Level Variables Integer     Y Y
Real Y Y Y Y
Multilevel Representation Bilevel Y Y Y Y
Trilevel        
k-Bilevel Y Y    

Note

The iterface to MibS is a prototype that has not been well-tested. This interface will be documented and finalized in an upcoming release of PAO.

The Solver Interface

The Solver object provides a single interface for setting up an interface to optimizers in PAO. This includes both PAO solvers for multilevel optimization problems, but also interfaces to conventional numerical solvers that are used by PAO solvers. We illustrate this distinction with the following example, which optimizes the PAO1 (1) example:

>>> # Create an interface to the PAO FA solver
>>> opt = pao.Solver("pao.pyomo.FA")

>>> # Optimize the model
>>> # By default, FA uses the glpk MIP solver
>>> results = opt.solve(M)
>>> print(M.x.value, M.y.value, M.L.z.value)
6.0 4.0 2.0


>>> # Create an interface to the PAO FA solver, using cbc
>>> opt = pao.Solver("pao.pyomo.FA", mip_solver="cbc")

>>> # Optimize the model using cbc
>>> results = opt.solve(M)
>>> print(M.x.value, M.y.value, M.L.z.value)
6.0 4.0 2.0

The Solver object is initialized using the solver name followed by solver-specific options. In this case, the FA algorithm accepts the mip_solver option that specifies the mixed-integer programming (MIP) solver that is used to solve the MIP that is generated by FA after reformulating the bilevel problem. The value of mip_solver is itself an optimizer. As illustrated here, this option can simply be the string name of the MIP solver that will be used. However, the Solver object can be used to define a MIP solver interface as well:

>>> # Create an interface to the cbc MIP solver
>>> mip = pao.Solver("cbc")
>>> # Create an interface to the PAO FA solver, using cbc
>>> opt = pao.Solver("pao.pyomo.FA", mip_solver=mip)

>>> # Optimize the model using cbc
>>> results = opt.solve(M)
>>> print(M.x.value, M.y.value, M.L.z.value)
6.0 4.0 2.0

This enables the customization of the MIP solver used by FA. Note that the solve() method accepts the same options as Solve. This allows for more dynamic specification of solver options:

>>> # Create an interface to the cbc MIP solver
>>> cbc = pao.Solver("cbc")
>>> # Create an interface to the glpk MIP solver
>>> glpk = pao.Solver("glpk")

>>> # Create an interface to the PAO FA solver
>>> opt = pao.Solver("pao.pyomo.FA")

>>> # Optimize the model using cbc
>>> results = opt.solve(M, mip_solver=cbc)
>>> print(M.x.value, M.y.value, M.L.z.value)
6.0 4.0 2.0

>>> # Optimize the model using glpk
>>> results = opt.solve(M, mip_solver=glpk)
>>> print(M.x.value, M.y.value, M.L.z.value)
6.0 4.0 2.0

Warning

The solve() current passes unknown keyword arguments to the optimizer used by PAO solvers, but this feature will be disabled.

PAO Solvers

Solvers developed in PAO have names that begin with pao.. The current set of available PAO solvers can be queried using the Solver object:

>>> for name in pao.Solver:
...     print(name)
pao.mpr.FA
pao.mpr.MIBS
pao.mpr.PCCG
pao.mpr.REG
pao.pyomo.FA
pao.pyomo.MIBS
pao.pyomo.PCCG
pao.pyomo.REG

>>> pao.Solver.summary()
pao.mpr.FA
    PAO solver for Multilevel Problem Representations that define linear
    bilevel problems.  Solver uses big-M relaxations discussed by Fortuny-
    Amat and McCarl (1981).

pao.mpr.MIBS
    PAO solver for Multilevel Problem Representations using the COIN-OR
    MibS solver by Tahernejad, Ralphs, and DeNegre (2020).

pao.mpr.PCCG
    PAO solver for Multilevel Problem Representations that define linear
    bilevel problems. Solver uses projected column constraint generation
    algorithm described by Yue et al. (2017).

pao.mpr.REG
    PAO solver for Multilevel Problem Representations that define linear
    bilevel problems.  Solver uses regularization discussed by Scheel and
    Scholtes (2000) and Ralph and Wright (2004).

pao.pyomo.FA
    PAO solver for Pyomo models that define linear and bilinear bilevel
    problems.  Solver uses big-M relaxations discussed by Fortuny-Amat and
    McCarl (1981).

pao.pyomo.MIBS
    PAO solver for Multilevel Problem Representations using the COIN-OR
    MibS solver by Tahernejad, Ralphs, and DeNegre (2020).

pao.pyomo.PCCG
    PAO solver for Pyomo models that define linear and bilinear bilevel
    problems.  Solver uses projected column constraint generation
    algorithm described by Yue et al. (2017)

pao.pyomo.REG
    PAO solver for Pyomo models that define linear and bilinear bilevel
    problems.  Solver uses regularization discussed by Scheel and Scholtes
    (2000) and Ralph and Wright (2004).

The solve() method includes documentation describing the keyword arguments for a specific solver. For example:

>>> opt = pao.Solver("pao.pyomo.FA")
>>> help(opt.solve)
Help on method solve in module pao.pyomo.solvers.mpr_solvers:

solve(model, **options) method of pao.pyomo.solvers.mpr_solvers.PyomoSubmodelSolver_FA instance
    Executes the solver and loads the solution into the model.

    Parameters
    ----------
    model
        The model that is being optimized.
    options
        Keyword options that are used to configure the solver.

    Keyword Arguments
    -----------------
    tee
      If True, then solver output is streamed to stdout. (default is False)
    load_solutions
      If True, then the finale solution is loaded into the model. (default is True)
    linearize_bigm
      The name of the big-M value used to linearize bilinear terms.  If this is not specified, then the solver will throw an error if bilinear terms exist in the model.
    mip_solver
      The MIP solver used by FA.  (default is glpk)

    Returns
    -------
    Results
        A summary of the optimization results.

The solve() method returns a results object that contains data about the optimization process. In particular, this object contains information about the termination conditions for the solver. The check_optimal_termination() method can be used confirm that the termination condition indicates that an optimal solution was found. For example:

>>> nlp = pao.Solver('ipopt', print_level=3)
>>> opt = pao.Solver('pao.pyomo.REG', nlp_solver=nlp)
>>> results = opt.solve(M)
>>> print(results.solver.termination_condition)
TerminationCondition.optimal
>>> results.check_optimal_termination()
True

Pyomo Solvers

The Solver object also provides a convenient interface to conventional numerical solvers. Currently, solver objects constructed by Solver are simple wrappers around Pyomo optimization solver objects. This interface supports two types of solver interfaces: (1) solvers that execute locally, and (2) solvers that execute on remote servers.

When optimizating a Pyomo model, solver parameters can be setup both when the solver interface is created and when a model is optimized. For example:

>>> # This is a nonlinear toy problem modeled with Pyomo
>>> NLP = pe.ConcreteModel()
>>> A = list(range(10))
>>> NLP.x = pe.Var(A, bounds=(0,None), initialize=1)
>>> NLP.o = pe.Objective(expr=sum(pe.sin((i+1)*NLP.x[i]) for i in A))
>>> NLP.c = pe.Constraint(expr=sum(NLP.x[i] for i in A) >= 1)

>>> nlp = pao.Solver('ipopt', print_level=3)
>>> # Apply ipopt with print level 3
>>> results = nlp.solve(NLP)
>>> # Override the default print level to using 5
>>> results = nlp.solve(NLP, print_level=5)

However, PAO users will typically setup solver parameters when the Pyomo solver is initially created:

>>> nlp = pao.Solver('ipopt', print_level=3)
>>> opt = pao.Solver('pao.pyomo.REG', nlp_solver=nlp)
>>> results = opt.solve(M)

When executing locally, the executable option can be used to explicitly specify the path to the executable that is used by this solver. This is helpful in contexts where Pyomo is not automatically finding the correct optimizer executable in a user’s shell environment.

When executing on a remote server, the server is used to specify the server that is used. Currently, only the neos server is supported, which allows the user to perform optimization at NEOS [NEOS]. The NEOS server requires a user to specify a valid email address:

Warning

There is no common reference for solver-specific parameters for the solvers available in Pyomo. These are generally documented with solver documentation, and users should expect to contact solver developers to learn about these.