//==================================================================================================
// G r a p h _ p r o b l e m                                                              Interface
// M i n _ c o s t _ f l o w
// C y c l e _ c a n c e l i n g
//                                                                                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 implements the cycle-canceling algorithm to solve the minimum cost flow problem
   (with linear costs) in graphs. */

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

// Guardian //--------------------------------------------------------------------------------------
#ifndef guGraphProblemMinCostFlowCycleCanceling
#define guGraphProblemMinCostFlowCycleCanceling

// 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  graphProblemMinCostFlowCycleCanceling
#define private_area graphProblemMinCostFlowCycleCanceling_private

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

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniGraphProblemMinCostFlowCycleCanceling
has_initializer;

// 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 {
 template <tdGraph> struct tyDistanceInfo {
  clArc<tuGraph> * predecessor;
  tyReal           distance;
 };
}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area {
 template <tdGraph>
 tyBoolean findNegativeCycle(clGraph<tuGraph> &,std_map(clArc<tuGraph> *,tyInteger) &);
}

namespace private_area {
 template <tdGraph>
 void buildNegativeCycle(std_map(clArc<tuGraph> *,tyInteger) &,clNode<tuGraph> *,tyMark);

 testing_mode ( function void test(void); )
}

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 /*ERROR*/ extern_error erNegativeCycleProblem; /* Problem to build the negative cycle. */
}

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

