/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* */
/* This file is part of the program and library */
/* PaPILO --- Parallel Presolve for Integer and Linear Optimization */
/* */
/* Copyright (C) 2020-2022 Konrad-Zuse-Zentrum */
/* fuer Informationstechnik Berlin */
/* */
/* This program is free software: you can redistribute it and/or modify */
/* it under the terms of the GNU Lesser General Public License as published */
/* by the Free Software Foundation, either version 3 of the License, or */
/* (at your option) any later version. */
/* */
/* This program is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU Lesser General Public License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with this program. If not, see . */
/* */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef _PAPILO_PRESOLVERS_FIX_CONTINUOUS_HPP_
#define _PAPILO_PRESOLVERS_FIX_CONTINUOUS_HPP_
#include "papilo/core/PresolveMethod.hpp"
#include "papilo/core/Problem.hpp"
#include "papilo/core/ProblemUpdate.hpp"
namespace papilo
{
/// presolver to fix continuous variables whose bounds are very close
template
class FixContinuous : public PresolveMethod
{
public:
FixContinuous() : PresolveMethod()
{
this->setName( "fixcontinuous" );
this->setTiming( PresolverTiming::kMedium );
this->setType( PresolverType::kContinuousCols );
}
virtual PresolveStatus
execute( const Problem& problem,
const ProblemUpdate& problemUpdate, const Num& num,
Reductions& reductions, const Timer& timer ) override;
};
#ifdef PAPILO_USE_EXTERN_TEMPLATES
extern template class FixContinuous;
extern template class FixContinuous;
extern template class FixContinuous;
#endif
template
PresolveStatus
FixContinuous::execute( const Problem& problem,
const ProblemUpdate& problemUpdate,
const Num& num,
Reductions& reductions, const Timer& timer )
{
assert( problem.getNumContinuousCols() != 0 );
const auto& consMatrix = problem.getConstraintMatrix();
const auto& domains = problem.getVariableDomains();
const auto& cflags = domains.flags;
const auto& objective = problem.getObjective();
const auto& lbs = problem.getLowerBounds();
const auto& ubs = problem.getUpperBounds();
const int ncols = consMatrix.getNCols();
PresolveStatus result = PresolveStatus::kUnchanged;
if( num.getFeasTol() == REAL{ 0 } )
return result;
for( int i = 0; i < ncols; ++i )
{
// dont fix removed or empty columns, integral columns, columns with
// infinity bounds, columns that are already fixed, and columns whose
// bounds are more than epsilon apart
if( cflags[i].test( ColFlag::kUnbounded, ColFlag::kIntegral,
ColFlag::kInactive ) ||
( ubs[i] - lbs[i] ) > num.getFeasTol() )
continue;
assert( consMatrix.getColSizes()[i] >= 0 );
assert( lbs[i] != ubs[i] );
auto colvec = consMatrix.getColumnCoefficients( i );
REAL maxabsval = num.max( colvec.getMaxAbsValue(), 1 );
maxabsval = num.max( abs( objective.coefficients[i] ), maxabsval );
// if the change in activity due to fixing this column is at most
// epsilon in every row we can fix it
if( ( ubs[i] - lbs[i] ) * maxabsval <= num.getFeasTol() )
{
REAL fixval;
// if one bound is an integral value, use that one
if( floor( ubs[i] ) == lbs[i] )
fixval = lbs[i];
else if( ceil( lbs[i] ) == ubs[i] )
fixval = ubs[i];
else // otherwise take the midpoint
fixval = REAL{ 0.5 } * ( ubs[i] + lbs[i] );
TransactionGuard tg{ reductions };
reductions.lockColBounds( i );
reductions.fixCol( i, fixval );
result = PresolveStatus::kReduced;
}
}
return result;
}
} // namespace papilo
#endif