//==================================================================================================
// G r a p h _ p r o b l e m                                                              Interface
// M i n _ c o s t _ f l o w
// A l g o r i t h 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 basic algorithms for the minimum cost flow problem in graphs. */

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

// Guardian //--------------------------------------------------------------------------------------
#ifndef guGraphProblemMinCostFlowAlgorithm
#define guGraphProblemMinCostFlowAlgorithm

// Headers //---------------------------------------------------------------------------------------
#include <bpp/graph_problem/min_cost_flow/structure.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  graphProblemMinCostFlowAlgorithm
#define private_area graphProblemMinCostFlowAlgorithm_private

namespace public_area  { /*NAMESPACE*/ using namespace graphProblemMinCostFlowStructure; }
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 clSolver;
}

namespace private_area {
 template <tdGraph> class clMintyColorForCompatibility1;
 template <tdGraph> class clMintyColorForCompatibility2;
}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area {
 template <tdGraph> tyBoolean checkCompatibility(const clGraph<tuGraph> &);
 template <tdGraph> tyBoolean checkFlow(const clGraph<tuGraph> &);
 template <tdGraph> tyInteger findCompatibleFlow(clGraph<tuGraph> &,tyBoolean);
 template <tdGraph> void      increaseFlow(std_map(clArc<tuGraph> *,tyInteger) &,tyReal);
 template <tdGraph> tyReal    totalCost(const clGraph<tuGraph> &);
}

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 r  Interface //------------------------------------------------------------------------
namespace public_area {
 /*CLASS clSolver */
 /* Represents a solver for the minimum cost flow problem with linear costs in a graph.
    It is an abstract class. */
 template <tdGraph> class clSolver {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clSolver(const clSolver &);
  private_property clSolver & operator = (const clSolver &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clSolver(void);
  public_property virtual destructor clSolver(void);

  /*AMETHOD clSolver */
  /* Solves the minimum cost flow problem in a graph. Abstract method. */
  public_property virtual tyInteger run(clGraph<tuGraph> & agGraph) const = 0;
 };
}

// M i n t y C o l o r F o r C o m p a t i b i l i t y 1  Interface //------------------------------
namespace private_area {
 template <tdGraph> class clMintyColorForCompatibility1 {
  //-------------------------------------------------------------------------------------------Types
  public_property typedef clArc<tuGraph> cpArc;
  //-----------------------------------------------------------------------------------------Private
  private_property
  constructor clMintyColorForCompatibility1(const clMintyColorForCompatibility1 &);

  private_property
  clMintyColorForCompatibility1 & operator = (const clMintyColorForCompatibility1 &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clMintyColorForCompatibility1(void) {}
  public_property destructor clMintyColorForCompatibility1(void) {}

  public_property tyBoolean red(const cpArc &) const;
  public_property tyBoolean black(const cpArc &) const;
  public_property tyBoolean blue(const cpArc &) const;
  public_property tyBoolean green(const cpArc &) const;

  public_property tcString color(const cpArc &) const;
 };
}

// M i n t y C o l o r F o r C o m p a t i b i l i t y 2  Interface //------------------------------
namespace private_area {
 template <tdGraph> class clMintyColorForCompatibility2 {
  //-------------------------------------------------------------------------------------------Types
  public_property typedef clArc<tuGraph> cpArc;
  //-----------------------------------------------------------------------------------------Private
  private_property
  constructor clMintyColorForCompatibility2(const clMintyColorForCompatibility2 &);

  private_property
  clMintyColorForCompatibility2 & operator = (const clMintyColorForCompatibility2 &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clMintyColorForCompatibility2(void) {}
  public_property destructor clMintyColorForCompatibility2(void) {}

  public_property tyBoolean red(const cpArc &) const;
  public_property tyBoolean black(const cpArc &) const;
  public_property tyBoolean blue(const cpArc &) const;
  public_property tyBoolean green(const cpArc &) const;

  public_property tcString color(const cpArc &) const;
 };
}

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

// S o l v e r  Inline //---------------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clSolver */
 /* Builds a solver for the minimum cost flow problem in a graph. */
 template <tdGraph> inline clSolver<tuGraph>::clSolver(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clSolver */ /* Destructs the solver. */
 template <tdGraph> inline clSolver<tuGraph>::~clSolver(void) {}
}

// M i n t y C o l o r F o r C o m p a t i b i l i t y 1  Inline //---------------------------------
namespace private_area {
 //----------------------------------------------------------------------------------------------Red
 template <tdGraph>
 inline tyBoolean clMintyColorForCompatibility1<tuGraph>::red(const cpArc & agArc) const {
  return (agArc.data().flow()==agArc.data().minimum()
          and agArc.data().flow()==agArc.data().maximum());
 }
 //--------------------------------------------------------------------------------------------Black
 template <tdGraph>
 inline tyBoolean clMintyColorForCompatibility1<tuGraph>::black(const cpArc & agArc) const
 { return (agArc.data().flow()<agArc.data().maximum()); }
 //---------------------------------------------------------------------------------------------Blue
 template <tdGraph>
 inline tyBoolean clMintyColorForCompatibility1<tuGraph>::blue(const cpArc & agArc) const
 { return (agArc.data().flow()>agArc.data().minimum()); }
 //--------------------------------------------------------------------------------------------Green
 template <tdGraph>
 inline tyBoolean clMintyColorForCompatibility1<tuGraph>::green(const cpArc & agArc) const {
  return (agArc.data().flow()>agArc.data().minimum()
          and agArc.data().flow()<agArc.data().maximum());
 }
}

// M i n t y C o l o r F o r C o m p a t i b i l i t y 2  Inline //---------------------------------
namespace private_area {
 //----------------------------------------------------------------------------------------------Red
 template <tdGraph>
 inline tyBoolean clMintyColorForCompatibility2<tuGraph>::red(const cpArc & agArc) const {
  return (agArc.data().flow()==agArc.data().minimum()
          and agArc.data().flow()==agArc.data().maximum());
 }
 //--------------------------------------------------------------------------------------------Black
 template <tdGraph>
 inline tyBoolean clMintyColorForCompatibility2<tuGraph>::black(const cpArc & agArc) const
 { return (agArc.data().flow()>agArc.data().minimum()); }
 //---------------------------------------------------------------------------------------------Blue
 template <tdGraph>
 inline tyBoolean clMintyColorForCompatibility2<tuGraph>::blue(const cpArc & agArc) const
 { return (agArc.data().flow()<agArc.data().maximum()); }
 //--------------------------------------------------------------------------------------------Green
 template <tdGraph>
 inline tyBoolean clMintyColorForCompatibility2<tuGraph>::green(const cpArc & agArc) const {
  return (agArc.data().flow()>agArc.data().minimum()
          and agArc.data().flow()<agArc.data().maximum());
 }
}

// Function Implementation //-----------------------------------------------------------------------
namespace public_area {
 //-------------------------------------------------------------------------------CheckCompatibility
 /*FUNCTION*/
 /* Verifies that the flow in a graph is compatible with the capacity boundaries
    (<CODE>true</CODE> = compatible). */
 template <tdGraph> tyBoolean checkCompatibility(const clGraph<tuGraph> & agGraph) {
  typedef typename clGraph<tuGraph>::cpArcX::const_iterator clArcIterator;

  tyBoolean     lcCompatible = true;
  clArcIterator lcCurrentArc = agGraph.arcs().begin();
  clArcIterator lcLastArc    = agGraph.arcs().end();

  clArc<tuGraph> * lcArc;

  while (lcCurrentArc!=lcLastArc and lcCompatible) {
   lcArc=(*lcCurrentArc).second;

   if (lcArc->data().flow()<lcArc->data().minimum()
       or lcArc->data().flow()>lcArc->data().maximum()) lcCompatible=false;

   lcCurrentArc++;
  }

  return (lcCompatible);
 }
 //----------------------------------------------------------------------------------------CheckFlow
 /*FUNCTION*/
 /* Verifies that the supposed flow in a graph is really a flow (<CODE>true</CODE> = valid). */
 template <tdGraph> tyBoolean checkFlow(const clGraph<tuGraph> & agGraph) {
  method_name("checkFlow");

  typedef typename clGraph<tuGraph>::cpNodeX::const_iterator clNodeIterator;
  typedef typename clNode<tuGraph>::cpArcX::const_iterator   clArcIterator;

  tyReal lcFlow;

  clNodeIterator    lcCurrentNode = agGraph.nodes().begin();
  clNodeIterator    lcLastNode    = agGraph.nodes().end();
  clNode<tuGraph> * lcSourceNode  = firstNode(agGraph);
  clNode<tuGraph> * lcTargetNode  = lastNode(agGraph);

  if (lcSourceNode==nil or lcTargetNode==nil) send_error(erInvalidFlowGraph);

  clArcIterator     lcCurrentArc  = lcSourceNode->outgoingArcs().begin();
  clArcIterator     lcLastArc     = lcSourceNode->outgoingArcs().end();
  tyReal            lcMainFlow    = 0.0;
  tyBoolean         lcValid       = true;

  while (lcCurrentArc!=lcLastArc) {
   lcMainFlow+=(*lcCurrentArc).second->data().flow();
   lcCurrentArc++;
  }

  while (lcCurrentNode!=lcLastNode and lcValid) {
   if ((*lcCurrentNode).second!=lcSourceNode) {
    lcFlow=0.0;
    lcCurrentArc=(*lcCurrentNode).second->incomingArcs().begin();
    lcLastArc=(*lcCurrentNode).second->incomingArcs().end();

    while (lcCurrentArc!=lcLastArc) {
     lcFlow+=(*lcCurrentArc).second->data().flow();
     lcCurrentArc++;
    }

    if ((*lcCurrentNode).second==lcTargetNode) lcFlow-=lcMainFlow;
    else {
     lcCurrentArc=(*lcCurrentNode).second->outgoingArcs().begin();
     lcLastArc=(*lcCurrentNode).second->outgoingArcs().end();

     while (lcCurrentArc!=lcLastArc) {
      lcFlow-=(*lcCurrentArc).second->data().flow();
      lcCurrentArc++;
     }
    }

    if (lcFlow!=0.0) lcValid=false;
   }

   lcCurrentNode++;
  }

  return (lcValid);
 }
 //-------------------------------------------------------------------------------FindCompatibleFlow
 /*FUNCTION*/
 /* Finds a compatible flow in a graph. The second argument is set to <CODE>true</CODE>
    if the algorithm has to consider the current flow of the graph, which is supposed to
    help it. */
 template <tdGraph> tyInteger findCompatibleFlow(clGraph<tuGraph> & agGraph,tyBoolean agKeepFlow) {
  method_name("findCompatibleFlow");

  typedef clArc<tuGraph>             cpArc;
  typedef std_map(cpArc *,tyInteger) cpCocycle;
  typedef std_map(cpArc *,tyInteger) cpCycle;
  typedef clNode<tuGraph>            cpNode;

  typedef typename clGraph<tuGraph>::cpArcX::const_iterator cpIterator1;
  typedef typename cpCocycle::const_iterator                cpIterator2;
  typedef typename clNode<tuGraph>::cpArcX::const_iterator  cpIterator3;

  cpArc *     lcArc;
  cpArc *     lcArc2;
  cpCocycle   lcCocycle;
  cpIterator1 lcCurrentArc1;
  cpIterator2 lcCurrentArc2;
  cpIterator3 lcCurrentArc3;
  cpCycle     lcCycle;
  tyReal      lcIncrement;
  cpIterator1 lcLastArc1;
  cpIterator2 lcLastArc2;
  cpIterator3 lcLastArc3;
  cpArc *     lcReturnLoop;

  private_area::clMintyColorForCompatibility1<tuGraph> lcMintyColor1;
  private_area::clMintyColorForCompatibility2<tuGraph> lcMintyColor2;

  tyCardinal lcNbIteration = 0;
  cpNode *   lcSourceNode  = firstNode(agGraph);
  cpNode *   lcTargetNode  = lastNode(agGraph);

  agGraph.solved()=false;

  // Flow Initialization //
  if (not agKeepFlow) {
   lcCurrentArc1=agGraph.arcs().begin();
   lcLastArc1=agGraph.arcs().end();

   while (lcCurrentArc1!=lcLastArc1) {
    (*lcCurrentArc1).second->data().flow()=0.0;
    lcCurrentArc1++;
   }
  }

  // Return Loop Adding //
  if (lcSourceNode==nil or lcTargetNode==nil) send_error(erInvalidFlowGraph);

  lcReturnLoop=new_object(cpArc(agGraph,agGraph.getNewArcKey(),prArcData(),
                          lcTargetNode->key(),lcSourceNode->key()));

  lcReturnLoop->data().minimum()=prArcData::negativeInfinity();
  lcReturnLoop->data().maximum()=prArcData::positiveInfinity();
  lcReturnLoop->data().flow()=0.0;

  if (agKeepFlow) {
   lcCurrentArc3=lcReturnLoop->sourceNode()->incomingArcs().begin();
   lcLastArc3=lcReturnLoop->sourceNode()->incomingArcs().end();

   while (lcCurrentArc3!=lcLastArc3) {
    lcReturnLoop->data().flow()+=(*lcCurrentArc3).second->data().flow();
    lcCurrentArc3++;
   }
  }

  // Flow Improving //
  lcCurrentArc1=agGraph.arcs().begin();
  lcLastArc1=agGraph.arcs().end();

  while (lcCurrentArc1!=lcLastArc1) {
   lcArc=(*lcCurrentArc1).second;

   // Flow Increase //
   if (lcArc->data().flow()<lcArc->data().minimum()) {
    while (lcArc->data().flow()<lcArc->data().minimum()
           and findMintyCycle(*lcArc,lcMintyColor1,lcCycle,lcCocycle)) {
     lcNbIteration++;
     lcCurrentArc2=lcCycle.begin();
     lcLastArc2=lcCycle.end();
     lcIncrement=realMax();

     while (lcCurrentArc2!=lcLastArc2) {
      lcArc2=(*lcCurrentArc2).first;

      if ((*lcCurrentArc2).second==+1)
       lcIncrement=mini(lcArc2->data().maximum()-lcArc2->data().flow(),lcIncrement);
      else lcIncrement=mini(lcArc2->data().flow()-lcArc2->data().minimum(),lcIncrement);

      lcCurrentArc2++;
     }

     increaseFlow(lcCycle,lcIncrement);
    }

    if (lcArc->data().flow()<lcArc->data().minimum()) {
     delete_object(lcReturnLoop);
     return (-1);
    }
   }

   // Flow Decrease //
   else if (lcArc->data().flow()>lcArc->data().maximum()) {
    while (lcArc->data().flow()>lcArc->data().maximum()
           and findMintyCycle(*lcArc,lcMintyColor2,lcCycle,lcCocycle)) {
     lcNbIteration++;
     lcCurrentArc2=lcCycle.begin();
     lcLastArc2=lcCycle.end();
     lcIncrement=realMax();

     while (lcCurrentArc2!=lcLastArc2) {
      lcArc2=(*lcCurrentArc2).first;

      if ((*lcCurrentArc2).second==+1)
       lcIncrement=mini(lcArc2->data().flow()-lcArc2->data().minimum(),lcIncrement);
      else lcIncrement=mini(lcArc2->data().maximum()-lcArc2->data().flow(),lcIncrement);

      lcCurrentArc2++;
     }

     increaseFlow(lcCycle,-lcIncrement);
    }

    if (lcArc->data().flow()>lcArc->data().maximum()) {
     delete_object(lcReturnLoop);
     return (-1);
    }
   }

   lcCurrentArc1++;
  }

  agGraph.solved()=true;
  delete_object(lcReturnLoop);
  return (lcNbIteration);
 }
 //-------------------------------------------------------------------------------------IncreaseFlow
 /*FUNCTION*/ /* Increases the flow in a cycle of a given value. */
 template <tdGraph>
 void increaseFlow(std_map(clArc<tuGraph> *,tyInteger) & agCycle,tyReal agValue) {
  typedef typename std_map(clArc<tuGraph> *,tyInteger)::const_iterator cpIterator;

  cpIterator lcCurrentArc = agCycle.begin();
  cpIterator lcLastArc    = agCycle.end();

  while (lcCurrentArc!=lcLastArc) {
   if ((*lcCurrentArc).second==+1) (*lcCurrentArc).first->data().flow()+=agValue;
   else (*lcCurrentArc).first->data().flow()-=agValue;

   lcCurrentArc++;
  }
 }
 //----------------------------------------------------------------------------------------TotalCost
 /*FUNCTION*/ /* Computes the total cost of a flow in a graph. */
 template <tdGraph> tyReal totalCost(const clGraph<tuGraph> & agGraph) {
  typedef typename clGraph<tuGraph>::cpArcX::const_iterator clArcIterator;

  tyReal        lcCost       = 0.0;
  clArcIterator lcCurrentArc = agGraph.arcs().begin();
  clArcIterator lcLastArc    = agGraph.arcs().end();

  while (lcCurrentArc!=lcLastArc) {
   lcCost+=(*lcCurrentArc).second->data().cost();
   lcCurrentArc++;
  }

  return (lcCost);
 }
}

// M i n t y C o l o r F o r C o m p a t i b i l i t y 1  Implementation //-------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------------Color
 template <tdGraph>
 tcString clMintyColorForCompatibility1<tuGraph>::color(const cpArc & agArc) const {
  if (red(agArc)) return ("red");
  if (black(agArc)) return ("black");
  if (blue(agArc)) return ("blue");
  return ("green");
 }
}

// M i n t y C o l o r F o r C o m p a t i b i l i t y 2  Implementation //-------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------------Color
 template <tdGraph>
 tcString clMintyColorForCompatibility2<tuGraph>::color(const cpArc & agArc) const {
  if (red(agArc)) return ("red");
  if (black(agArc)) return ("black");
  if (blue(agArc)) return ("blue");
  return ("green");
 }
}

// 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
// A l g o r i t h 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/algorithm.cpp"

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

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

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphProblemMinCostFlowAlgorithm
#define private_area graphProblemMinCostFlowAlgorithm_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Graph_problem/Min_cost_flow/Algorithm");

// 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 //-------------------------------------------------------------------------------------------
}