// S o l v e A l g o  Interface //------------------------------------------------------------------
namespace public_area {
 /*CLASS clSolveAlgo */
 /* Represents an algorithm to solve the minimum cost flow problem in a graph using the
    cycle-canceling method. */
 template <tdGraph> class clSolveAlgo : public clSolver<tuGraph> {
  //-----------------------------------------------------------------------------------------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 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 an algorithm to solve 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) {}
}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------FindNegativeCycle
 /*FUNCTION*/
 /* Finds a negative cost cycle. <CODE>false</CODE> is returned if no such cycle exists. */
 template <tdGraph> tyBoolean findNegativeCycle(clGraph<tuGraph> & agGraph,
                                                std_map(clArc<tuGraph> *,tyInteger) & agCycle) {
  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_vector(clNode<tuGraph> *)         cpNodeS;
  typedef private_area::tyDistanceInfo<tuGraph> tyInfo;

  clArc<tuGraph> *  lcArc;
  cpArcIterator2    lcCurrentArc2;
  cpNodeIterator    lcCurrentNode2;
  tyInfo *          lcInfo1;
  tyInfo *          lcInfo2;
  cpArcIterator2    lcLastArc2;
  cpNodeIterator    lcLastNode2;
  tyReal            lcNewDistance;
  clNode<tuGraph> * lcNode;
  cpNodeS           lcNodeS;
  clNode<tuGraph> * lcStartNode;

  cpArcIterator1 lcCurrentArc1  = agGraph.arcs().begin();
  cpNodeIterator lcCurrentNode1 = agGraph.nodes().begin();
  cpArcIterator2 lcLastArc1     = agGraph.arcs().end();
  cpNodeIterator lcLastNode1    = agGraph.nodes().end();
  tyMark         lcMark1        = ++(agGraph.mark());
  tyMark         lcMark2        = ++(agGraph.mark());
  tyReal         lcMaximumCost  = 0.0;

  // Nodes Initialization //
  while (lcCurrentNode1!=lcLastNode1) {
   lcNode=(*lcCurrentNode1).second;
   lcNode->work()=new_object(tyInfo);
   ++lcCurrentNode1;
  }

  // Maximum Cost Search //
  while (lcCurrentArc1!=lcLastArc1) {
   lcArc=(*lcCurrentArc1).second;
   if (lcArc->data().unitCost()>lcMaximumCost) lcMaximumCost=lcArc->data().unitCost();
   ++lcCurrentArc1;
  }

  lcMaximumCost*=-1.0;

  // Negative Cycle Search //
  lcCurrentNode1=agGraph.nodes().begin();
  lcLastNode1=agGraph.nodes().end();

  while (lcCurrentNode1!=lcLastNode1) {
   lcStartNode=(*lcCurrentNode1).second;

   if (lcStartNode->mark()!=lcMark2) {
    // Nodes Initialization //
    lcCurrentNode2=agGraph.nodes().begin();
    lcLastNode2=agGraph.nodes().end();

    while (lcCurrentNode2!=lcLastNode2) {
     lcNode=(*lcCurrentNode2).second;
     lcInfo1=static_cast<tyInfo *>(lcNode->work());
     lcInfo1->distance=realMax();
     lcInfo1->predecessor=nil;
     ++lcCurrentNode2;
    }

    // Start Node Initialization //
    lcInfo1=static_cast<tyInfo *>(lcStartNode->work());
    lcInfo1->distance=0.0;
    lcNodeS.push_back(lcStartNode);
    lcStartNode->mark()=lcMark2;

    // Cycle Search //
    while (lcNodeS.size()!=0) {
     lcNode=lcNodeS.back();
     lcNodeS.pop_back();
     lcInfo1=static_cast<tyInfo *>(lcNode->work());
     lcNode->mark()=lcMark2;

     // Outgoing Arcs //
     lcCurrentArc2=lcNode->outgoingArcs().begin();
     lcLastArc2=lcNode->outgoingArcs().end();

     while (lcCurrentArc2!=lcLastArc2) {
      lcArc=(*lcCurrentArc2).second;

      if (lcArc->data().flow()<lcArc->data().maximum()) {
       lcInfo2=static_cast<tyInfo *>(lcArc->targetNode()->work());
       lcNewDistance=lcInfo1->distance+lcArc->data().unitCost();

       if (lcInfo2->distance>lcNewDistance) {
        lcInfo2->distance=lcNewDistance;
        lcInfo2->predecessor=lcArc;

        if (lcArc->targetNode()->mark()!=lcMark1) {
         lcArc->targetNode()->mark()=lcMark1;
         lcNodeS.push_back(lcArc->targetNode());
        }

        if (lcNewDistance<agGraph.nodes().size()*lcMaximumCost) {
         private_area::buildNegativeCycle(agCycle,lcArc->targetNode(),++(agGraph.mark()));
         deleteNodeWorkspace(agGraph,tyInfo());
         return (true);
        }
       }
      }

      ++lcCurrentArc2;
     }

     // Incoming Arcs //
     lcCurrentArc2=lcNode->incomingArcs().begin();
     lcLastArc2=lcNode->incomingArcs().end();

     while (lcCurrentArc2!=lcLastArc2) {
      lcArc=(*lcCurrentArc2).second;

      if (lcArc->data().flow()>lcArc->data().minimum()) {
       lcInfo2=static_cast<tyInfo *>(lcArc->sourceNode()->work());
       lcNewDistance=lcInfo1->distance-lcArc->data().unitCost();

       if (lcInfo2->distance>lcNewDistance) {
        lcInfo2->distance=lcNewDistance;
        lcInfo2->predecessor=lcArc;

        if (lcArc->sourceNode()->mark()!=lcMark1) {
         lcArc->sourceNode()->mark()=lcMark1;
         lcNodeS.push_back(lcArc->sourceNode());
        }

        if (lcNewDistance<agGraph.nodes().size()*lcMaximumCost) {
         private_area::buildNegativeCycle(agCycle,lcArc->sourceNode(),++(agGraph.mark()));
         deleteNodeWorkspace(agGraph,tyInfo());
         return (true);
        }
       }
      }

      ++lcCurrentArc2;
     }
    }
   }

   ++lcCurrentNode1;
  }

  deleteNodeWorkspace(agGraph,tyInfo());
  return (false);
 }
}

