//================================================================================================== // L i n e a r _ s y s t e m Interface // C p l e x // 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 CPLEX software. */
// File Name //------------------------------------------------------------------------------------- #line __LINE__ "linear_system/cplex.hpp"
// Guardian //-------------------------------------------------------------------------------------- #ifndef guLinearSystemCplex #define guLinearSystemCplex
// Headers //--------------------------------------------------------------------------------------- #include <bpp/linear_system/solver.hpp> /*INCLUDE*/
namespace bpp {
// Importation/Exportation //----------------------------------------------------------------------- #ifdef LINEAR_SYSTEM_DLL #define dll_export DLL_EXPORT #else #define dll_export DLL_IMPORT #endif
// Namespaces //------------------------------------------------------------------------------------ #define public_area linearSystemCplex #define private_area linearSystemCplex_private
namespace public_area { /*NAMESPACE*/ using namespace linearSystemSolver; } namespace private_area { using namespace public_area; }
extern_module_name;
// Initialization //-------------------------------------------------------------------------------- #define iniLinearSystemCplex has_initializer;
// Macrocommands //---------------------------------------------------------------------------------
// Types & Classes //------------------------------------------------------------------------------- namespace public_area { //------------------------------------------------------------------------------------------Classes template <class prContent> class clCplexSolver; }
namespace private_area {}
// Functions Interface //--------------------------------------------------------------------------- namespace public_area {} namespace private_area {}
// Errors //---------------------------------------------------------------------------------------- namespace public_area { /*ERROR*/ extern_error erCplexUnknownError; /* An unknown error has occurred in the CPLEX software. */
cplex_no ( /*ERROR*/ extern_error erCplexNotInstalled; /* The library is not built for the use of the CPLEX software. */ ) }
// Constants & Variables //------------------------------------------------------------------------- extern_dynamic_constant(private,clString,goTempoCommandFileName,?); extern_dynamic_constant(private,clString,goTempoModelFileName,?); extern_dynamic_constant(private,clString,goTempoResultFileName,?);
extern_dynamic_constant(private,clString,goDataLocation,?);
// C p l e x S o l v e r Interface //-------------------------------------------------------------- namespace public_area { /*CLASS clCplexSolver */ /* Represents the CPLEX solver. */ template <class prContent> class clCplexSolver : public linearSystemSolver::clSolver<prContent> { //-----------------------------------------------------------------------------------------Private private_property clCplexSolver & operator = (const clCplexSolver &);
private_property tyInteger analyzeError(clInStream &) const; //------------------------------------------------------------------------------------------Public public_property constructor clCplexSolver(void); public_property constructor clCplexSolver(const clCplexSolver &); public_property destructor clCplexSolver(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 {}
// C p l e x S o l v e r Inline //----------------------------------------------------------------- namespace public_area { //--------------------------------------------------------------------------------------Constructor /*METHOD clCplexSolver */ /* Builds a CPLEX solver. */ template <class prContent> inline clCplexSolver<prContent>::clCplexSolver(void) : linearSystemSolver::clSolver<prContent>() {} //--------------------------------------------------------------------------------------Constructor /*METHOD clCplexSolver */ /* Builds a CPLEX solver from another one. */ template <class prContent> inline clCplexSolver<prContent>::clCplexSolver(const clCplexSolver<prContent> &) : clSolver<prContent>() {} //---------------------------------------------------------------------------------------Destructor /*METHOD clCplexSolver */ /* Destructs the solver. */ template <class prContent> inline clCplexSolver<prContent>::~clCplexSolver(void) {} //----------------------------------------------------------------------------------------Available /*METHOD clCplexSolver */ /* Indicates if the CPLEX solver is available. */ template <class prContent> inline tyBoolean clCplexSolver<prContent>::available(void) const { return (exchangeCplex::valid()); } //---------------------------------------------------------------------------------------------Name /*METHOD clCplexSolver */ /* Returns the name of the solver. It is always "CPLEX". */ template <class prContent> inline tcString clCplexSolver<prContent>::name(void) const { return ("CPLEX"); } }
// Function Implementation //----------------------------------------------------------------------- namespace public_area {} namespace private_area {}
// C p l e x S o l v e r Implementation //--------------------------------------------------------- namespace public_area { //-------------------------------------------------------------------------------------AnalyzeError template <class prContent> tyInteger clCplexSolver<prContent>::analyzeError(clInStream & agStream) const { method_name("cplexSolver::analyzeError");
tyInteger lcErrorNo;
agStream >> lcErrorNo;
if (lcErrorNo==1101) return (-1); else { send_error(erCplexUnknownError); return (-1); } } //------------------------------------------------------------------------------------AnalyzeResult /*METHOD clCplexSolver */ /* Analyzes from a stream the results given by the CPLEX software and stores them in a linear program structure. */ template <class prContent> tyInteger clCplexSolver<prContent>::analyzeResult(clInStream & agStream, clLinearSystem<prContent> & agSystem) const { method_name("cplexSolver::analyzeResult");
typedef typename clLinearSystem<prContent>::cpVariableX::const_iterator cpIterator;
tyCardinal lcCounter = 0; cpIterator lcCurrentVariable = agSystem.variables().begin(); cpIterator lcLastVariable = agSystem.variables().end();
tyCharacter lcDummyString[256]; tyVariableKey lcKey; tyInteger lcNbIteration; tyReal lcObjective; clString lcString;
agSystem.solved()=false; const_cast<clCplexSolver<prContent> *>(this)->atLastBranchingNodesNumber=0;
// Number Iterations // while (lcCounter<2) { agStream >> lcString; if (lcString=="Error") return (analyzeError(agStream)); if (lcString=="CPLEX>") lcCounter++; }
agStream >> lcString; while (lcString!="Iterations" and lcString!="CPLEX>") { if (lcString=="Error") return (analyzeError(agStream)); agStream >> lcString; }
if (lcString=="Iterations") { agStream >> lcString >> lcNbIteration; agStream >> lcString; while (lcString!="CPLEX>") { if (lcString=="Error") return (analyzeError(agStream));
if (lcString=="Nodes") { agStream >> lcString; agStream >> const_cast<clCplexSolver<prContent> *>(this)->atLastBranchingNodesNumber; }
agStream >> lcString; } }
// Objective Value // agStream >> lcString;
while (lcString!="Objective" and lcString!="CPLEX>") { if (lcString=="Error") return (analyzeError(agStream)); agStream >> lcString; }
if (lcString=="CPLEX>") return (-1); agStream >> lcString >> lcObjective;
// Variables Value // agStream >> lcString;
while (lcString!="CPLEX>") { if (lcString=="Error") return (analyzeError(agStream)); agStream >> lcString; }
while (lcCurrentVariable!=lcLastVariable) { (*lcCurrentVariable).second->value()=0.0; lcCurrentVariable++; }
agStream >> lcString; if (lcString=="Illegal") return (-1); if (lcString!="All") { agStream.getline(lcDummyString,256); agStream >> lcString; }
while (lcString[0]=='x') { lcKey=cardinal(lcString.data()+1); agStream >> agSystem.variable(lcKey).value(); agStream >> lcString; }
if (lcString!="CPLEX>" and lcString!="All") send_error(erStreamReading); if (agStream.fail()) send_error(erStreamReading); agSystem.solved()=true; return (lcNbIteration); } //----------------------------------------------------------------------------------GenerateCommand /*METHOD clCplexSolver */ /* Generates a file containing the commands sent to the CPLEX software to solve a given linear program. */ template <class prContent> void clCplexSolver<prContent>::generateCommand(tcString agCommandFileName, tcString agModelFileName, const clLinearSystem<prContent> &) const { method_name("cplexSolver::generateCommand");
clOutFile lcFile;
open(lcFile,agCommandFileName,ios::out|ios::trunc); lcFile << "read " << agModelFileName << end_line; lcFile << "optimize" << end_line; lcFile << "display solution objective" << end_line; lcFile << "display solution variables -" << end_line; lcFile << "quit" << end_line; close(lcFile);
if (lcFile.fail()) send_error(erFileWriting); } //------------------------------------------------------------------------------------GenerateModel /*METHOD clCplexSolver */ /* Generates into a stream a model of a linear program that the CPLEX software can understand. */ template <class prContent> void clCplexSolver<prContent>::generateModel(clOutStream & agStream, const clLinearSystem<prContent> & agSystem) const { method_name("cplexSolver::generateModel");
typedef typename clLinearSystem<prContent>::cpVariableX::const_iterator cpIterator; typedef clCoefficientX::const_iterator clIterator;
tyCardinal lcConstraintNo = 0; tyCardinal lcCounter = 0; clIterator lcCurrentCoefficient = agSystem.objective().coefficients().begin(); cpIterator lcCurrentVariable = agSystem.variables().begin(); tyBoolean lcFirstCoefficient = true; clIterator lcLastCoefficient = agSystem.objective().coefficients().end(); cpIterator lcLastVariable = agSystem.variables().end(); tyCardinal lcNbConstraint = agSystem.constraints().size();
const clConstraint<prContent> * lcConstraint; tyReal lcValue;
// Objective // if (agSystem.objective().kind()==maximum) agStream << "maximize" << end_line; else agStream << "minimize" << end_line;
agStream << " obj: ";
while (lcCurrentCoefficient!=lcLastCoefficient) { lcValue=(*lcCurrentCoefficient).second;
if (lcFirstCoefficient) { agStream << lcValue << " x" << (*lcCurrentCoefficient).first; lcFirstCoefficient=false; } else if (lcValue<0) agStream << " - " << -lcValue << " x" << (*lcCurrentCoefficient).first; else if (lcValue>=0) agStream << " + " << lcValue << " x" << (*lcCurrentCoefficient).first;
lcCurrentCoefficient++; lcCounter++; if (lcCurrentCoefficient!=lcLastCoefficient and lcCounter%10==0) agStream << end_line; }
agStream << end_line << end_line;
// Constraints // agStream << "subject to" << end_line;
while (lcConstraintNo<lcNbConstraint) { agStream << " c" << lcConstraintNo << ": "; lcFirstCoefficient=true; lcCounter=0; lcConstraint=&(agSystem[lcConstraintNo]); lcCurrentCoefficient=lcConstraint->coefficients().begin(); lcLastCoefficient=lcConstraint->coefficients().end();
while (lcCurrentCoefficient!=lcLastCoefficient) { lcValue=(*lcCurrentCoefficient).second;
if (lcFirstCoefficient) { agStream << lcValue << " x" << (*lcCurrentCoefficient).first; lcFirstCoefficient=false; } else if (lcValue<0) agStream << " - " << -lcValue << " x" << (*lcCurrentCoefficient).first; else if (lcValue>=0) agStream << " + " << lcValue << " x" << (*lcCurrentCoefficient).first;
lcCurrentCoefficient++; lcCounter++; if (lcCurrentCoefficient!=lcLastCoefficient and lcCounter%10==0) agStream << end_line; }
if (lcConstraint->kind()==inferiority) agStream << " <= "; else if (lcConstraint->kind()==superiority) agStream << " >= "; else agStream << " = ";
agStream << lcConstraint->boundary() << end_line; lcConstraintNo++; }
agStream << end_line;
// Bounds // agStream << "bounds" << end_line;
while (lcCurrentVariable!=lcLastVariable) { agStream << " 0 <= x" << (*lcCurrentVariable).first << " <= +infinity" << end_line; lcCurrentVariable++; }
agStream << end_line;
// Integrity // agStream << "integers" << end_line; lcCurrentVariable=agSystem.variables().begin();
while (lcCurrentVariable!=lcLastVariable) { if ((*lcCurrentVariable).second->kind()==integralVariable) agStream << " x" << (*lcCurrentVariable).first << end_line;
lcCurrentVariable++; }
agStream << end_line; agStream << "end" << end_line;
if (agStream.fail()) send_error(erStreamWriting); } //-------------------------------------------------------------------------------------OutTemporary /*METHOD clCplexSolver */ /* Writes into a stream the last intermediate files used and generated by the CPLEX software to solve a linear program. */ template <class prContent> void clCplexSolver<prContent>::outTemporary(clOutStream & agStream) const { method_name("cplexSolver::outTemporary");
clInFile lcFile;
agStream << "[>] Temporary Command File:" << end_line; open(lcFile,private_area::goTempoCommandFileName->data(),ios::in); copy(agStream,lcFile,false); close(lcFile); if (lcFile.fail()) send_error(erFileReading);
agStream << end_line; agStream << "[>] Temporary Model File:" << end_line; open(lcFile,private_area::goTempoModelFileName->data(),ios::in); copy(agStream,lcFile,false); close(lcFile); if (lcFile.fail()) send_error(erFileReading);
agStream << end_line; agStream << "[>] Temporary Result File:" << end_line; open(lcFile,private_area::goTempoResultFileName->data(),ios::in); copy(agStream,lcFile,false); agStream << end_line; close(lcFile); if (lcFile.fail()) send_error(erFileReading); } //----------------------------------------------------------------------------------RemoveTemporary /*METHOD clCplexSolver */ /* Removes the last intermediate files used and generated by the CPLEX software to solve a linear program. */ template <class prContent> void clCplexSolver<prContent>::removeTemporary(void) const { removeFile(private_area::goTempoCommandFileName->data()); removeFile(private_area::goTempoModelFileName->data()); removeFile(private_area::goTempoResultFileName->data()); } //----------------------------------------------------------------------------------------------Run /*METHOD clCplexSolver */ /* Solves a linear program with the CPLEX software. */ template <class prContent> tyInteger clCplexSolver<prContent>::run(clLinearSystem<prContent> & agSystem) const { method_name("cplexSolver::run");
cplex_yes ( using namespace private_area;
clOutFile lcFile1; clInFile lcFile2; tyInteger lcNbIteration;
// Generation // open(lcFile1,goTempoModelFileName->data(),ios::out|ios::trunc); generateModel(lcFile1,agSystem); close(lcFile1); if (lcFile1.fail()) send_error(erFileWriting);
// Execution // generateCommand(goTempoCommandFileName->data(),goTempoModelFileName->data(),agSystem);
exchangeCplex:: execute((clString("< ")+*goTempoCommandFileName+" > "+*goTempoResultFileName).data());
// Analysis // open(lcFile2,goTempoResultFileName->data(),ios::in); lcNbIteration=analyzeResult(lcFile2,agSystem); close(lcFile2); if (lcFile2.fail()) send_error(erFileReading);
if (not linearSystemSolver_private::goTemporaryKept) { removeFile(goTempoCommandFileName->data()); removeFile(goTempoModelFileName->data()); removeFile(goTempoResultFileName->data()); }
return (lcNbIteration); )
cplex_no ( send_error(erCplexNotInstalled); 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 // C p l e x // 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/cplex.cpp"
// DLL Belonging //--------------------------------------------------------------------------------- #define LINEAR_SYSTEM_DLL
// Headers //--------------------------------------------------------------------------------------- #include <bpp/file_name.hpp> /*NEED*/ #include <bpp/linear_system/cplex.hpp> /*INTERFACE*/
namespace bpp {
// Namespaces //------------------------------------------------------------------------------------ #define public_area linearSystemCplex #define private_area linearSystemCplex_private #define dll_export DLL_EXPORT
namespace public_area {} namespace private_area {}
static_module_name("Linear_system/Cplex");
// Initialization //-------------------------------------------------------------------------------- #undef iniLinearSystemCplex static_constant(private_area::clInitializer,goInitializer);
// Errors //---------------------------------------------------------------------------------------- namespace public_area { static_error erCplexUnknownError; cplex_no ( static_error erCplexNotInstalled; ) }
// Constants & Variables //------------------------------------------------------------------------- dynamic_constant(clString,goTempoCommandFileName); dynamic_constant(clString,goTempoModelFileName); dynamic_constant(clString,goTempoResultFileName);
dynamic_constant(clString,goDataLocation);
// Static Members //-------------------------------------------------------------------------------- namespace public_area {} namespace private_area {}
// Functions Implementation //---------------------------------------------------------------------- namespace public_area {} namespace private_area {}
// 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);
erCplexUnknownError.create("CPLEX - An unknown error has occurred."); cplex_no ( erCplexNotInstalled.create("CPLEX isn't installed."); )
goTempoCommandFileName = new_object(clString(environment::temporaryLocation()+ fileNameSeparator()+LINEAR_SYSTEM_CPLEX_TEMPORARY_FILE_1));
goTempoModelFileName = new_object(clString(environment::temporaryLocation()+ fileNameSeparator()+LINEAR_SYSTEM_CPLEX_TEMPORARY_FILE_2));
goTempoResultFileName = new_object(clString(environment::temporaryLocation()+ fileNameSeparator()+LINEAR_SYSTEM_CPLEX_TEMPORARY_FILE_3));
goDataLocation = new_object(clString(environment::dataLocation()+fileNameSeparator()+ "linear_system"+fileNameSeparator()+"cplex")); }
initializer_catch; } } //---------------------------------------------------------------------------------------------Stop property void clInitializer::stop(void) { try { environment::informTermination(goModuleName);
delete_object(goTempoCommandFileName); delete_object(goTempoModelFileName); delete_object(goTempoResultFileName); delete_object(goDataLocation); }
initializer_catch; } }
// End //------------------------------------------------------------------------------------------- } |
|