//==================================================================================================
// L i n e a r _ s y s t e m                                                              Interface
// S o l v e r
//                                                                                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 a generic interface for the resolution of linear programs. */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "linear_system/solver.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guLinearSystemSolver
#define guLinearSystemSolver

// Headers //---------------------------------------------------------------------------------------
#include <bpp/exchange.hpp> /*INCLUDE*/
#include <bpp/linear_system/structure.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  linearSystemSolver
#define private_area linearSystemSolver_private

namespace public_area  { /*NAMESPACE*/ using namespace linearSystemStructure; }
namespace private_area { using namespace public_area; }

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniLinearSystemSolver
has_initializer;

// Macrocommands //---------------------------------------------------------------------------------

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area {
 //------------------------------------------------------------------------------------------Classes
 template <class prContent> class clSolver;
}

namespace private_area {}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area  {
 inline void preserveTemporary(void);
 inline void removeTemporary(void);
}

namespace private_area { testing_mode ( function void test(void); ) }

// Errors //----------------------------------------------------------------------------------------
namespace public_area {}

// Constants & Variables //-------------------------------------------------------------------------
/*VARIABLE*/
/* Indicates if the intermediate files generated and used during a resolution by a solver are
   preserved or removed from the temporary folder. */
extern_static_constant(private,tyBoolean,goTemporaryKept,temporaryKept);

extern_dynamic_constant(private,clString,goDataLocation,?);
extern_static_constant(private,clMutex,goMutex,?);

// S o l v e r  Interface //------------------------------------------------------------------------
namespace public_area {
 /*CLASS clSolver */
 /* Represents a solver of linear programs. This is an abstract class. */
 template <class prContent> class clSolver {
  //-----------------------------------------------------------------------------------------Private
  private_property static clSolver<prContent> * atDefaultSolver;
  private_property static clInitializerMutex    atMutex;

  private_property constructor clSolver(const clSolver &);
  private_property clSolver & operator = (const clSolver &);
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clSolver */
  /* Number of branching nodes that were needed during the last resolution by the solver (valid
     only for mixed integer programs). */
  read_only_attribute(tyCardinal,atLastBranchingNodesNumber,lastBranchingNodesNumber);

  public_property constructor clSolver(void);
  public_property virtual destructor clSolver(void);

  /*AMETHOD clSolver */ /* Indicates if the solver is available. Abstract method. */
  public_property virtual tyBoolean available(void) const = 0;

  /*AMETHOD clSolver */
  /* Analyzes from a stream the results given by the solver software and stores them in a linear
     program structure. Abstract method. */
  public_property
  virtual tyInteger analyzeResult(clInStream & agStream,
                                  clLinearSystem<prContent> & agSystem) const = 0;

  /*AMETHOD clSolver */
  /* Generates a file containing the commands sent to the solver software to solve a given linear
     program. Abstract method. */
  public_property
  virtual void generateCommand(tcString agCommandFileName,tcString agModelFileName,
                               const clLinearSystem<prContent> & agSystem) const = 0;

  /*AMETHOD clSolver */
  /* Generates into a stream a model of a linear program that the solver software can
     understand. Abstract method. */
  public_property virtual void generateModel(clOutStream & agStream,
                                             const clLinearSystem<prContent> & agSystem) const = 0;

  /*AMETHOD clSolver */ /* Returns the name of the solver. Abstract method. */
  public_property virtual tcString name(void) const = 0;

  /*AMETHOD clSolver */
  /* Writes into a stream the last intermediate files used and generated by the solver software to
     solve a linear program. Abstract method. */
  public_property virtual void outTemporary(clOutStream & agStream) const = 0;

  /*AMETHOD clSolver */
  /* Removes the last intermediate files used and generated by the solver software to solve a
     linear program. Abstract method. */
  public_property virtual void removeTemporary(void) const = 0;

  /*AMETHOD clSolver */ /* Solves a linear program with the solver software. Abstract method. */
  public_property virtual tyInteger run(clLinearSystem<prContent> & agSystem) const = 0;

  public_property static clSolver<prContent> & defaultSolver(void);
 };
}

