//================================================================================================== // L i n e a r _ s y s t e m Interface // A m p l // 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 AMPL software. */
// File Name //------------------------------------------------------------------------------------- #line __LINE__ "linear_system/ampl.hpp"
// Guardian //-------------------------------------------------------------------------------------- #ifndef guLinearSystemAmpl #define guLinearSystemAmpl
// 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 linearSystemAmpl #define private_area linearSystemAmpl_private
namespace public_area { /*NAMESPACE*/ using namespace linearSystemSolver; } namespace private_area { using namespace public_area; }
extern_module_name;
// Initialization //-------------------------------------------------------------------------------- #define iniLinearSystemAmpl has_initializer;
// Macrocommands //---------------------------------------------------------------------------------
// Types & Classes //------------------------------------------------------------------------------- namespace public_area { //------------------------------------------------------------------------------------------Classes template <class prContent> class clAmplSolver; }
namespace private_area {}
// Functions Interface //--------------------------------------------------------------------------- namespace public_area {} namespace private_area {}
// Errors //---------------------------------------------------------------------------------------- namespace public_area { /*ERROR*/ extern_error erAmplUnknownError; /* An unknown error has occurred in the AMPL software. */
ampl_no ( /*ERROR*/ extern_error erAmplNotInstalled; /* The library is not built for the use of the AMPL 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,?);
// A m p l S o l v e r Interface //---------------------------------------------------------------- namespace public_area { /*CLASS clAmplSolver */ /* Represents the AMPL solver. */ template <class prContent> class clAmplSolver : public linearSystemSolver::clSolver<prContent> { //-----------------------------------------------------------------------------------------Private private_property clAmplSolver & operator = (const clAmplSolver &); //------------------------------------------------------------------------------------------Public public_property constructor clAmplSolver(void); public_property constructor clAmplSolver(const clAmplSolver &); public_property destructor clAmplSolver(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 {}
// A m p l S o l v e r Inline //------------------------------------------------------------------- namespace public_area { //--------------------------------------------------------------------------------------Constructor /*METHOD clAmplSolver */ /* Builds an AMPL solver. */ template <class prContent> inline clAmplSolver<prContent>::clAmplSolver(void) : linearSystemSolver::clSolver<prContent>() {} //--------------------------------------------------------------------------------------Constructor /*METHOD clAmplSolver */ /* Builds an AMPL solver from another one. */ template <class prContent> inline clAmplSolver<prContent>::clAmplSolver(const clAmplSolver<prContent> &) : clSolver<prContent>() {} //---------------------------------------------------------------------------------------Destructor /*METHOD clAmplSolver */ /* Destructs the AMPL solver. */ template <class prContent> inline clAmplSolver<prContent>::~clAmplSolver(void) {} //----------------------------------------------------------------------------------------Available /*METHOD clAmplSolver */ /* Indicates if the AMPL solver is available. */ template <class prContent> inline tyBoolean clAmplSolver<prContent>::available(void) const { return (exchangeAmpl::valid()); } //---------------------------------------------------------------------------------------------Name /*METHOD clAmplSolver */ /* Returns the name of the solver. It is always "AMPL". */ template <class prContent> inline tcString clAmplSolver<prContent>::name(void) const { return ("AMPL"); } }
// Function Implementation //----------------------------------------------------------------------- namespace public_area {} namespace private_area {}
// A m p l S o l v e r Implementation //----------------------------------------------------------- namespace public_area { //------------------------------------------------------------------------------------AnalyzeResult /*METHOD clAmplSolver */ /* Analyzes from a stream the results given by the AMPL software and stores them in a linear program structure. */ template <class prContent> tyInteger clAmplSolver<prContent>::analyzeResult(clInStream & agStream, clLinearSystem<prContent> & agSystem) const { method_name("amplSolver::analyzeResult");
tyReal lcObjective; clString lcString; tyVariableKey lcKey;
agSystem.solved()=false; agStream >> lcString; if (lcString!=exchangeAmpl::solver()) return (-1);
// Objective // agStream >> lcString; while (lcString!="obj") agStream >> lcString; agStream >> lcString >> lcObjective; if (agStream.fail()) send_error(erStreamReading);
// Constraints // agStream >> lcString;
while (lcString!="") { lcKey=cardinal(lcString.data()+1); agStream >> lcString; agStream >> agSystem.variable(lcKey).value(); if (agStream.fail()) send_error(erStreamReading); agStream >> lcString; }
if (agStream.fail()) send_error(erStreamReading); agSystem.solved()=true; return (0); } //----------------------------------------------------------------------------------GenerateCommand /*METHOD clAmplSolver */ /* Generates a file containing the commands sent to the AMPL software to solve a given linear program. */ template <class prContent> void clAmplSolver<prContent>::generateCommand(tcString agCommandFileName,tcString agModelFileName, const clLinearSystem<prContent> & agSystem) const { method_name("amplSolver::generateCommand");
typedef typename clLinearSystem<prContent>::cpVariableX::const_iterator cpIterator;
cpIterator lcCurrentVariable = agSystem.variables().begin(); cpIterator lcLastVariable = agSystem.variables().end();
clOutFile lcFile;
open(lcFile,agCommandFileName,ios::out|ios::trunc); lcFile << "option solver xlsol;" << end_line; lcFile << "model " << agModelFileName << ';' << end_line; lcFile << "solve;" << end_line; lcFile << "display obj;" << end_line; lcFile << "display ";
while (lcCurrentVariable!=lcLastVariable) { lcFile << 'x' << (*lcCurrentVariable).first; lcCurrentVariable++; if (lcCurrentVariable==lcLastVariable) lcFile << ';'; else lcFile << ','; }
lcFile << end_line; lcFile << "quit;" << end_line;
close(lcFile);
if (lcFile.fail()) send_error(erFileWriting); } //------------------------------------------------------------------------------------GenerateModel /*METHOD clAmplSolver */ /* Generates into a stream a model of a linear program that the AMPL software can understand. */ template <class prContent> void clAmplSolver<prContent>::generateModel(clOutStream & agStream, const clLinearSystem<prContent> & agSystem) const { method_name("amplSolver::generateModel");
typedef typename clLinearSystem<prContent>::cpVariableX::const_iterator cpIterator; typedef clCoefficientX::const_iterator clIterator;
tyCardinal lcConstraintNo = 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;
// Variables // while (lcCurrentVariable!=lcLastVariable) { agStream << "var x" << (*lcCurrentVariable).first; if ((*lcCurrentVariable).second->kind()==integralVariable) agStream << " integer"; agStream << " >= 0;" << end_line; lcCurrentVariable++; }
agStream << end_line;
// Objective // if (agSystem.objective().kind()==maximum) agStream << "maximize"; else agStream << "minimize";
agStream << " obj: ";
while (lcCurrentCoefficient!=lcLastCoefficient) { lcValue=(*lcCurrentCoefficient).second;
if (lcFirstCoefficient) { agStream << lcValue << " * x" << (*lcCurrentCoefficient).first; lcFirstCoefficient=false; } else if (lcValue<0.0) agStream << " - " << -lcValue << " * x" << (*lcCurrentCoefficient).first; else if (lcValue>0) agStream << " + " << lcValue << " * x" << (*lcCurrentCoefficient).first;
lcCurrentCoefficient++; }
agStream << ';' << end_line << end_line;
// Constraints // while (lcConstraintNo<lcNbConstraint) { agStream << "subject to c" << lcConstraintNo << ": "; lcFirstCoefficient=true; lcConstraint=&(agSystem[lcConstraintNo]); lcCurrentCoefficient=lcConstraint->coefficients().begin(); lcLastCoefficient=lcConstraint->coefficients().end();
while (lcCurrentCoefficient!=lcLastCoefficient) { lcValue=(*lcCurrentCoefficient).second;
if (lcFirstCoefficient) { if (lcValue!=0) { 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++; }
if (lcConstraint->kind()==inferiority) agStream << " <= "; else if (lcConstraint->kind()==superiority) agStream << " >= "; else agStream << " = ";
agStream << lcConstraint->boundary() << ';' << end_line; lcConstraintNo++; }
if (agStream.fail()) send_error(erStreamWriting); } //-------------------------------------------------------------------------------------OutTemporary /*METHOD clAmplSolver */ /* Writes into a stream the last intermediate files used and generated by the AMPL software to solve a linear program. */ template <class prContent> void clAmplSolver<prContent>::outTemporary(clOutStream & agStream) const { method_name("amplSolver::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); close(lcFile); if (lcFile.fail()) send_error(erFileReading); } //----------------------------------------------------------------------------------RemoveTemporary /*METHOD clAmplSolver */ /* Removes the last intermediate files used and generated by the AMPL software to solve a linear program. */ template <class prContent> void clAmplSolver<prContent>::removeTemporary(void) const { removeFile(private_area::goTempoCommandFileName->data()); removeFile(private_area::goTempoModelFileName->data()); removeFile(private_area::goTempoResultFileName->data()); } //----------------------------------------------------------------------------------------------Run /*METHOD clAmplSolver */ /* Solves a linear program with the AMPL software. */ template <class prContent> tyInteger clAmplSolver<prContent>::run(clLinearSystem<prContent> & agSystem) const { method_name("amplSolver::run");
ampl_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);
exchangeAmpl:: 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); )
ampl_no ( send_error(erAmplNotInstalled); return (0); ) } }
namespace private_area {}
// End //------------------------------------------------------------------------------------------- } #undef dll_export #undef public_area #undef private_area #endif |
//================================================================================================== // L i n e a r _ s y s t e m Implementation // A m p l // 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/ampl.cpp"
// DLL Belonging //--------------------------------------------------------------------------------- #define LINEAR_SYSTEM_DLL
// Headers //--------------------------------------------------------------------------------------- #include <bpp/file_name.hpp> /*NEED*/ #include <bpp/linear_system/ampl.hpp> /*INTERFACE*/
namespace bpp {
// Namespaces //------------------------------------------------------------------------------------ #define public_area linearSystemAmpl #define private_area linearSystemAmpl_private #define dll_export DLL_EXPORT
namespace public_area {} namespace private_area {}
static_module_name("Linear_system/Ampl");
// Initialization //-------------------------------------------------------------------------------- #undef iniLinearSystemAmpl static_constant(private_area::clInitializer,goInitializer);
// Errors //---------------------------------------------------------------------------------------- namespace public_area { static_error erAmplUnknownError; ampl_no ( static_error erAmplNotInstalled; ) }
// 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);
erAmplUnknownError.create("AMPL - An unknown error has occurred."); ampl_no ( erAmplNotInstalled.create("AMPL isn't installed."); )
goTempoCommandFileName = new_object(clString(environment::temporaryLocation()+ fileNameSeparator()+LINEAR_SYSTEM_AMPL_TEMPORARY_FILE_1));
goTempoModelFileName = new_object(clString(environment::temporaryLocation()+ fileNameSeparator()+LINEAR_SYSTEM_AMPL_TEMPORARY_FILE_2));
goTempoResultFileName = new_object(clString(environment::temporaryLocation()+ fileNameSeparator()+LINEAR_SYSTEM_AMPL_TEMPORARY_FILE_3));
goDataLocation = new_object(clString(environment::dataLocation()+fileNameSeparator()+ "linear_system"+fileNameSeparator()+"ampl")); }
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 //------------------------------------------------------------------------------------------- } |
|