Re-solving Linear Programs with COIN-OR

I recently had to go from solving a Linear Program (LP) once only, to modifying the problem and re-solving it multiple times. I was using the excellent open source COIN-OR libraries as my interface (OSI) and solver (CLP).

I found that you will get obscure-looking crashes (though, to be sure, I am using the downloaded binaries, not building COIN from source) inside OSI/COIN if you do not keep around the matrix and vector objects that you use to build your LP. It is safe to delete these objects if you are solving the problem once only, even before you have called initialSolve(). But it is not safe if you have to re-solve the LP!

A simple generic little helper class I used for this is:

class LPObjects
CoinPackedMatrix* m_matrix;
double* m_objective, * m_col_lb, * m_col_ub, * m_rowrhs, * m_rowsen;

m_objective = NULL;
m_col_lb = m_col_ub = NULL;
m_rowrhs = m_rowsen = NULL;
m_matrix = NULL;

void Create(int n_cols, int n_rows, double dblInfinity)
m_objective = new double[n_cols]; //the objective coefficients
m_col_lb = new double[n_cols]; //the column lower bounds
m_col_ub = new double[n_cols]; //the column upper bounds
m_rowrhs = new double[n_rows]; //the row rhs
m_rowsen = new char[n_rows]; //the row sense

for (int i = 0; i
m_objective[i] = 0.0;
for (int i = 0; i
m_col_lb[i] = 0.0;
m_col_ub[i] = dblInfinity;
m_matrix = new CoinPackedMatrix(false, 0, 0);
m_matrix->setDimensions(0, n_cols);

If si is your OsiXxxSolverInterface object, and g_LP is a static pointer to an instance of LPObjects, then g_LP can be initialised with:

if (g_LP == NULL)
g_LP = new LPObjects;
g_LP->Create(n_cols, n_rows, si->getInfinity());

Create your problem representation by filling out rowrhs, rowsen, etc, and be sure to use CoinPackedMatrix’s appendRows to populate your matrix coefficients in bulk rather than using multiple calls to appendRow (which is much much slower for larger LPs).

Then load your problem into OSI with:

si->loadProblem(*g_LP->m_matrix, g_LP->m_col_lb, g_LP->m_col_ub, g_LP->m_objective, g_LP->m_rowsen, g_LP->m_rowrhs, NULL);

and solve with si->initialSolve(). Now you change the LP using the usual methods such as si->setColUpper(), and re-solve with si->resolve(). Note your call to si->setColUpper() (or whatever) does not directly reference the matrix or vectors of g_LP, but those objects must remain in memory!

Code used with binary distribution “CoinAll-1.2.0-win32-msvc9” under Windows Vista / Visual C++ Express 2008.