/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* */
/* 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_CORE_PROBLEM_BUILDER_HPP_
#define _PAPILO_CORE_PROBLEM_BUILDER_HPP_
namespace papilo
{
#include "papilo/core/MatrixBuffer.hpp"
#include "papilo/core/Problem.hpp"
#include "papilo/misc/String.hpp"
#include "papilo/misc/Vec.hpp"
template
class ProblemBuilder
{
public:
/// Sets the number of columns to the given value. The information of columns
/// that already exist is kept, new columns are continuous and fixed to zero.
/// If the number of columns is reduced, then the information for the removed
/// columns is lost.
void
setNumCols( int ncols )
{
// allocate column information
obj.coefficients.resize( ncols );
domains.lower_bounds.resize( ncols );
domains.upper_bounds.resize( ncols );
domains.flags.resize( ncols );
colnames.resize( ncols );
}
/// Sets the number of rows to the given value. The information of rows that
/// already exist is kept, new rows are qualities with right hand side zero.
/// If the number of rows is reduced, then the information for the removed
/// rows is lost.
void
setNumRows( int nrows )
{
// allocate row information
lhs.resize( nrows );
rhs.resize( nrows );
rflags.resize( nrows );
rownames.resize( nrows );
}
/// Returns the current number of rows
int
getNumRows() const
{
return static_cast( rflags.size() );
}
/// Returns the current number of cols
int
getNumCols() const
{
return static_cast( domains.flags.size() );
}
/// reserve storage for the given number of non-zeros
void
reserve( int nnz, int nrows, int ncols )
{
matrix_buffer.reserve( nnz );
// reserve space for row information
lhs.reserve( nrows );
rhs.reserve( nrows );
rflags.reserve( nrows );
rownames.reserve( nrows );
// reserve space for column information
obj.coefficients.reserve( ncols );
domains.lower_bounds.reserve( ncols );
domains.upper_bounds.reserve( ncols );
domains.flags.reserve( ncols );
colnames.reserve( ncols );
}
/// change the objective coefficient of a column
void
setObj( int col, REAL val )
{
obj.coefficients[col] = std::move( val );
}
/// change the objective coefficient of all columns
void
setObjAll( Vec values )
{
assert( values.size() == obj.coefficients.size() );
for( int c = 0; c < (int) values.size(); ++c )
obj.coefficients[c] = std::move( values[c] );
}
/// change the objectives constant offset
void
setObjOffset( REAL val )
{
obj.offset = std::move( val );
}
void
setColLbInf( int col, bool isInfinite )
{
if( isInfinite )
domains.flags[col].set( ColFlag::kLbInf );
else
domains.flags[col].unset( ColFlag::kLbInf );
}
void
setColLbInfAll( Vec isInfinite )
{
assert( domains.flags.size() == isInfinite.size() );
for( int c = 0; c < (int) isInfinite.size(); ++c )
setColLbInf( c, isInfinite[c] );
}
void
setColUbInf( int col, bool isInfinite )
{
if( isInfinite )
domains.flags[col].set( ColFlag::kUbInf );
else
domains.flags[col].unset( ColFlag::kUbInf );
}
void
setColUbInfAll( Vec isInfinite )
{
assert( domains.flags.size() == isInfinite.size() );
for( int c = 0; c < (int) isInfinite.size(); ++c )
setColUbInf( c, isInfinite[c] );
}
void
setColLb( int col, REAL lb )
{
domains.lower_bounds[col] = std::move( lb );
}
void
setColLbAll( Vec lbs )
{
assert( lbs.size() == domains.lower_bounds.size() );
for( int c = 0; c < (int) lbs.size(); ++c )
domains.lower_bounds[c] = std::move( lbs[c
] );
}
void
setColUb( int col, REAL ub )
{
domains.upper_bounds[col] = std::move( ub );
}
void
setColUbAll( Vec ubs )
{
assert( ubs.size() == domains.upper_bounds.size() );
for( int c = 0; c < (int) ubs.size(); ++c )
domains.upper_bounds[c] = std::move( ubs[c] );
}
void
setColIntegral( int col, bool isIntegral )
{
if( isIntegral )
domains.flags[col].set( ColFlag::kIntegral );
else
domains.flags[col].unset( ColFlag::kIntegral );
}
void
setColImplInt( int col, bool isImplInt )
{
if( isImplInt )
domains.flags[col].set( ColFlag::kImplInt );
else
domains.flags[col].unset( ColFlag::kImplInt );
}
void
setColIntegralAll( Vec isIntegral )
{
assert( isIntegral.size() == domains.flags.size() );
for( int c = 0; c < (int) isIntegral.size(); ++c )
setColIntegral( c, isIntegral[c] );
}
void
setRowLhsInf( int row, bool isInfinite )
{
if( isInfinite )
rflags[row].set( RowFlag::kLhsInf );
else
rflags[row].unset( RowFlag::kLhsInf );
}
void
setRowLhsInfAll( Vec isInfinite )
{
assert( isInfinite.size() == rflags.size() );
for( int r = 0; r < (int) isInfinite.size(); ++r )
setRowLhsInf( r, isInfinite[r] );
}
void
setRowRhsInf( int row, bool isInfinite )
{
if( isInfinite )
rflags[row].set( RowFlag::kRhsInf );
else
rflags[row].unset( RowFlag::kRhsInf );
}
void
setRowRhsInfAll( Vec isInfinite )
{
assert( isInfinite.size() == rflags.size() );
for( int r = 0; r < (int) isInfinite.size(); ++r )
setRowRhsInf( r, isInfinite[r] );
}
void
setRowLhs( int row, REAL lhsval )
{
lhs[row] = std::move( lhsval );
}
void
setRowLhsAll( Vec lhsvals )
{
assert( lhsvals.size() == lhs.size() );
for( int r = 0; r < (int) lhsvals.size(); ++r )
lhs[r] = std::move( lhsvals[r] );
}
void
setRowRhs( int row, REAL rhsval )
{
rhs[row] = std::move( rhsval );
}
void
setRowRhsAll( Vec rhsvals )
{
assert( rhsvals.size() == rhs.size() );
for( int r = 0; r < (int) rhsvals.size(); ++r )
rhs[r] = std::move( rhsvals[r] );
}
/// add a nonzero entry for the given row and column
void
addEntry( int row, int col, const REAL& val )
{
assert( val != 0 );
matrix_buffer.addEntry( row, col, val );
}
/// add all given entries given in tripel: (row,col,val)
void
addEntryAll( Vec> entries )
{
for( auto trp : entries )
addEntry( std::get<0>( trp ), std::get<1>( trp ), std::get<2>( trp ) );
}
/// add the nonzero entries for the given row
template
void
addRowEntries( int row, int len, const int* cols, const R* vals )
{
for( int i = 0; i != len; ++i )
{
assert( vals[i] != 0 );
matrix_buffer.addEntry( row, cols[i], REAL{ vals[i] } );
}
}
template
void
setRowName( int row, Str&& name )
{
rownames[row] = String( name );
}
template
void
setRowNameAll( Vec names )
{
assert( rownames.size() == names.size() );
for( int r = 0; r < (int) names.size(); ++r )
rownames[r] = String( names[r] );
}
template
void
setColName( int col, Str&& name )
{
colnames[col] = String( name );
}
template
void
setColNameAll( Vec names )
{
assert( colnames.size() == names.size() );
for( int c = 0; c < (int) names.size(); ++c )
colnames[c] = String( names[c] );
}
template
void
setProblemName( Str&& name )
{
probname = String( name );
}
/// add the nonzero entries for the given column
template
void
addColEntries( int col, int len, const int* rows, const R* vals )
{
for( int i = 0; i != len; ++i )
{
assert( vals[i] != 0 );
matrix_buffer.addEntry( rows[i], col, REAL{ vals[i] } );
}
}
Problem
build()
{
Problem problem;
int nRows = lhs.size();
int nColumns = obj.coefficients.size();
problem.setName( std::move( probname ) );
problem.setConstraintMatrix( ConstraintMatrix{
matrix_buffer.buildCSR( nRows, nColumns ),
matrix_buffer.buildCSC( nRows, nColumns ), std::move( lhs ),
std::move( rhs ), std::move( rflags ) } );
matrix_buffer.clear();
problem.setObjective( std::move( obj ) );
problem.setVariableDomains( std::move( domains ) );
problem.setVariableNames( std::move( colnames ) );
problem.setConstraintNames( std::move( rownames ) );
ConstraintMatrix& matrix = problem.getConstraintMatrix();
for(int i=0; i< problem.getNRows(); i++){
RowFlags rowFlag = matrix.getRowFlags()[i];
if( !rowFlag.test( RowFlag::kRhsInf ) &&
!rowFlag.test( RowFlag::kLhsInf ) &&
matrix.getLeftHandSides()[i] == matrix.getRightHandSides()[i] )
matrix.getRowFlags()[i].set(RowFlag::kEquation);
}
return problem;
}
private:
MatrixBuffer matrix_buffer;
Objective obj;
VariableDomains domains;
Vec lhs;
Vec rhs;
Vec rflags;
Vec rownames;
Vec colnames;
String probname;
};
} // namespace papilo
#endif