namespace private_area {
 //-------------------------------------------------------------------------------BuildNegativeCycle
 template <tdGraph> void buildNegativeCycle(std_map(clArc<tuGraph> *,tyInteger) & agCycle,
                                            clNode<tuGraph> * agStartNode,tyMark agMark) {
  method_name("BuildNegativeCycle");

  typedef private_area::tyDistanceInfo<tuGraph> tyInfo;

  clArc<tuGraph> *  lcArc;
  clNode<tuGraph> * lcNode;
  clNode<tuGraph> * lcFirstNode;

  clNode<tuGraph> * lcPredecessor = agStartNode;

  agCycle.erase(agCycle.begin(),agCycle.end());

  // Cycle Search //
  do {
   lcNode=lcPredecessor;
   lcNode->mark()=agMark;
   lcArc=static_cast<tyInfo *>(lcNode->work())->predecessor;

   if (lcArc->targetNode()==lcNode) lcPredecessor=lcArc->sourceNode();
   else lcPredecessor=lcArc->targetNode();
  }
  while (lcPredecessor!=nil and lcPredecessor->mark()!=agMark);

  if (lcPredecessor==nil) send_error(erNegativeCycleProblem);
  lcFirstNode=lcPredecessor;

  // Cycle Building //
  do {
   lcNode=lcPredecessor;
   lcArc=static_cast<tyInfo *>(lcNode->work())->predecessor;

   if (lcArc->targetNode()==lcNode) {
    lcPredecessor=lcArc->sourceNode();
    agCycle.insert(std_make_pair(lcArc,+1));
   }
   else {
    lcPredecessor=lcArc->targetNode();
    agCycle.insert(std_make_pair(lcArc,-1));
   }
  }
  while (lcPredecessor!=lcFirstNode and lcPredecessor!=nil);
 }
}

// S o l v e A l g o  Implementation //-------------------------------------------------------------
namespace public_area {
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clSolveAlgo */
 /* Solves the minimum cost flow problem using the cycle-canceling method. */
 template <tdGraph> tyInteger clSolveAlgo<tuGraph>::run(clGraph<tuGraph> & agGraph) const {
  method_name("solveAlgo::run");

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

  typedef typename cpCycle::const_iterator                 cpIterator1;
  typedef typename clNode<tuGraph>::cpArcX::const_iterator cpIterator2;

  cpArc *     lcArc;
  cpIterator1 lcCurrentArc1;
  cpIterator2 lcCurrentArc2;
  cpCycle     lcCycle;
  tyReal      lcIncrement;
  cpIterator1 lcLastArc1;
  cpIterator2 lcLastArc2;
  tyReal      lcLeft;
  tyCardinal  lcNbIteration;
  cpArc *     lcReturnLoop;

  cpNode * lcSourceNode = firstNode(agGraph);
  cpNode * lcTargetNode = lastNode(agGraph);

  // Compatible Flow Search //
  lcNbIteration=findCompatibleFlow(agGraph,false);
  if (not agGraph.solved()) return (lcNbIteration);
  agGraph.solved()=false;

  // 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().unitCost()=0.0;
  lcReturnLoop->data().flow()=0.0;

  lcCurrentArc2=lcReturnLoop->sourceNode()->incomingArcs().begin();
  lcLastArc2=lcReturnLoop->sourceNode()->incomingArcs().end();

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

  // Cycle Canceling //
  while (findNegativeCycle(agGraph,lcCycle)) {
   lcNbIteration++;
   lcIncrement=realMax();
   lcCurrentArc1=lcCycle.begin();
   lcLastArc1=lcCycle.end();

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

    if ((*lcCurrentArc1).second==+1) lcLeft=lcArc->data().maximum()-lcArc->data().flow();
    else lcLeft=lcArc->data().flow()-lcArc->data().minimum();

    if (lcLeft<lcIncrement) lcIncrement=lcLeft;
    lcCurrentArc1++;
   }

   increaseFlow(lcCycle,lcIncrement);
  }

  delete_object(lcReturnLoop);
  agGraph.solved()=true;
  return (lcNbIteration);
 }
}

// End //-------------------------------------------------------------------------------------------
}
#undef dll_export
#undef tdGraph
#undef tuGraph
#undef public_area
#undef private_area
#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
// C y c le _ c a n c e l i n g
//                                                                                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/cycle_canceling.cpp"

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

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

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphProblemMinCostFlowCycleCanceling
#define private_area graphProblemMinCostFlowCycleCanceling_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Graph_problem/Min_cost_flow/Cycle_canceling");

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

// Errors //----------------------------------------------------------------------------------------
namespace public_area { static_error erNegativeCycleProblem; }

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

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

    erNegativeCycleProblem.create("Min Cost Flow - Problem to build the negative cycle.");
   }

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


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