Basic Model Classes
Hierarchy
The basic model class hierarchy is simple. The top three levels of the
hierarchy are depicted in the figure below. The first two levels (i.e., Clp
Model, Clp Simplex, ClpInterior) contain all the problem data which defines a
model (aka, a problem instance). The third level is less model and more
algorithmic. There is a fourth level (for models with more general
objectives than linear ones), but it is beyond the current scope of this
document.
The class ClpModel contains all problem data. There may be a few pieces of
data which could be elsewhere but which are permanent and so they are here.
The main example of this is a status array: it makes the most sense for
Simplex but has use for crossing over from any solution.
ClpSimplex inherits from ClpModel, as does ClpInterior. Extra data is specific
to the Simplex Algorithm and can be transient e.g., scaling arrays. Normally
a user will just be dealing with the ClpSimplex class and not with the ClpModel
class.
From the point of view of most Simplex users, the ClpModel and ClpSimplex
classes are all one needs to know about. There are algorithm-specific classes
which inherit from ClpSimplex (e.g., ClpSimplexDual and ClpSimplexPrimal), but
they have no member data and very rarely need be visible to user. So, for
example, after instantiating an object model of type ClpSimplex,
the user would type model.dual() to invoke dual algorithm.
First Example
Below is our first CLP example code. It is short enough to present in full.
Most of the remaining examples in this Guide will take the form of small code
fragments.
minimum.cpp
This sample program creates a default ClpSimplex model,
reads an mps file, and if there are no errors, solves it using the primal
algorithm. Simple, but not terribly useful: there is no way to see the results
of the solve. There are two main kinds of results -- a status saying what
happened to the model, and arrays filled with the solution values.
Getting at the Solution
It is often the case with CLP that there is more than one way to do something.
This is a consequence of CLP's mixed heritage as a child of OSL and a cousin of
OSI. Finding the status of a model exemplifies this situation.
The OSI way to check for optimality is to call model.isProvenOptimal(). Also
available are isProvenPrimalInfeasible(),
isProvenDualInfeasible(),
isPrimalObjectiveLimitReached(),
isDualObjectiveLimitReached(),
isIterationLimitReached() or the feared
isAbandoned(). Should one prefer the OSL way of doing
things, model.status() returns as it would in OSL-land, so 0 means optimal,
1 means primal infeasible etc.
Similarly, to pick up the solution values, we can inhabit the virtuous OSI-land
or the not-quite-so-virtuous CLP-land. By this it is meant that there are
const and non-const forms of arrays. It is easier to deal with the non-const
versions, so most of the later elaborate algorithms use them.
Methods for getting solution information
Purpose
OSI-style (virtuous)
CLP style (less virtuous)

Primal column solution
const double * getColSolution()
double * primalColumnSolution()

Dual row solution
const double * getRowPrice()
double * dualColumnSolution()

Primal row solution
const double * getRowActivity()
double * primalRowSolution()

Dual row solution
const double * getReducedCost()
double * dualColumnSolution()

Number of rows in model
int getNumRows()
int numberRows()

Number of columns in model
int getNumCols()
int numberColumns()

