//================================================================================================== // L i n e a r _ s y s t e m Interface // G l p k // By Bruno Bachelet //================================================================================================== // Copyright (c) 1999-2016 // Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net // // This file is part of the B++ Library. This library is free software; you can redistribute it // and/or modify it under the terms of the GNU Library General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your option) any later // version. // // This library 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 Library General Public License for more details (http://www.gnu.org).
/*DESCRIPTION*/ /* This module provides facilities to solve linear programs with the GLPK 4.54 package. */
// File Name //------------------------------------------------------------------------------------- #line __LINE__ "linear_system/glpk.hpp"
// Guardian //-------------------------------------------------------------------------------------- #ifndef guLinearSystemGlpk #define guLinearSystemGplk
// Headers //--------------------------------------------------------------------------------------- #include <cstdio> /*INCLUDE*/ #include <bpp/linear_system/solver.hpp> /*INCLUDE*/
#ifdef GLPK_YES extern "C" { #include <glpk.h> /*INCLUDE*/
#undef str2dbl // May conflict with JNI. } #endif
namespace bpp {
// Importation/Exportation //----------------------------------------------------------------------- #ifdef LINEAR_SYSTEM_DLL #define dll_export DLL_EXPORT #else #define dll_export DLL_IMPORT #endif
// Namespaces //------------------------------------------------------------------------------------ #define public_area linearSystemGlpk #define private_area linearSystemGlpk_private
namespace public_area { /*NAMESPACE*/ using namespace linearSystemSolver; } namespace private_area { using namespace public_area; }
extern_module_name;
// Initialization //-------------------------------------------------------------------------------- #define iniLinearSystemGlpk has_initializer;
// Macrocommands //--------------------------------------------------------------------------------- #ifdef GLPK_YES /*MACROCOMMAND*/ /* The expression <CODE>prLine</CODE> is integrated into the source code if GLPK is used. */ #define glpk_yes(prLine) prLine
/*MACROCOMMAND*/ /* The expression <CODE>prLine</CODE> is integrated into the source code if GLPK is not used. */ #define glpk_no(prLine) #else #define glpk_yes(prLine) #define glpk_no(prLine) prLine #endif
// Types & Classes //------------------------------------------------------------------------------- namespace public_area { //------------------------------------------------------------------------------------------Classes template <class prContent> class clGlpkSolver; }
namespace private_area {}
// Functions Interface //--------------------------------------------------------------------------- namespace public_area {} namespace private_area { function int glpkPrint(tyPointer,tcString); }
// Errors //---------------------------------------------------------------------------------------- namespace public_area { /*ERROR*/ extern_error erGlpkImproperUse; /* Improper use of the GLPK solver. */
/*ERROR*/ extern_error erGlpkIterationLimitExceeded; /* The maximum number of iterations is reached. */
/*ERROR*/ extern_error erGlpkNumericalProblem; /* Numerical problem to solve the linear program. */
/*ERROR*/ extern_error erGlpkTimeLimitExceeded; /* The maximum time of execution is reached. */
/*ERROR*/ extern_error erGlpkUnknownError; /* An unknown error has occurred in the GLPK package. */
glpk_no ( /*ERROR*/ extern_error erGlpkNotInstalled; /* The library is not built for the use of the GLPK package. */ ) }
// Constants & Variables //------------------------------------------------------------------------- extern_dynamic_constant(private,clString,goTempoResultFileName,?);
// G l p k S o l v e r Interface //---------------------------------------------------------------- namespace public_area { /*CLASS clGlpkSolver */ /* Represents the GLPK solver. */ template <class prContent> class clGlpkSolver : public linearSystemSolver::clSolver<prContent> { //-----------------------------------------------------------------------------------------Private private_property clGlpkSolver & operator = (const clGlpkSolver &); //------------------------------------------------------------------------------------------Public public_property constructor clGlpkSolver(void); public_property constructor clGlpkSolver(const clGlpkSolver &); public_property destructor clGlpkSolver(void);
public_property tyBoolean available(void) const; public_property tyInteger analyzeResult(clInStream &,clLinearSystem<prContent> &) const;
public_property void generateCommand(tcString,tcString,const clLinearSystem<prContent> &) const;
public_property void generateModel(clOutStream &,const clLinearSystem<prContent> &) const; public_property tcString name(void) const; public_property void outTemporary(clOutStream &) const; public_property void removeTemporary(void) const; public_property tyInteger run(clLinearSystem<prContent> &) const; }; }
// Functions Inline //------------------------------------------------------------------------------ namespace public_area {} namespace private_area {}
// G l p k S o l v e r Inline //------------------------------------------------------------------- namespace public_area { //--------------------------------------------------------------------------------------Constructor /*METHOD clGlpkSolver */ /* Builds a GLPK solver. */ template <class prContent> inline clGlpkSolver<prContent>::clGlpkSolver(void) : linearSystemSolver::clSolver<prContent>() {} //--------------------------------------------------------------------------------------Constructor /*METHOD clGlpkSolver */ /* Builds a GLPK solver from another one. */ template <class prContent> inline clGlpkSolver<prContent>::clGlpkSolver(const clGlpkSolver<prContent> &) : clSolver<prContent>() {} //---------------------------------------------------------------------------------------Destructor /*METHOD clGlpkSolver */ /* Destructs the solver. */ template <class prContent> inline clGlpkSolver<prContent>::~clGlpkSolver(void) {} //----------------------------------------------------------------------------------------Available /*METHOD clGlpkSolver */ /* Indicates if the GLPK solver is available. */ template <class prContent> inline tyBoolean clGlpkSolver<prContent>::available(void) const { glpk_yes ( return (true); ) glpk_no ( return (false); ) } //------------------------------------------------------------------------------------AnalyzeResult /*METHOD clGlpkSolver */ /* Not used, throws an exception if called. */ template <class prContent> inline tyInteger clGlpkSolver<prContent>::analyzeResult(clInStream &,clLinearSystem<prContent> &) const { send_inline_error(erGlpkImproperUse,"glpkSolver::analyzeResult"); return (0); } //----------------------------------------------------------------------------------GenerateCommand /*METHOD clGlpkSolver */ /* Not used, throws an exception if called. */ template <class prContent> inline void clGlpkSolver<prContent>::generateCommand(tcString,tcString, const clLinearSystem<prContent> &) const { send_inline_error(erGlpkImproperUse,"glpkSolver::generateCommand"); } //------------------------------------------------------------------------------------GenerateModel /*METHOD clGlpkSolver */ /* Not used, throws an exception if called. */ template <class prContent> inline void clGlpkSolver<prContent>::generateModel(clOutStream &,const clLinearSystem<prContent> &) const { send_inline_error(erGlpkImproperUse,"glpkSolver::generateModel"); } //---------------------------------------------------------------------------------------------Name /*METHOD clGlpkSolver */ /* Returns the name of the solver. It is always "GLPK". */ template <class prContent> inline tcString clGlpkSolver<prContent>::name(void) const { return ("GLPK"); } }
// Function Implementation //----------------------------------------------------------------------- namespace public_area {} namespace private_area {}
// G l p k S o l v e r Implementation //----------------------------------------------------------- namespace public_area { //-------------------------------------------------------------------------------------OutTemporary /*METHOD clGlpkSolver */ /* Writes into a stream the last intermediate files used and generated by the GLPK software to solve a linear program. */ template <class prContent> void clGlpkSolver<prContent>::outTemporary(clOutStream & agStream) const { method_name("glpkSolver::outTemporary");
clInFile lcFile;
agStream << "[>] Temporary Result File:" << end_line; open(lcFile,private_area::goTempoResultFileName->data(),ios::in|ios::binary); copy(agStream,lcFile,false); close(lcFile); if (lcFile.fail()) send_error(erFileReading); } //----------------------------------------------------------------------------------RemoveTemporary /*METHOD clGlpkSolver */ /* Removes the last intermediate files used and generated by the GLPK package to solve a linear program. */ template <class prContent> void clGlpkSolver<prContent>::removeTemporary(void) const { removeFile(private_area::goTempoResultFileName->data()); } //----------------------------------------------------------------------------------------------Run /*METHOD clGlpkSolver */ /* Solves a linear program with the GLPK software. */ template <class prContent> tyInteger clGlpkSolver<prContent>::run(clLinearSystem<prContent> & glpk_yes(agSystem)) const { method_name("glpkSolver::run");
glpk_yes ( typedef glp_prob * tyLinearSystem; typedef typename clLinearSystem<prContent>::cpVariableX::const_iterator cpIterator; typedef clCoefficientX::const_iterator clIterator; typedef std_map(tyVariableKey,tyCardinal) clVariableX;
tyCardinal lcConstraintNo = 0; cpIterator lcCurrentVariable = agSystem.variables().begin(); std::FILE * lcFile = nil; cpIterator lcLastVariable = agSystem.variables().end(); tyBoolean lcMixedProblem = false; tyCardinal lcNbConstraint = agSystem.constraints().size(); tyCardinal lcVariableNo = 1;
clConstraint<prContent> * lcConstraint; clIterator lcCurrentCoefficient; tyInteger lcIteration; tyVariableKey lcKey; clIterator lcLastCoefficient; tyReturn lcResult; clString lcString; tyLinearSystem lcSystem; tyReal lcValue; clVariableX lcVariableX;
std_vector(double) lcCoefficientS(1); std_vector(int) lcColumnS(1); std_vector(int) lcRowS(1);
if (linearSystemSolver_private::goTemporaryKept) { lcFile=fopen(private_area::goTempoResultFileName->data(),"w"); glp_term_hook(private_area::glpkPrint,lcFile); } else glp_term_hook(private_area::glpkPrint,nil);
// System Creation // lcSystem=glp_create_prob();
// MIP Program Checking // while (lcCurrentVariable!=lcLastVariable and not lcMixedProblem) { if ((*lcCurrentVariable).second->kind()==integralVariable) lcMixedProblem=true; ++lcCurrentVariable; }
// Objective & Variables // if (agSystem.objective().kind()==maximum) glp_set_obj_dir(lcSystem,GLP_MAX); else glp_set_obj_dir(lcSystem,GLP_MIN);
glp_add_cols(lcSystem,agSystem.variables().size()); lcCurrentVariable=agSystem.variables().begin();
while (lcCurrentVariable!=lcLastVariable) { lcKey=(*lcCurrentVariable).first; lcString=clString("x")+string(lcKey); glp_set_col_name(lcSystem,lcVariableNo,lcString.data()); glp_set_obj_coef(lcSystem,lcVariableNo,agSystem.objective()[lcKey]); glp_set_col_bnds(lcSystem,lcVariableNo,GLP_LO,0.0,realMax()); lcVariableX.insert(std_make_pair(lcKey,lcVariableNo));
if (lcMixedProblem) { if ((*lcCurrentVariable).second->kind()==integralVariable) glp_set_col_kind(lcSystem,lcVariableNo,GLP_IV); else glp_set_col_kind(lcSystem,lcVariableNo,GLP_CV); }
++lcCurrentVariable; ++lcVariableNo; }
// Constraints // glp_add_rows(lcSystem,lcNbConstraint);
while (lcConstraintNo<lcNbConstraint) { lcString=clString("c"+string(lcConstraintNo)); glp_set_row_name(lcSystem,lcConstraintNo+1,lcString.data()); lcConstraint=&(agSystem[lcConstraintNo]); lcCurrentCoefficient=lcConstraint->coefficients().begin(); lcLastCoefficient=lcConstraint->coefficients().end();
while (lcCurrentCoefficient!=lcLastCoefficient) { lcValue=(*lcCurrentCoefficient).second; lcVariableNo=lcVariableX[(*lcCurrentCoefficient).first];
if (not isEqual(lcValue,0.0)) { lcRowS.push_back(int(lcConstraintNo+1)); lcColumnS.push_back(int(lcVariableNo)); lcCoefficientS.push_back(double(lcValue)); }
++lcCurrentCoefficient; }
if (lcConstraint->kind()==inferiority) glp_set_row_bnds(lcSystem,lcConstraintNo+1,GLP_UP,realMin(),lcConstraint->boundary()); else if (lcConstraint->kind()==superiority) glp_set_row_bnds(lcSystem,lcConstraintNo+1,GLP_LO,lcConstraint->boundary(),realMax()); else glp_set_row_bnds(lcSystem,lcConstraintNo+1,GLP_FX,lcConstraint->boundary(), lcConstraint->boundary());
++lcConstraintNo; }
glp_load_matrix(lcSystem,lcRowS.size()-1,&(lcRowS[0]),&(lcColumnS[0]),&(lcCoefficientS[0]));
// Linear Resolution // if (!lcMixedProblem) { glp_smcp lcParameters;
glp_init_smcp(&lcParameters); lcParameters.presolve=GLP_ON; lcResult=glp_simplex(lcSystem,&lcParameters);
if (lcResult==GLP_EITLIM) send_error(erGlpkIterationLimitExceeded); if (lcResult==GLP_ETMLIM) send_error(erGlpkTimeLimitExceeded); if (lcResult==GLP_ESING || lcResult==GLP_ECOND) send_error(erGlpkNumericalProblem); else if (lcResult!=GLP_ENOPFS && lcResult!=0) send_error(erGlpkUnknownError);
lcResult=glp_get_status(lcSystem); } // MIP Resolution // else { glp_iocp lcParameters;
glp_init_iocp(&lcParameters); lcParameters.presolve=GLP_ON; lcResult=glp_intopt(lcSystem,&lcParameters);
if (lcResult==GLP_ETMLIM) send_error(erGlpkTimeLimitExceeded); if (lcResult==GLP_EMIPGAP) send_error(erGlpkNumericalProblem); else if (lcResult!=GLP_ENOPFS && lcResult!=0) send_error(erGlpkUnknownError);
lcResult=glp_mip_status(lcSystem); }
// Problem Not Feasible // if (lcResult!=GLP_OPT) { // System Destruction // glp_delete_prob(lcSystem);
if (linearSystemSolver_private::goTemporaryKept and lcFile!=nil) { fclose(lcFile); glp_term_hook(nil,nil); }
agSystem.solved()=false; return (-1); }
// Result Analysis // lcCurrentVariable=agSystem.variables().begin(); lcVariableNo=1;
while (lcCurrentVariable!=lcLastVariable) { if (lcMixedProblem) (*lcCurrentVariable).second->value()=glp_mip_col_val(lcSystem,lcVariableNo); else glp_get_col_prim(lcSystem,lcVariableNo);
++lcCurrentVariable; ++lcVariableNo; }
// System Destruction // lcIteration=glp_get_it_cnt(lcSystem); glp_delete_prob(lcSystem);
if (linearSystemSolver_private::goTemporaryKept and lcFile!=nil) { fclose(lcFile); glp_term_hook(nil,nil); }
agSystem.solved()=true; return (lcIteration); )
glpk_no ( send_error(erGlpkNotInstalled); return (0); ) } }
// End //------------------------------------------------------------------------------------------- } #undef dll_export #undef public_area #undef private_area #endif |
//================================================================================================== // L i n e a r _ s y s t e m Implementation // G l p k // By Bruno Bachelet //================================================================================================== // Copyright (c) 1999-2016 // Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net // // This file is part of the B++ Library. This library is free software; you can redistribute it // and/or modify it under the terms of the GNU Library General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your option) any later // version. // // This library 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 Library General Public License for more details (http://www.gnu.org).
// File Name //------------------------------------------------------------------------------------- #line __LINE__ "linear_system/glpk.cpp"
// DLL Belonging //--------------------------------------------------------------------------------- #define LINEAR_SYSTEM_DLL
// Headers //--------------------------------------------------------------------------------------- #include <cstdio> /*NEED*/ #include <bpp/file_name.hpp> /*NEED*/ #include <bpp/linear_system/glpk.hpp> /*INTERFACE*/
namespace bpp {
// Namespaces //------------------------------------------------------------------------------------ #define public_area linearSystemGlpk #define private_area linearSystemGlpk_private #define dll_export DLL_EXPORT
namespace public_area {} namespace private_area {}
static_module_name("Linear_system/Glpk");
// Initialization //-------------------------------------------------------------------------------- #undef iniLinearSystemGlpk static_constant(private_area::clInitializer,goInitializer);
// Errors //---------------------------------------------------------------------------------------- namespace public_area { static_error erGlpkImproperUse; static_error erGlpkIterationLimitExceeded; static_error erGlpkNumericalProblem; static_error erGlpkTimeLimitExceeded; static_error erGlpkUnknownError;
glpk_no ( static_error erGlpkNotInstalled; ) }
// Constants & Variables //------------------------------------------------------------------------- dynamic_constant(clString,goTempoResultFileName);
// Static Members //-------------------------------------------------------------------------------- namespace public_area {} namespace private_area {}
// Functions Implementation //---------------------------------------------------------------------- namespace public_area {}
namespace private_area { //----------------------------------------------------------------------------------------GlpkPrint property int glpkPrint(tyPointer agStream,tcString agMessage) { if (agStream==nil) return (1); return (std::fprintf((std::FILE *)agStream,"%s",agMessage)); } }
// X X X Implementation //------------------------------------------------------------------------- namespace {}
// I n i t i a l i z e r Implementation //--------------------------------------------------------- namespace private_area { //--------------------------------------------------------------------------------------------Start property void clInitializer::start(void) { if (atCounter++ == 0) { try { #include <bpp/modules.hpp> /*NEED*/ registerStop(this); environment::informInitialization(goModuleName);
erGlpkImproperUse.create("GLPK - Improper use."); erGlpkIterationLimitExceeded.create("GLPK - The maximum number of iterations is reached."); erGlpkNumericalProblem.create("GLPK - Numerical problem to solve the linear program."); erGlpkTimeLimitExceeded.create("GLPK - The maximum time of execution is reached."); erGlpkUnknownError.create("GLPK - An unknown error has occurred.");
glpk_no ( erGlpkNotInstalled.create("GLPK isn't installed."); )
goTempoResultFileName = new_object(clString(environment::temporaryLocation()+ fileNameSeparator()+LINEAR_SYSTEM_GLPK_TEMPORARY_FILE)); }
initializer_catch; } } //---------------------------------------------------------------------------------------------Stop property void clInitializer::stop(void) { try { environment::informTermination(goModuleName);
delete_object(goTempoResultFileName); }
initializer_catch; } }
// End //------------------------------------------------------------------------------------------- } |
|