// $Id$
// Copyright (C) 2000, International Business Machines
// Corporation and others. All Rights Reserved.
// This code is licensed under the terms of the Eclipse Public License (EPL).
#include "VolVolume.hpp"
#include "CoinHelperFunctions.hpp"
#include "CoinPackedMatrix.hpp"
#include "CoinMpsIO.hpp"
//#############################################################################
class lpHook : public VOL_user_hooks {
private:
lpHook(const lpHook&);
lpHook& operator=(const lpHook&);
private:
/// Pointer to dense vector of structural variable upper bounds
double *colupper_;
/// Pointer to dense vector of structural variable lower bounds
double *collower_;
/// Pointer to dense vector of objective coefficients
double *objcoeffs_;
/// Pointer to dense vector of right hand sides
double *rhs_;
/// Pointer to dense vector of senses
char *sense_;
/// The problem matrix in a row ordered form
CoinPackedMatrix rowMatrix_;
/// The problem matrix in a column ordered form
CoinPackedMatrix colMatrix_;
public:
lpHook(const double* clb, const double* cub, const double* obj,
const double* rhs, const char* sense, const CoinPackedMatrix& mat);
virtual ~lpHook();
public:
// for all hooks: return value of -1 means that volume should quit
/** compute reduced costs
@param u (IN) the dual variables
@param rc (OUT) the reduced cost with respect to the dual values
*/
virtual int compute_rc(const VOL_dvector& u, VOL_dvector& rc);
/** Solve the subproblem for the subgradient step.
@param dual (IN) the dual variables
@param rc (IN) the reduced cost with respect to the dual values
@param lcost (OUT) the lagrangean cost with respect to the dual values
@param x (OUT) the primal result of solving the subproblem
@param v (OUT) b-Ax for the relaxed constraints
@param pcost (OUT) the primal objective value of x
*/
virtual int solve_subproblem(const VOL_dvector& dual, const VOL_dvector& rc,
double& lcost, VOL_dvector& x, VOL_dvector& v,
double& pcost);
/** Starting from the primal vector x, run a heuristic to produce
an integer solution
@param x (IN) the primal vector
@param heur_val (OUT) the value of the integer solution (return
DBL_MAX
here if no feas sol was found
*/
virtual int heuristics(const VOL_problem& p,
const VOL_dvector& x, double& heur_val) {
return 0;
}
};
//#############################################################################
lpHook::lpHook(const double* clb, const double* cub, const double* obj,
const double* rhs, const char* sense,
const CoinPackedMatrix& mat)
{
const int colnum = mat.getNumCols();
const int rownum = mat.getNumRows();
colupper_ = new double[colnum];
collower_ = new double[colnum];
objcoeffs_ = new double[colnum];
rhs_ = new double[rownum];
sense_ = new char[rownum];
std::copy(clb, clb + colnum, collower_);
std::copy(cub, cub + colnum, colupper_);
std::copy(obj, obj + colnum, objcoeffs_);
std::copy(rhs, rhs + rownum, rhs_);
std::copy(sense, sense + rownum, sense_);
if (mat.isColOrdered()) {
colMatrix_.copyOf(mat);
rowMatrix_.reverseOrderedCopyOf(mat);
} else {
rowMatrix_.copyOf(mat);
colMatrix_.reverseOrderedCopyOf(mat);
}
}
//-----------------------------------------------------------------------------
lpHook::~lpHook()
{
delete[] colupper_;
delete[] collower_;
delete[] objcoeffs_;
delete[] rhs_;
delete[] sense_;
}
//#############################################################################
int
lpHook::compute_rc(const VOL_dvector& u, VOL_dvector& rc)
{
rowMatrix_.transposeTimes(u.v, rc.v);
const int psize = rowMatrix_.getNumCols();
for (int i = 0; i < psize; ++i)
rc[i] = objcoeffs_[i] - rc[i];
return 0;
}
//-----------------------------------------------------------------------------
int
lpHook::solve_subproblem(const VOL_dvector& dual, const VOL_dvector& rc,
double& lcost, VOL_dvector& x, VOL_dvector& v,
double& pcost)
{
int i;
const int psize = x.size();
const int dsize = v.size();
// compute the lagrangean solution corresponding to the reduced costs
for (i = 0; i < psize; ++i)
x[i] = (rc[i] >= 0.0) ? collower_[i] : colupper_[i];
// compute the lagrangean value (rhs*dual + primal*rc)
lcost = 0;
for (i = 0; i < dsize; ++i)
lcost += rhs_[i] * dual[i];
for (i = 0; i < psize; ++i)
lcost += x[i] * rc[i];
// compute the rhs - lhs
colMatrix_.times(x.v, v.v);
for (i = 0; i < dsize; ++i)
v[i] = rhs_[i] - v[i];
// compute the lagrangean primal objective
pcost = 0;
for (i = 0; i < psize; ++i)
pcost += x[i] * objcoeffs_[i];
return 0;
}
//#############################################################################
int
main(int argc, char * argv[])
{
const char extension[4] = "mps";
if (argc != 2) {
printf("Usage: vollp \n (omitting the .mps)\n");
exit(1);
}
CoinMpsIO mpsio;
mpsio.readMps(argv[1], extension);
printf("\n\n\n\n ============== Starting volume =================\n\n\n\n");
VOL_problem volprob;
const CoinPackedMatrix* mat = mpsio.getMatrixByCol();
const int psize = mat->getNumCols();
const int dsize = mat->getNumRows();
char * sense = new char[dsize];
memcpy(sense, mpsio.getRowSense(), dsize);
// Set the lb/ub on the duals
volprob.dsize = dsize;
volprob.psize = psize;
volprob.dual_lb.allocate(dsize);
volprob.dual_ub.allocate(dsize);
int i;
for (i = 0; i < dsize; ++i) {
switch (sense[i]) {
case 'E':
volprob.dual_lb[i] = -1.0e31;
volprob.dual_ub[i] = 1.0e31;
break;
case 'L':
volprob.dual_lb[i] = -1.0e31;
volprob.dual_ub[i] = 0.0;
break;
case 'G':
volprob.dual_lb[i] = 0.0;
volprob.dual_ub[i] = 1.0e31;
break;
default:
printf("Volume Algorithm can't work if there is a non ELG row\n");
abort();
}
}
lpHook myHook(mpsio.getColLower(), mpsio.getColUpper(),
mpsio.getObjCoefficients(),
mpsio.getRightHandSide(), mpsio.getRowSense(), *mat);
volprob.solve(myHook, false /* no warmstart */);
//------------- extract the solution ---------------------------
printf("Best lagrangean value: %f\n", volprob.value);
double avg = 0;
for (i = 0; i < dsize; ++i) {
switch (sense[i]) {
case 'E':
avg += CoinAbs(volprob.viol[i]);
break;
case 'L':
if (volprob.viol[i] < 0)
avg += (-volprob.viol[i]);
break;
case 'G':
if (volprob.viol[i] > 0)
avg += volprob.viol[i];
break;
}
}
printf("Average primal constraint violation: %f\n", avg/dsize);
// volprob.dsol contains the dual solution (dual feasible)
// volprob.psol contains the primal solution
// (NOT necessarily primal feasible)
return 0;
}