The reader may have noted a preference for "number" over
"num" and "column" over "col". This may be a
reaction to when one of the authors was young and 5 or 6 letters was the
maximum in FORTRAN for any name or to early days with Osl when seven characters
were allowed but the first three had to be "EKK"!
Using the above-listed functions, our initial example might be continued as follows:
Possible extension of minimum.cpp
This code sample would pretty-print information about the model's primal and
dual solutions. How to additionally print row and column names is
illustrated in the defaults.cpp file in the
"Samples" directory (the "Samples" are properly addressed
in ). This sample is also useful as it
explicitly performs default actions (e.g. it sets the primal feasiblility
tolerance value to the default value).
The remainder of this chapter will show some more of the basic tasks a user
might want to perform. Apart from presolve we will only be looking at actions
which can be performed when including the single header file
COIN/Clp/include/ClpSimplex.hpp.
Building and Modifying a Model
Rather than reading a model from an MPS file we can load a model from arrays
in memory. There are various loadProblem methods which
are similar to those in OSI. It is easy to add more such methods to CLP if the need arises.
We can copy in integer information by
copyInIntegerInformation(const char * array) where array
is 0 or 1 to say integer and we can drop existing information by
deleteIntegerInformation(). There are various ways of
changing the size of a model. The simplest is
resize(newNumberRows,newNumberColumns) - this will either
truncate model or add default rows or columns - a default row has lower bound
of -infinity and upper bound of +infinity, while a default column has zero cost,
zero lower bound and an upper bound of +infinity.
Normally we would use deleteRows,
addRows, deleteColumns and
addColumns, where the add ones will also add in the
elements. A potentially very useful way of modifying a model is strictly a
constructor. Given a large model and a list of rows and a list of columns it
constructs the model as a subset of the large model. It is possible to change
the order of the columns/rows and to duplicate columns/rows. So a list of
columns 4,4,1,0 will create a new model where the first two columns are copies
of column 4 in original model and the next two are the first two of original
model in reverse order. This can be useful to form a model with piecewise
linear costs by duplicating columns and then modifying bounds and costs.
Tolerances
There are set and get methods for tolerances, for example,
double primalTolerance() and
setPrimalTolerance(double). An individual variable is
deemed primal feasible if it is less than the tolerance referred to by these
methods below its lower bound and less than it above its upper bound.
Similarly for dual tolerances, a variable is deemed to be dual feasible if its
reduced cost is greater than minus the tolerance or its distance to the upper
bound is less than primal tolerance and the reduced cost is less than plus the
tolerance or the distance to lower bound is less than primal tolerance. This
is just complementarity conditions adadpted for tolerances and simple lower and
upper bounds.(Note that the above was stated as for minimization - signs are
reversed for maximization.)
Some Useful Sets and Gets
Some Useful Sets and Gets
Method(s)
Description

setMaximumIterations(int value)
setMaximumSeconds(double value)
These methods tell CLP to stop after a given number of iterations or
seconds.

double objectiveValue()
This method returns the objective value.

const double * getObjCoefficients()
double * objective()
These methods return the objective coefficients.

const double * getRowLower()
double * rowLower()
const double * getRowUpper()
double * rowUpper()
const double * getColLower()
double * columnLower()
const double * getColUpper()
double * columnUpper()
These methods give lower and upper bounds on row and column activities.

infeasibilityRay()
unboundedRay()
If the problem was primal or dual infeasible, these methods will give a
pointer to a ray proving infeasibility.

matrix()
There are more options as the user has great flexibility in how the problem
matrix is stored, but the default is as a
CoinPackedMatrix and so we have that this method
returns a pointer to a CoinPackedMatrix which can
be further manipulated.

getNumElements()
Returns the number of elements in the problem matrix.

setOptimizationDirection(int direction)
optimizationDirection()
These methods set and get the objective sense. The parameter
direction should be +1 to minimize, -1 to maximize,
and 0 to ignore.

Simplex-specific Methods
Some of the most commonly-used methods when working with Simplex are listed in
the table below.
Common Simplex-specific methods
Method(s)
Description

primal(int mode=0)
This applies the primal algorithm. If mode is
set to the default of 0, then the method uses the status variables to
determine basis and solution. If mode is 1 then
the method does a values pass so variables not in basis are given their
current values and one pass of variables is done to clean up the basis
with an equal or better objective value.

dual(int mode=0)
This applies the dual algorithm. if mode is set
to the default of 0, then the method uses the status variables to
determine basis and solution. If mode is 1 then
the method uses input duals and does a values pass so one pass of basic
variables is done to clean up the duals with an equal or better objective
value.

scaling(int mode=1)
This method toggles scaling on (mode set to 1)
and off (mode set to 0).

