//==================================================================================================
// G r a p h _ p r o b l e m                                                              Interface
// M i n _ c o s t _ f l o w
// L i n e a r _ s y s t e m
//                                                                                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 the minimum cost flow problem (with linear costs)
   in graphs using linear program modeling. */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "graph_problem/min_cost_flow/linear_system.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guGraphProblemMinCostFlowLinearSystem
#define guGraphProblemMinCostFlowLinearSystem

// Headers //---------------------------------------------------------------------------------------
#include <bpp/graph_problem/min_cost_flow/algorithm.hpp> /*INCLUDE*/

namespace bpp {

// Importation/Exportation //-----------------------------------------------------------------------
#ifdef GRAPH_PROBLEM_MIN_COST_FLOW_DLL
 #define dll_export DLL_EXPORT
#else
 #define dll_export DLL_IMPORT
#endif

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphProblemMinCostFlowLinearSystem
#define private_area graphProblemMinCostFlowLinearSystem_private

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

extern_module_name;

// Initialization //--------------------------------------------------------------------------------

// Macrocommands //---------------------------------------------------------------------------------
/*ALIAS*/
#define tdGraph class prArcData,class prNodeData //

/*ALIAS*/
#define tuGraph prArcData,prNodeData //

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area {
 //------------------------------------------------------------------------------------------Classes
 template <tdGraph> class clSolveAlgo;
}

namespace private_area {}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area  {}
namespace private_area { testing_mode ( function void test(void); ) }

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

// Constants & Variables //-------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// S o l v e A l g o  Interface //------------------------------------------------------------------
namespace public_area {
 /*CLASS clSolveAlgo */
 /* Represents a linear program solver for the minimum cost flow problem in a graph. */
 template <tdGraph> class clSolveAlgo : public clSolver<tuGraph> {
  //-------------------------------------------------------------------------------------------Types
  /*TYPE clSolveAlgo */ /* Type of the linear program solver used to solve the problem. */
  public_property
  typedef linearSystemSolver::clSolver<public_area::clVariableContent> clLinearSolver;
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clSolveAlgo(const clSolveAlgo &);
  private_property clSolveAlgo & operator = (const clSolveAlgo &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clSolveAlgo(void);
  public_property virtual destructor clSolveAlgo(void);

  public_property void buildLinearSystem(clFlowSystem &,clGraph<tuGraph> &) const;
  public_property tyInteger run(clGraph<tuGraph> &,const clLinearSolver &) const;
  public_property tyInteger run(clGraph<tuGraph> &) const;
 };
}

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

// S o l v e A l g o  Inline //---------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clSolveAlgo */
 /* Builds a linear program solver for the minimum cost flow problem in a graph. */
 template <tdGraph> inline clSolveAlgo<tuGraph>::clSolveAlgo(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clSolveAlgo */ /* Destructs the algorithm. */
 template <tdGraph> inline clSolveAlgo<tuGraph>::~clSolveAlgo(void) {}
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clSolveAlgo */
 /* Solves the minimum cost flow problem using the default linear program solver. */
 template <tdGraph> inline tyInteger clSolveAlgo<tuGraph>::run(clGraph<tuGraph> & agGraph) const
 { return (run(agGraph,clLinearSolver::defaultSolver())); }
}

// S o l v e A l g o  Implementation //-------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------BuildLinearSystem
 /*METHOD clSolveAlgo */
 /* Builds a linear program equivalent to the minimum cost flow problem of a graph. */
 template <tdGraph>
 void clSolveAlgo<tuGraph>::buildLinearSystem(clFlowSystem & agSystem,
                                              clGraph<tuGraph> & agGraph) const {
  typedef typename clGraph<tuGraph>::cpArcX::const_iterator  cpArcIterator1;
  typedef typename clNode<tuGraph>::cpArcX::const_iterator   cpArcIterator2;
  typedef typename clGraph<tuGraph>::cpNodeX::const_iterator cpNodeIterator;

  typedef std_map(tyArcKey,linearSystem::tyVariableKey) clAssociation;
  typedef linearSystem::tyVariableKey                   tyKey;

  tyKey          lcCounter     = 0;
  cpArcIterator1 lcCurrentArc1 = agGraph.arcs().begin();
  cpNodeIterator lcCurrentNode = agGraph.nodes().begin();
  cpArcIterator1 lcLastArc1    = agGraph.arcs().end();
  cpNodeIterator lcLastNode    = agGraph.nodes().end();

  clArc<tuGraph> *   lcArc;
  clAssociation      lcAssociation;
  clFlowConstraint * lcConstraint;
  cpArcIterator2     lcCurrentArc2;
  tyKey              lcKey;
  cpArcIterator2     lcLastArc2;
  clFlowVariable *   lcVariable1;
  clFlowVariable *   lcVariable2;

  // Capacity Constraints & Objective Function //
  while (lcCurrentArc1!=lcLastArc1) {
   lcArc=(*lcCurrentArc1).second;

   lcVariable1=new_object(clFlowVariable(agSystem,lcCounter++,
                                         linearSystem::realVariable,lcArc->key()));

   lcVariable2=new_object(clFlowVariable(agSystem,lcCounter++,
                                         linearSystem::realVariable,lcArc->key()));

   lcAssociation.insert(std_make_pair(lcArc->key(),lcVariable1->key()));
   lcConstraint=new_object(clFlowConstraint(agSystem,linearSystem::superiority));
   lcConstraint->setCoefficient(lcVariable1->key(),1.0);
   lcConstraint->setCoefficient(lcVariable2->key(),-1.0);
   lcConstraint->boundary()=lcArc->data().minimum();
   lcConstraint=new_object(clFlowConstraint(agSystem,linearSystem::inferiority));
   lcConstraint->setCoefficient(lcVariable1->key(),1.0);
   lcConstraint->setCoefficient(lcVariable2->key(),-1.0);
   lcConstraint->boundary()=lcArc->data().maximum();
   agSystem.objective().setCoefficient(lcVariable1->key(),lcArc->data().unitCost());
   agSystem.objective().setCoefficient(lcVariable2->key(),-lcArc->data().unitCost());
   lcCurrentArc1++;
  }

  new_object(clFlowVariable(agSystem,lcCounter,linearSystem::realVariable,nilArc()));
  new_object(clFlowVariable(agSystem,lcCounter+1,linearSystem::realVariable,nilArc()));
  agSystem.objective().kind()=linearSystem::minimum;

  // Flow Constraints //
  while (lcCurrentNode!=lcLastNode) {
   lcConstraint=new_object(clFlowConstraint(agSystem,linearSystem::equality));
   lcConstraint->boundary()=0.0;

   lcCurrentArc2=(*lcCurrentNode).second->incomingArcs().begin();
   lcLastArc2=(*lcCurrentNode).second->incomingArcs().end();

   if (lcCurrentArc2==lcLastArc2) {
    lcConstraint->setCoefficient(lcCounter,1.0);
    lcConstraint->setCoefficient(lcCounter+1,-1.0);
   }

   while (lcCurrentArc2!=lcLastArc2) {
    lcArc=(*lcCurrentArc2).second;
    lcKey=lcAssociation[lcArc->key()];
    lcConstraint->setCoefficient(lcKey,1.0);
    lcConstraint->setCoefficient(lcKey+1,-1.0);
    lcCurrentArc2++;
   }

   lcCurrentArc2=(*lcCurrentNode).second->outgoingArcs().begin();
   lcLastArc2=(*lcCurrentNode).second->outgoingArcs().end();

   if (lcCurrentArc2==lcLastArc2) {
    lcConstraint->setCoefficient(lcCounter,-1.0);
    lcConstraint->setCoefficient(lcCounter+1,1.0);
   }

   while (lcCurrentArc2!=lcLastArc2) {
    lcArc=(*lcCurrentArc2).second;
    lcKey=lcAssociation[lcArc->key()];
    lcConstraint->setCoefficient(lcKey,-1.0);
    lcConstraint->setCoefficient(lcKey+1,1.0);
    lcCurrentArc2++;
   }

   lcCurrentNode++;
  }
 }
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clSolveAlgo */
 /* Solves the minimum cost flow problem of a graph using a given linear program solver. */
 template <tdGraph> tyInteger clSolveAlgo<tuGraph>::run(clGraph<tuGraph> & agGraph,
                                                        const clLinearSolver & agSolver) const {
  typename clGraph<tuGraph>::cpArc *        lcArc;
  clFlowSystem::cpVariableX::const_iterator lcCurrentVariable;
  clFlowSystem::cpVariableX::const_iterator lcLastVariable;
  tyInteger                                 lcNbIteration;
  clFlowSystem                              lcSystem;
  clFlowVariable *                          lcVariable1;
  clFlowVariable *                          lcVariable2;

  // Linear System Resolution //
  buildLinearSystem(lcSystem,agGraph);
  lcNbIteration=agSolver.run(lcSystem);
  agGraph.solved()=lcSystem.solved();
  if (not lcSystem.solved()) return (lcNbIteration);

  // Connection With The Graph //
  lcCurrentVariable=lcSystem.variables().begin();
  lcLastVariable=lcSystem.variables().end();

  while (lcCurrentVariable!=lcLastVariable) {
   lcVariable1=(*lcCurrentVariable).second;
   lcCurrentVariable++;
   lcVariable2=(*lcCurrentVariable).second;

   if (lcVariable1->content().arc()!=nilArc()) {
    lcArc=&(agGraph.arc(lcVariable1->content().arc()));
    lcArc->data().flow()=lcVariable1->value()-lcVariable2->value();
   }

   lcCurrentVariable++;
  }

  return (lcNbIteration);
 }
}

// End //-------------------------------------------------------------------------------------------
}
#undef dll_export
#undef public_area
#undef private_area
#undef tdGraph
#undef tuGraph
#endif
 
//==================================================================================================
// G r a p h _ p r o b l e m                                                         Implementation
// M i n _ c o s t _ f l o w
// L i n e a r _ s y s t e m
//                                                                                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__ "graph_problem/min_cost_flow/linear_system.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define GRAPH_PROBLEM_MIN_COST_FLOW_DLL

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

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphProblemMinCostFlowLinearSystem
#define private_area graphProblemMinCostFlowLinearSystem_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Graph_problem/Min_cost_flow/Linear_system");

// Initialization //--------------------------------------------------------------------------------

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

// Constants & Variables //-------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

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

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

// X X X  Implementation //-------------------------------------------------------------------------
namespace {}

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