// Functions Inline //------------------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------PreserveTemporary
 /*FUNCTION*/
 /* Sets that the intermediate files generated and used during a resolution by a solver software
    must be preserved. */
 inline void preserveTemporary(void) {
  safe_yes ( private_area::goMutex.lock(); )
  private_area::goTemporaryKept=true;
  safe_yes ( private_area::goMutex.release(); )
 }
 //----------------------------------------------------------------------------------RemoveTemporary
 /*FUNCTION*/
 /* Sets that the intermediate files generated and used during a resolution by a solver software
    must be removed from the temporary folder. */
 inline void removeTemporary(void) {
  safe_yes ( private_area::goMutex.lock(); )
  private_area::goTemporaryKept=false;
  safe_yes ( private_area::goMutex.release(); )
 }
}

namespace private_area {}

// S o l v e r  Inline //---------------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clSolver */ /* Builds a solver of linear programs. */
 template <class prContent> inline clSolver<prContent>::clSolver(void)
 : atLastBranchingNodesNumber(0) {}
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clSolver */ /* Builds a solver from another one. */
 template <class prContent> inline clSolver<prContent>::clSolver(const clSolver<prContent> &)
 : atLastBranchingNodesNumber(0) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clSolver */ /* Destructs the solver. */
 template <class prContent> inline clSolver<prContent>::~clSolver(void) {}
}

// S o l v e r  Implementation //-------------------------------------------------------------------
namespace public_area {
 commentary (
  //-----------------------------------------------------------------------------------DefaultSolver
  /*METHOD clSolver */ /* Returns the default solver of linear programs. Static method. */
  template <class prContent> clSolver<prContent> & clSolver<prContent>::defaultSolver(void) {
   typedef linearSystemAmpl::clAmplSolver<prContent>          cpAmplSolver;
   typedef linearSystemCplex::clCplexSolver<prContent>        cpCplexSolver;
   typedef linearSystemCplexLibrary::clCplexSolver<prContent> cpCplexLibrarySolver;
   typedef linearSystemGlpk::clGlpkSolver<prContent>          cpGlpkSolver;

   if (atMutex.tryLock()) {
    atDefaultSolver=nil;
    cplex_library_yes ( atDefaultSolver=new cpCplexLibrarySolver(); )

    cplex_yes (
     if (atDefaultSolver==nil and exchangeCplex::valid()) atDefaultSolver=new cpCplexSolver();
    )

    ampl_yes (
     if (atDefaultSolver==nil and exchangeAmpl::valid()) atDefaultSolver=new cpAmplSolver();
    )

    if (atDefaultSolver==nil) atDefaultSolver=new cpGlpkSolver();
    atMutex.release();
   }

   return (*atDefaultSolver);
  }
 )
}

// End //-------------------------------------------------------------------------------------------
}
#undef dll_export
#undef public_area
#undef private_area
#endif
 
//==================================================================================================
// L i n e a r _ s y s t e m                                                         Implementation
// S o l v e r
//                                                                                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/solver.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define LINEAR_SYSTEM_DLL

// Headers //---------------------------------------------------------------------------------------
#include <bpp/linear_system/solver.hpp> /*INTERFACE*/

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  linearSystemSolver
#define private_area linearSystemSolver_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Linear_system/Solver");

// Initialization //--------------------------------------------------------------------------------
#undef iniLinearSystemSolver
static_constant(private_area::clInitializer,goInitializer);

// Errors //----------------------------------------------------------------------------------------
namespace public_area {}

// Constants & Variables //-------------------------------------------------------------------------
static_constant(tyBoolean,goTemporaryKept);
dynamic_constant(clString,goDataLocation);
static_constant(clMutex,goMutex);

// Static Members //--------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// X X X  Implementation //-------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// 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);

    goDataLocation = new_object(clString(environment::dataLocation()+fileNameSeparator()
                     +"linear_system"+fileNameSeparator()+"solver"));

    goTemporaryKept = false;
   }

   initializer_catch;
  }
 }
 //---------------------------------------------------------------------------------------------Stop
 property void clInitializer::stop(void) {
  try {
   environment::informTermination(goModuleName);

   delete_object(goDataLocation);
  }

  initializer_catch;
 }
}

// End //-------------------------------------------------------------------------------------------
}