int crash(double gap,int mode)
This method attemps to improve on an all slack basis and remains a work
in progress. For dual this will move variables to the dual feasible bound
if the gap between bounds is less than gap. Setting
mode to 0 guesses which algorithm is better, while
a value of 1 or 2 will result in more work being done. The return code is
0 if the basis was not slacks in first case, it is negative if dual is
preferred or positive if primal. ±1 means an all slack basis seemed
best, while ±2 means some work was done.

perturb(int mode)
This method toggles perturbation on (mode set to 1)
and off (mode set to 0). It should be considered
a work in progress, although on some problems it gives very good results.

factorizationFrequency()
setFactorizationFrequency(int value)
These are "get" and "set" methods for the basis matrix
factorization frequency. The default is to refactor every 200 iterations,
but it may make more sense to use something such as 100 + the number of
rows divided by 50.

dualBound()
setDualBound(double value)
These are "get" and "set" methods for the
"dual bound". The CLP dual algorithm declares all problems
to be dual feasible by putting non-basic variables to correct bounds for
the reduced cost. If the gap between the bounds is too big then it
pretends the gap is only the value specified by this set method.
In essence, this gives a composite dual rather than a pure
Phase I- Phase II method.

infeasibilityCost()
setInfeasibilityCost(double value)
These are the primal analogs to the "dual bound" methods.

numberPrimalInfeasibilities()
sumPrimalInfeasibilities()
After a solve, there may be infeasibilities. These methods serve to
check for said infeasibilities. One could check the solution explicitly
as well. For a code fragement illustrating this, see
.

Presolve
The header file for the use of CLP's presolve functionality is
COIN/Clp/include/Presolve.hpp. The code fragment below
illustrates some of the possibilities offered by CLP's presolve:
Presolve code fragment
#include "Presolve.hpp"
...
ClpSimplex model; // initialized by readMps or some other method
...
Presolve presolveInfo;
ClpSimplex * presolvedModel = presolveInfo(model);
// at this point we have original model and a new model. The information
// on the operations done is in presolveInfo
if (presolvedModel) {
// was not found to be infeasible - so lets solve
// if presolvedModel was NULL then it was primal infeasible and ...
presolvedModel->dual(); // or whatever else we wish to do
presolveInfo.postsolve(true); // the true updates status arrays in original
/* If the presolved model was optimal then so should the original be.
We can use checkSolution and test feasibility */
model.checkSolution();
if (model.numberDualInfeasibilities()||
model.numberPrimalInfeasibilities()) {
printf("%g dual %g(%d) Primal %g(%d)\n",
model.objectiveValue(),
model.sumDualInfeasibilities(),
model.numberDualInfeasibilities(),
model.sumPrimalInfeasibilities(),
model.numberPrimalInfeasibilities());
// Due to tolerances we can not guarantee that so you may wish to throw in
model.primal(1);
}
Presolve has a few more options which can be found in the header file, for
example whether to treat as an integer problem or whether to keep row and
column names.
Status Array
The astute reader may have noticed that the status array has been mentioned
once or twice. The beginning user will not need to look at it Nevertheless,
for completeness the status of a variable can be found and set as shown below.
The possible state of a variable are listed in the following table (each may
have to be preceded by ClpSimplex::):
Possible states of a variable
State
Description

isFree
Not in basis, has infinite bounds

basic
In basis

atUpperBound
At upper bound

atLowerBound
At lower bound

superBasic
Between bounds, but not basic or free

isFixed
Not in basis, bounds are equal

To get or set the status of a variable is a simple task:
// Get row status...
Status status=model.getRowStatus(sequenceNumber)
// ... or get column status.
Status status=model.getColumnStatus(sequenceNumber)
// Set row status to basic (for example)...
model.setRowStatus(sequenceNumber,ClpSimplex::basic)
// ... or column status to basic.
model.setColumnStatus(sequenceNumber,ClpSimplex::basic)