Highs::run()Highs::run() has evolved a great deal since it was first created to
"solve" the LP in the HighsLp instance Highs::lp_. As well as
solving more problem classes, and using more solvers, features have
been added inelegantly. The simplicity of having a single
Highs::run() method, with different features obscured within it will
be replaced by multiple, nested, "solve" methods which are explicit in
their features and very much simpler.
The only refactoring came when the multiple objective code was added:
Highs::optimizeModel() inherited the content of Highs::run() so
that a single call toHighs::run() could perform multiple
optimizations.
Other developments that have been implemented inelegantly are
Highs::run()As #2269
highlighted, users of cvxpy can only execute Highs::run(), so the
following actions that were previously in app/RunHighs.cpp, are now
performed in Highs::run()
There is still one action inapp/RunHighs.cpp that should be performed in Highs::run()
These "HiGHS files" actions must only be performed at the "top level"
of Highs::run(), and this is acheived by caching the file options in
the Highs class and clearing them from options_ so that they aren't
applied at lower level calls to Highs::run(). They are then restored
before returning from Highs::run().
User objective and/or bound scaling is performed before assessing
whether there is excessive problem data and suggesting user objective
and bound scaling. These user scaling actions must only be performed
at the "top level" of Highs::run(), and this is acheived by caching
the user scaling options in the Highs class and clearing them from
options_ so that they aren't applied at lower level calls to
Highs::run(). If user scaling has been applied in a call to
Highs::run(), it is unapplied and the option values restored before
returning from Highs::run().
The HighsLp class contains data values and structures that cannot be handled explicitly by the solvers.
If a variable has an excessivly large objective cost, this is
interpreted as being infinte, and handled in
Highs::handleInfCost() by fixing the variable at its lower or
upper bound (when finite) according to the sign of the cost and the
sense of the optimization, and zeroing the cost. After solving the
problem, the cost and bounds must be restored.
If a variable is of type HighsVarType::kSemiContinuous or
HighsVarType::kSemiInteger, it is assessed in
assessSemiVariables (in HighsLpUtils.cpp) before reformulation
in withoutSemiVariables (in HighsLpUtils.cpp)
If it is not strictly "semi" it is set toHighsVarType::kContinuous or HighsVarType::kInteger
kMaxSemiVariableUpper then,
depending on the lower bound, if it is possible to reformulate it the
upper bound is set to kMaxSemiVariableUpper (it is said to be "tightened".
Otherwise, it is deemed to be illegalThese modifications are currently performed in Highs::run(), with
very careful code to ensure that they are removed before returning
from Highs::run().
With the plan to allow indicator constraints and SOS as generalised disjunctive forms that will be reformulated, the handling of "mods" needs to be refactored!
The inelegance of Highs::run() (and Highs::optimizeModel()) was
exposed by
#2635. Both methods
need to be refactored. Firstly, Highs::run() must be refactored into
the following set of nested methods. By calling the appropriate
method, there is no need to "hide" option settings by caching and then
clearing their value.
Refactoring Highs::optimizeModel() is trickier. There needs to be a
method where any "mods" are made, so that at the level below the
problem defined by the HighsModel class (without semi-variables) is
solved.
Highs::runThis "outer" layer can contain the "HiGHS files" actions that were
previously in app/RunHighs.cpp, and user scaling
Highs::optimizeHighs()The next layer applies any "mods" to the HighsModel class, and calls
Highs::optimizeModel() or Highs::multiobjectiveSolve() if there
are multiple objectives.
Highs::optimizeModel()The next layer should just optimize what's in the HighsModel (without semi-variables)
Refactoring Highs::optimizeModel() is tricky, so is is temporarily
renamed Highs::calledOptimizeModel(), and Highs::optimizeModel()
is a temporary intermediate method to facilitate this is.
The most obvious place where Highs::run() was called at a "lower
level" is in the MIP solver. Since there are no "upper level"
actions to be performed, it can call Highs::optimizeModel(). To
emphasise that just an LP is being solved, Highs::optimizeLp() has
been created. This is currently a call to Highs::optimizeModel()
Move the code to write out the presolved model from app/RunHighs.cpp to Highs::run()
Move the "mods" to Highs::optimizeHighs()
For problems with multiple objectives
Apply user scaling to the multiple objectives
Assess the multiple objectives for extreme values
Accumulate subsystem solve times
In IIS calculations, accumulate subsystem solve times
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.