// Copyright (C) 2002, International Business Machines
// Corporation and others. All Rights Reserved.
#include <stdio.h>
#include <assert.h>
#include <iostream>
#include "CoinHelperFunctions.hpp"
#include "CoinPresolveMatrix.hpp"
#include "CoinTime.hpp"
/*! \file
This file contains methods for CoinPresolveMatrix, the object used during
presolve transformations.
*/
/*
Constructor and destructor for CoinPresolveMatrix.
*/
/*
CoinPresolveMatrix constructor
The constructor does very little, for much the same reasons that the
CoinPrePostsolveMatrix constructor does little. Might as well wait until we
load a matrix.
In general, for presolve the allocated size can be equal to the size of the
constraint matrix before presolve transforms are applied. (Presolve
transforms are assumed to reduce the size of the constraint system.) But we
need to keep the *_alloc parameters for compatibility with
CoinPrePostsolveMatrix.
*/
CoinPresolveMatrix::CoinPresolveMatrix
(int ncols_alloc, int nrows_alloc, CoinBigIndex nelems_alloc)
: CoinPrePostsolveMatrix(ncols_alloc,nrows_alloc,nelems_alloc),
clink_(0),
rlink_(0),
dobias_(0.0),
mrstrt_(0),
hinrow_(0),
rowels_(0),
hcol_(0),
integerType_(0),
anyInteger_(false),
tuning_(false),
startTime_(0.0),
feasibilityTolerance_(0.0),
status_(-1),
pass_(0),
maxSubstLevel_(3),
colChanged_(0),
colsToDo_(0),
numberColsToDo_(0),
nextColsToDo_(0),
numberNextColsToDo_(0),
rowChanged_(0),
rowsToDo_(0),
numberRowsToDo_(0),
nextRowsToDo_(0),
numberNextRowsToDo_(0),
presolveOptions_(0),
anyProhibited_(false)
{ /* nothing to do here */
return ; }
/*
CoinPresolveMatrix destructor.
*/
CoinPresolveMatrix::~CoinPresolveMatrix()
{ delete[] clink_ ;
delete[] rlink_ ;
delete[] mrstrt_ ;
delete[] hinrow_ ;
delete[] rowels_ ;
delete[] hcol_ ;
delete[] integerType_ ;
delete[] rowChanged_ ;
delete[] rowsToDo_ ;
delete[] nextRowsToDo_ ;
delete[] colChanged_ ;
delete[] colsToDo_ ;
delete[] nextColsToDo_ ;
return ; }
/*
This routine loads a CoinPackedMatrix and proceeds to do the bulk of the
initialisation for the PrePostsolve and Presolve objects.
In the CoinPrePostsolveMatrix portion of the object, it initialises the
column-major packed matrix representation and the arrays that track the
motion of original columns and rows.
In the CoinPresolveMatrix portion of the object, it initialises the
row-major packed matrix representation, the arrays that assist in matrix
storage management, and the arrays that track the rows and columns to be
processed.
Arrays are allocated to the requested size (ncols0_, nrow0_, nelems0_).
The source matrix must be column ordered; it does not need to be gap-free.
Bulk storage in the column-major (hrow_, colels_) and row-major (hcol_,
rowels_) matrices is allocated at twice the required size so that we can
expand columns and rows as needed. This is almost certainly grossly
oversize, but (1) it's efficient, and (2) the utility routines which
compact the bulk storage areas have no provision to reallocate.
*/
void CoinPresolveMatrix::setMatrix (const CoinPackedMatrix *mtx)
{
/*
Check to make sure the matrix will fit and is column ordered.
*/
if (mtx->isColOrdered() == false)
{ throw CoinError("source matrix must be column ordered",
"setMatrix","CoinPrePostsolveMatrix") ; }
int numCols = mtx->getNumCols() ;
if (numCols > ncols0_)
{ throw CoinError("source matrix exceeds allocated capacity",
"setMatrix","CoinPrePostsolveMatrix") ; }
/*
Acquire the actual size, but allocate the matrix storage to the
requested capacity. The column-major rep is part of the PrePostsolve
object, the row-major rep belongs to the Presolve object.
*/
ncols_ = numCols ;
nrows_ = mtx->getNumRows() ;
nelems_ = mtx->getNumElements() ;
bulk0_ = (CoinBigIndex) (bulkRatio_*nelems0_) ;
if (mcstrt_ == 0) mcstrt_ = new CoinBigIndex [ncols0_+1] ;
if (hincol_ == 0) hincol_ = new int [ncols0_+1] ;
if (hrow_ == 0) hrow_ = new int [bulk0_] ;
if (colels_ == 0) colels_ = new double [bulk0_] ;
if (mrstrt_ == 0) mrstrt_ = new CoinBigIndex [nrows0_+1] ;
if (hinrow_ == 0) hinrow_ = new int [nrows0_+1] ;
if (hcol_ == 0) hcol_ = new int [bulk0_] ;
if (rowels_ == 0) rowels_ = new double [bulk0_] ;
/*
Grab the corresponding vectors from the source matrix.
*/
const CoinBigIndex *src_mcstrt = mtx->getVectorStarts() ;
const int *src_hincol = mtx->getVectorLengths() ;
const double *src_colels = mtx->getElements() ;
const int *src_hrow = mtx->getIndices() ;
/*
Bulk copy the column starts and lengths.
*/
CoinMemcpyN(src_mcstrt,mtx->getSizeVectorStarts(),mcstrt_) ;
CoinMemcpyN(src_hincol,mtx->getSizeVectorLengths(),hincol_) ;
/*
Copy the coefficients column by column in case there are gaps between
the columns in the bulk storage area. The assert is just in case the
gaps are *really* big.
*/
assert(src_mcstrt[ncols_] <= bulk0_) ;
int j;
for ( j = 0 ; j < numCols ; j++)
{ int lenj = src_hincol[j] ;
CoinBigIndex offset = mcstrt_[j] ;
CoinMemcpyN(src_colels+offset,lenj,colels_+offset) ;
CoinMemcpyN(src_hrow+offset,lenj,hrow_+offset) ; }
/*
Now make a row-major copy. Start by counting the number of coefficients in
each row; we can do this directly in hinrow. Given the number of
coefficients in a row, we know how to lay out the bulk storage area.
*/
CoinZeroN(hinrow_,nrows0_+1) ;
for ( j = 0 ; j < ncols_ ; j++)
{ int *rowIndices = hrow_+mcstrt_[j] ;
int lenj = hincol_[j] ;
for (int k = 0 ; k < lenj ; k++)
{ int i = rowIndices[k] ;
hinrow_[i]++ ; } }
/*
Initialize mrstrt[i] to the start of row i+1. As we drop each coefficient
and column index into the bulk storage arrays, we'll decrement and store.
When we're done, mrstrt[i] will point to the start of row i, as it should.
*/
int totalCoeffs = 0 ;
int i;
for ( i = 0 ; i < nrows_ ; i++)
{ totalCoeffs += hinrow_[i] ;
mrstrt_[i] = totalCoeffs ; }
mrstrt_[nrows_] = totalCoeffs ;
for ( j = ncols_-1 ; j >= 0 ; j--)
{ int lenj = hincol_[j] ;
double *colCoeffs = colels_+mcstrt_[j] ;
int *rowIndices = hrow_+mcstrt_[j] ;
for (int k = 0 ; k < lenj ; k++)
{ int ri;
ri = rowIndices[k] ;
double aij = colCoeffs[k] ;
CoinBigIndex l = --mrstrt_[ri] ;
rowels_[l] = aij ;
hcol_[l] = j ; } }
/*
Now the support structures. The entry for original column j should start
out as j; similarly for row i. originalColumn_ and originalRow_ belong to
the PrePostsolve object.
*/
if (originalColumn_ == 0) originalColumn_ = new int [ncols0_] ;
if (originalRow_ == 0) originalRow_ = new int [nrows0_] ;
for ( j = 0 ; j < ncols0_ ; j++)
originalColumn_[j] = j ;
for ( i = 0 ; i < nrows0_ ; i++)
originalRow_[i] = i ;
/*
We have help to set up the clink_ and rlink_ vectors (aids for matrix bulk
storage management). clink_ and rlink_ belong to the Presolve object. Once
this is done, it's safe to set mrstrt_[nrows_] and mcstrt_[ncols_] to the
full size of the bulk storage area.
*/
if (clink_ == 0) clink_ = new presolvehlink [ncols0_+1] ;
if (rlink_ == 0) rlink_ = new presolvehlink [nrows0_+1] ;
presolve_make_memlists(mcstrt_,hincol_,clink_,ncols_) ;
presolve_make_memlists(mrstrt_,hinrow_,rlink_,nrows_) ;
mcstrt_[ncols_] = bulk0_ ;
mrstrt_[nrows_] = bulk0_ ;
/*
No rows or columns have been changed just yet. colChanged_ and rowChanged_
belong to the Presolve object.
*/
if (colChanged_ == 0) colChanged_ = new unsigned char [ncols0_] ;
CoinZeroN(colChanged_,ncols0_) ;
if (rowChanged_ == 0) rowChanged_ = new unsigned char [nrows0_] ;
CoinZeroN(rowChanged_,nrows0_) ;
/*
Finally, allocate the various *ToDo arrays. These are used to track the rows
and columns which should be processed in a given round of presolve
transforms. These belong to the Presolve object. Setting number*ToDo to 0
is all the initialization that's required here.
*/
rowsToDo_ = new int [nrows0_] ;
numberRowsToDo_ = 0 ;
nextRowsToDo_ = new int [nrows0_] ;
numberNextRowsToDo_ = 0 ;
colsToDo_ = new int [ncols0_] ;
numberColsToDo_ = 0 ;
nextColsToDo_ = new int [ncols0_] ;
numberNextColsToDo_ = 0 ;
return ; }
/*
These functions set integer type information. The first expects an array with
an entry for each variable. The second sets all variables to integer or
continuous type.
*/
void CoinPresolveMatrix::setVariableType (const unsigned char *variableType,
int lenParam)
{ int len ;
if (lenParam < 0)
{ len = ncols_ ; }
else
if (lenParam > ncols0_)
{ throw CoinError("length exceeds allocated size",
"setIntegerType","CoinPresolveMatrix") ; }
else
{ len = lenParam ; }
if (integerType_ == 0) integerType_ = new unsigned char [ncols0_] ;
CoinCopyN(variableType,len,integerType_) ;
return ; }
void CoinPresolveMatrix::setVariableType (bool allIntegers, int lenParam)
{ int len ;
if (lenParam < 0)
{ len = ncols_ ; }
else
if (lenParam > ncols0_)
{ throw CoinError("length exceeds allocated size",
"setIntegerType","CoinPresolveMatrix") ; }
else
{ len = lenParam ; }
if (integerType_ == 0) integerType_ = new unsigned char [ncols0_] ;
const unsigned char value = 1 ;
if (allIntegers == true)
{ CoinFillN(integerType_,len,value) ; }
else
{ CoinZeroN(integerType_,len) ; }
return ; }
/*
The next pair of routines initialises the [row,col]ToDo lists in preparation
for a major pass. All except rows/columns marked as prohibited are added to
the lists.
*/
void CoinPresolveMatrix::initColsToDo ()
/*
Initialize the ToDo lists in preparation for a major iteration of
preprocessing. First, cut back the ToDo and NextToDo lists to zero entries.
Then place all columns not marked prohibited on the ToDo list.
*/
{ int j ;
numberNextColsToDo_ = 0 ;
if (anyProhibited_ == false)
{ for (j = 0 ; j < ncols_ ; j++)
{ colsToDo_[j] = j ; }
numberColsToDo_ = ncols_ ; }
else
{ numberColsToDo_ = 0 ;
for (j = 0 ; j < ncols_ ; j++)
if (colProhibited(j) == false)
{ colsToDo_[numberColsToDo_++] = j ; } }
return ; }
void CoinPresolveMatrix::initRowsToDo ()
/*
Initialize the ToDo lists in preparation for a major iteration of
preprocessing. First, cut back the ToDo and NextToDo lists to zero entries.
Then place all rows not marked prohibited on the ToDo list.
*/
{ int i ;
numberNextRowsToDo_ = 0 ;
if (anyProhibited_ == false)
{ for (i = 0 ; i < nrows_ ; i++)
{ rowsToDo_[i] = i ; }
numberRowsToDo_ = nrows_ ; }
else
{ numberRowsToDo_ = 0 ;
for (i = 0 ; i < nrows_ ; i++)
if (rowProhibited(i) == false)
{ rowsToDo_[numberRowsToDo_++] = i ; } }
return ; }
int CoinPresolveMatrix::stepColsToDo ()
/*
This routine transfers the contents of NextToDo to ToDo, simultaneously
resetting the Changed indicator. It returns the number of columns
transfered.
*/
{ int k ;
for (k = 0 ; k < numberNextColsToDo_ ; k++)
{ int j = nextColsToDo_[k] ;
unsetColChanged(j) ;
colsToDo_[k] = j ; }
numberColsToDo_ = numberNextColsToDo_ ;
numberNextColsToDo_ = 0 ;
return (numberColsToDo_) ; }
int CoinPresolveMatrix::stepRowsToDo ()
/*
This routine transfers the contents of NextToDo to ToDo, simultaneously
resetting the Changed indicator. It returns the number of columns
transfered.
*/
{ int k ;
for (k = 0 ; k < numberNextRowsToDo_ ; k++)
{ int i = nextRowsToDo_[k] ;
unsetRowChanged(i) ;
rowsToDo_[k] = i ; }
numberRowsToDo_ = numberNextRowsToDo_ ;
numberNextRowsToDo_ = 0 ;
return (numberRowsToDo_) ; }
// Say we want statistics - also set time
void
CoinPresolveMatrix::statistics()
{
tuning_=true;
startTime_ = CoinCpuTime();
}
syntax highlighted by Code2HTML, v. 0.9.1