/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* */ /* 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_IO_SOL_WRITER_HPP_ #define _PAPILO_IO_SOL_WRITER_HPP_ #include "papilo/Config.hpp" #include "papilo/misc/Vec.hpp" #include "papilo/misc/fmt.hpp" #include #include #include #include #ifdef PAPILO_USE_BOOST_IOSTREAMS_WITH_BZIP2 #include #endif #ifdef PAPILO_USE_BOOST_IOSTREAMS_WITH_ZLIB #include #endif namespace papilo { /// Writer to write problem structures into an mps file template struct SolWriter { static void writePrimalSol( const std::string& filename, const Vec& sol, const Vec& objective, const REAL& solobj, const Vec& colnames ) { std::ofstream file( filename, std::ofstream::out ); boost::iostreams::filtering_ostream out; #ifdef PAPILO_USE_BOOST_IOSTREAMS_WITH_ZLIB if( boost::algorithm::ends_with( filename, ".gz" ) ) out.push( boost::iostreams::gzip_compressor() ); #endif #ifdef PAPILO_USE_BOOST_IOSTREAMS_WITH_BZIP2 if( boost::algorithm::ends_with( filename, ".bz2" ) ) out.push( boost::iostreams::bzip2_compressor() ); #endif out.push( file ); fmt::print( out, "{: <50} {: <18.15}\n", "=obj=", double( solobj ) ); for( int i = 0; i != (int) sol.size(); ++i ) { if( sol[i] != 0.0 ) { fmt::print( out, "{: <50} {: <18.15} obj({:.15})\n", colnames[i], double( sol[i] ), double( objective[i] ) ); } } } static void writeDualSol( const std::string& filename, const Vec& sol, const Vec& rhs, const Vec& lhs, const REAL& obj_value, const Vec& row_names ) { std::ofstream file( filename, std::ofstream::out ); boost::iostreams::filtering_ostream out; #ifdef PAPILO_USE_BOOST_IOSTREAMS_WITH_ZLIB if( boost::algorithm::ends_with( filename, ".gz" ) ) out.push( boost::iostreams::gzip_compressor() ); #endif #ifdef PAPILO_USE_BOOST_IOSTREAMS_WITH_BZIP2 if( boost::algorithm::ends_with( filename, ".bz2" ) ) out.push( boost::iostreams::bzip2_compressor() ); #endif out.push( file ); fmt::print( out, "{: <50} {: <18.15}\n", "=obj=", double( obj_value ) ); for( int i = 0; i < (int) sol.size(); ++i ) { if( sol[i] != 0.0 ) { REAL objective = lhs[i]; if( sol[i] < 0 ) objective = rhs[i]; fmt::print( out, "{: <50} {: <18.15} obj({:.15})\n", row_names[i], double( sol[i] ), double( objective ) ); } } } static void writeReducedCostsSol( const std::string& filename, const Vec& sol, const Vec& ub, const Vec& lb, const REAL& solobj, const Vec& col_names ) { std::ofstream file( filename, std::ofstream::out ); boost::iostreams::filtering_ostream out; #ifdef PAPILO_USE_BOOST_IOSTREAMS_WITH_ZLIB if( boost::algorithm::ends_with( filename, ".gz" ) ) out.push( boost::iostreams::gzip_compressor() ); #endif #ifdef PAPILO_USE_BOOST_IOSTREAMS_WITH_BZIP2 if( boost::algorithm::ends_with( filename, ".bz2" ) ) out.push( boost::iostreams::bzip2_compressor() ); #endif out.push( file ); fmt::print( out, "{: <50} {: <18.15}\n", "=obj=", double( solobj ) ); for( int i = 0; i < (int) sol.size(); ++i ) { if( sol[i] != 0.0 ) { REAL objective = lb[i]; if( sol[i] < 0 ) objective = ub[i]; fmt::print( out, "{: <50} {: <18.15} obj({:.15})\n", col_names[i], double( sol[i] ), double( objective ) ); } } } static void writeBasis( const std::string& filename, const Vec& colBasis, const Vec& rowBasis, const Vec& col_names, const Vec& row_names ) { std::ofstream file( filename, std::ofstream::out ); boost::iostreams::filtering_ostream out; #ifdef PAPILO_USE_BOOST_IOSTREAMS_WITH_ZLIB if( boost::algorithm::ends_with( filename, ".gz" ) ) out.push( boost::iostreams::gzip_compressor() ); #endif #ifdef PAPILO_USE_BOOST_IOSTREAMS_WITH_BZIP2 if( boost::algorithm::ends_with( filename, ".bz2" ) ) out.push( boost::iostreams::bzip2_compressor() ); #endif int rowSize = (int) rowBasis.size(); assert(colBasis.size() == col_names.size()); assert( rowSize == row_names.size()); out.push( file ); int row = 0; fmt::print( out, "NAME papilo.bas\n"); for( int col = 0; col < (int) colBasis.size(); ++col ) { if( colBasis[col] == VarBasisStatus::BASIC ) { /* Find non basic row */ for(; row < rowSize; row++) { if(rowBasis[row] != VarBasisStatus::BASIC) break; } assert( rowBasis[row] == VarBasisStatus::ON_UPPER || rowBasis[row] == VarBasisStatus::ON_LOWER || rowBasis[row] == VarBasisStatus::ZERO || rowBasis[row] == VarBasisStatus::FIXED ); if( colBasis[col] == VarBasisStatus::ON_UPPER ) fmt::print( out, " XU {: <50} {: <50}\n", col_names[col], row_names[row]); else fmt::print( out, " XL {: <50} {: <50}\n", col_names[col], row_names[row]); row++; } else if( colBasis[col] == VarBasisStatus::ON_UPPER ) fmt::print( out, " UL {: <50}\n", col_names[col]); else if( colBasis[col] == VarBasisStatus::ON_LOWER || colBasis[col] == VarBasisStatus::ZERO ) { /* Default is all non-basic variables on lower bound (if finite) or * at zero (if free). nothing to do in this case. */ } else assert( false ); } fmt::print( out, "ENDDATA\n"); // assert(check_if_remaining_rows_are_basic( rowBasis, rowSize, row )); } static bool check_if_remaining_rows_are_basic( const Vec& rowBasis, int rowSize, int row ) { // Check that we covered all nonbasic rows - the remaining should be basic. for(; row < rowSize; row++) { if(rowBasis[row] != VarBasisStatus::BASIC) break; } return row == rowSize ; } }; } // namespace papilo #endif