//==================================================================================================
// G r a p h _ p r o b l e m                                                              Interface
// M i n _ c o s t _ t e n s i o n
// C o n f o r m 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 an algorithm we call "conforming" (or "out-of-kilter") to solve
   the minimum cost tension problem in graphs. Several versions of this algorithm are
   provided for linear, piecewise linear and convex costs. */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "graph_problem/min_cost_tension/conforming.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guGraphProblemMinCostTensionConforming
#define guGraphProblemMinCostTensionConforming

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

namespace bpp {

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

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphProblemMinCostTensionConforming
#define private_area graphProblemMinCostTensionConforming_private

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

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniGraphProblemMinCostTensionConforming
has_initializer;

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

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

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area {}

namespace private_area {
 template <tdGraph,class prConformity> class clDirectMintyColor;
 template <tdGraph,class prConformity> class clInverseMintyColor;
}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area {
 template <tdGraph> void increaseFlow(clGraph<tuGraph> &,ctCycle &,tyReal);
 template <tdGraph> void increaseFlow(const std_map(clArc<tuGraph> *,tyInteger) &,tyReal);
 template <tdGraph> void nullFlow(clGraph<tuGraph> &);
}

namespace private_area {
 template <tdGraph,class prConformity> tyInteger conformArc(clArc<tuGraph> &,const prConformity &);

 template <tdGraph,class prConformity>
 void improveArc(clArc<tuGraph> &,const clDirectMintyColor<tuGraph,prConformity> &,
                 const clInverseMintyColor<tuGraph,prConformity> &,const prConformity &);

 template <tdGraph,class prConformity>
 tyReal maximumDecreaseFlow(const std_map(clArc<tuGraph> *,tyInteger) &,const prConformity &);

 template <tdGraph,class prConformity>
 tyReal maximumIncreaseFlow(const std_map(clArc<tuGraph> *,tyInteger) &,const prConformity &);

 template <tdGraph,class prConformity>
 tyReal maximumDecreaseTension(const std_map(clArc<tuGraph> *,tyInteger) &,const prConformity &);

 template <tdGraph,class prConformity>
 tyReal maximumIncreaseTension(const std_map(clArc<tuGraph> *,tyInteger) &,const prConformity &);

 function clOutStream & operator << (clOutStream &,tyMintyColor);

 testing_mode ( function void test(void); )
}

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 /*ERROR*/ extern_error erMaximumDecreaseFlow;
 /* The maximum decrease flow is negative, zero or infinite in the "conforming" algorithm. */

 /*ERROR*/ extern_error erMaximumIncreaseFlow;
 /* The maximum increase flow is negative, zero or infinite in the "conforming" algorithm. */

 /*ERROR*/ extern_error erMaximumDecreaseTension;
 /* The maximum decrease tension is negative, zero or infinite in the "conforming" algorithm. */

 /*ERROR*/ extern_error erMaximumIncreaseTension;
 /* The maximum increase tension is negative, zero or infinite in the "conforming" algorithm. */
}

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

// D i r e c t M i n t y C o l o r  Interface //----------------------------------------------------
namespace private_area {
 template <tdGraph,class prConformity> class clDirectMintyColor {
  //-------------------------------------------------------------------------------------------Types
  public_property typedef clArc<tuGraph> cpArc;
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clDirectMintyColor(const clDirectMintyColor &);
  private_property clDirectMintyColor & operator = (const clDirectMintyColor &);

  private_property const prConformity & atConformity;
  //------------------------------------------------------------------------------------------Public
  public_property constructor clDirectMintyColor(const prConformity &);
  public_property destructor clDirectMintyColor(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;
 };
}

// I n v e r s e M i n t y C o l o r  Interface //--------------------------------------------------
namespace private_area {
 template <tdGraph,class prConformity> class clInverseMintyColor {
  //-------------------------------------------------------------------------------------------Types
  public_property typedef clArc<tuGraph> cpArc;
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clInverseMintyColor(const clInverseMintyColor &);
  private_property clInverseMintyColor & operator = (const clInverseMintyColor &);

  private_property const prConformity & atConformity;
  //------------------------------------------------------------------------------------------Public
  public_property constructor clInverseMintyColor(const prConformity &);
  public_property destructor clInverseMintyColor(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;
 };
}

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

// D i r e c t M i n t y C o l o r  Inline //-------------------------------------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------Constructor
 template <tdGraph,class prConformity> inline clDirectMintyColor<tuGraph,prConformity>::
 clDirectMintyColor(const prConformity & agConformity) : atConformity(agConformity) {}
 //----------------------------------------------------------------------------------------------Red
 template <tdGraph,class prConformity>
 inline tyBoolean clDirectMintyColor<tuGraph,prConformity>::red(const cpArc & agArc) const
 { return (atConformity.arcColor(agArc)==private_area::red); }
 //--------------------------------------------------------------------------------------------Black
 template <tdGraph,class prConformity>
 inline tyBoolean clDirectMintyColor<tuGraph,prConformity>::black(const cpArc & agArc) const
 { return (atConformity.arcColor(agArc)==private_area::black); }
 //---------------------------------------------------------------------------------------------Blue
 template <tdGraph,class prConformity>
 inline tyBoolean clDirectMintyColor<tuGraph,prConformity>::blue(const cpArc & agArc) const
 { return (atConformity.arcColor(agArc)==private_area::blue); }
 //--------------------------------------------------------------------------------------------Green
 template <tdGraph,class prConformity>
 inline tyBoolean clDirectMintyColor<tuGraph,prConformity>::green(const cpArc & agArc) const
 { return (atConformity.arcColor(agArc)==private_area::green); }
}

// I n v e r s e M i n t y C o l o r  Inline //-----------------------------------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------Constructor
 template <tdGraph,class prConformity> inline clInverseMintyColor<tuGraph,prConformity>::
 clInverseMintyColor(const prConformity & agConformity) : atConformity(agConformity) {}
 //----------------------------------------------------------------------------------------------Red
 template <tdGraph,class prConformity>
 inline tyBoolean clInverseMintyColor<tuGraph,prConformity>::red(const cpArc & agArc) const
 { return (atConformity.arcColor(agArc)==private_area::red); }
 //--------------------------------------------------------------------------------------------Black
 template <tdGraph,class prConformity>
 inline tyBoolean clInverseMintyColor<tuGraph,prConformity>::black(const cpArc & agArc) const
 { return (atConformity.arcColor(agArc)==private_area::blue); }
 //---------------------------------------------------------------------------------------------Blue
 template <tdGraph,class prConformity>
 inline tyBoolean clInverseMintyColor<tuGraph,prConformity>::blue(const cpArc & agArc) const
 { return (atConformity.arcColor(agArc)==private_area::black); }
 //--------------------------------------------------------------------------------------------Green
 template <tdGraph,class prConformity>
 inline tyBoolean clInverseMintyColor<tuGraph,prConformity>::green(const cpArc & agArc) const
 { return (atConformity.arcColor(agArc)==private_area::green); }
}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area {
 //-------------------------------------------------------------------------------------IncreaseFlow
 /*FUNCTION*/ /* Increases the flow in a cycle. */
 template <tdGraph>
 void increaseFlow(clGraph<tuGraph> & agGraph,ctCycle & agCycle,tyReal agValue) {
  clCycle::const_iterator lcCurrentArc = agCycle.begin();
  clCycle::const_iterator lcLastArc    = agCycle.end();

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

   lcCurrentArc++;
  }
 }
 //-------------------------------------------------------------------------------------IncreaseFlow
 /*FUNCTION*/ /* Increases the flow in a cycle. */
 template <tdGraph>
 void increaseFlow(const 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++;
  }
 }
 //-----------------------------------------------------------------------------------------NullFlow
 /*FUNCTION*/ /* Nulls the flow of a graph. */
 template <tdGraph> void nullFlow(clGraph<tuGraph> & agGraph) {
  typedef typename clGraph<tuGraph>::cpArcX::const_iterator cpIterator;

  cpIterator lcCurrentArc = agGraph.arcs().begin();
  cpIterator lcLastArc    = agGraph.arcs().end();

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

namespace private_area {
 //---------------------------------------------------------------------------------------ConformArc
 template <tdGraph,class prConformity>
 tyInteger conformArc(clArc<tuGraph> & agArc,const prConformity & agConformity) {
  clDirectMintyColor<tuGraph,prConformity>  lcDirectMintyColor(agConformity);
  clInverseMintyColor<tuGraph,prConformity> lcInverseMintyColor(agConformity);

  tyInteger lcIteration = 0;

  while (not agConformity.conformedArc(agArc)) {
   lcIteration++;
   improveArc(agArc,lcDirectMintyColor,lcInverseMintyColor,agConformity);
  }

  return (lcIteration);
 }
 //---------------------------------------------------------------------------------------ImproveArc
 template <tdGraph,class prConformity>
 void improveArc(clArc<tuGraph> & agArc,
                 const clDirectMintyColor<tuGraph,prConformity> & agDirectMintyColor,
                 const clInverseMintyColor<tuGraph,prConformity> & agInverseMintyColor,
                 const prConformity & agConformity) {
  method_name("improveArc");

  std_map(clArc<tuGraph> *,tyInteger) lcCocycle;
  std_map(clArc<tuGraph> *,tyInteger) lcCycle;
  tyReal                              lcMaximum;

  if (agConformity.arcColor(agArc)==black) {
   if (findMintyCycle<tuGraph,clDirectMintyColor<tuGraph,prConformity> >
       (agArc,agDirectMintyColor,lcCycle,lcCocycle)) {
    lcMaximum=maximumDecreaseFlow(lcCycle,agConformity);
    if (lcMaximum<=0.0 or lcMaximum==realMax()) send_error(erMaximumDecreaseFlow);
    increaseFlow(lcCycle,-lcMaximum);
   }
   else {
    lcMaximum=maximumIncreaseTension(lcCocycle,agConformity);
    if (lcMaximum<=0.0 or lcMaximum==realMax()) send_error(erMaximumIncreaseTension);
    graphProblemTension::increaseTension(lcCocycle,lcMaximum);
   }
  }
  else {
   if(findMintyCycle<tuGraph,clInverseMintyColor<tuGraph,prConformity> >
      (agArc,agInverseMintyColor,lcCycle,lcCocycle)) {
    lcMaximum=maximumIncreaseFlow(lcCycle,agConformity);
    if (lcMaximum<=0.0 or lcMaximum==realMax()) send_error(erMaximumIncreaseFlow);
    increaseFlow(lcCycle,lcMaximum);
   }
   else {
    lcMaximum=maximumDecreaseTension(lcCocycle,agConformity);
    if (lcMaximum<=0.0 or lcMaximum==realMax()) send_error(erMaximumDecreaseTension);
    graphProblemTension::increaseTension(lcCocycle,-lcMaximum);
   }
  }
 }
 //------------------------------------------------------------------------------MaximumDecreaseFlow
 template <tdGraph,class prConformity>
 tyReal maximumDecreaseFlow(const std_map(clArc<tuGraph> *,tyInteger) & agCycle,
                            const prConformity & agConformity) {
  typedef typename std_map(clArc<tuGraph> *,tyInteger)::const_iterator cpIterator;

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

  const clArc<tuGraph> * lcArc;

  tyReal lcMaximum = realMax();

  while (lcCurrentArc!=lcLastArc) {
   lcArc=(*lcCurrentArc).first;

   if ((*lcCurrentArc).second==+1)
    lcMaximum=mini(lcMaximum,agConformity.maximumDecreaseFlow(*lcArc));
   else lcMaximum=mini(lcMaximum,agConformity.maximumIncreaseFlow(*lcArc));

   lcCurrentArc++;
  }

  return (lcMaximum);
 }
 //------------------------------------------------------------------------------MaximumIncreaseFlow
 template <tdGraph,class prConformity>
 tyReal maximumIncreaseFlow(const std_map(clArc<tuGraph> *,tyInteger) & agCycle,
                                          const prConformity & agConformity) {
  typedef typename std_map(clArc<tuGraph> *,tyInteger)::const_iterator cpIterator;

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

  const clArc<tuGraph> * lcArc;

  tyReal lcMaximum = realMax();

  while (lcCurrentArc!=lcLastArc) {
   lcArc=(*lcCurrentArc).first;

   if ((*lcCurrentArc).second==+1)
    lcMaximum=mini(lcMaximum,agConformity.maximumIncreaseFlow(*lcArc));
   else lcMaximum=mini(lcMaximum,agConformity.maximumDecreaseFlow(*lcArc));

   lcCurrentArc++;
  }

  return (lcMaximum);
 }
 //---------------------------------------------------------------------------MaximumDecreaseTension
 template <tdGraph,class prConformity>
 tyReal maximumDecreaseTension(const std_map(clArc<tuGraph> *,tyInteger) & agCocycle,
                               const prConformity & agConformity) {
  typedef typename std_map(clArc<tuGraph> *,tyInteger)::const_iterator cpIterator;

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

  const clArc<tuGraph> * lcArc;

  tyReal lcMaximum = realMax();

  while (lcCurrentArc!=lcLastArc) {
   lcArc=(*lcCurrentArc).first;

   if ((*lcCurrentArc).second==+1)
    lcMaximum=mini(lcMaximum,agConformity.maximumDecreaseTension(*lcArc));
   else lcMaximum=mini(lcMaximum,agConformity.maximumIncreaseTension(*lcArc));

   lcCurrentArc++;
  }

  return (lcMaximum);
 }
 //---------------------------------------------------------------------------MaximumIncreaseTension
 template <tdGraph,class prConformity>
 tyReal maximumIncreaseTension(const std_map(clArc<tuGraph> *,tyInteger) & agCocycle,
                               const prConformity & agConformity) {
  typedef typename std_map(clArc<tuGraph> *,tyInteger)::const_iterator cpIterator;

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

  const clArc<tuGraph> * lcArc;

  tyReal lcMaximum = realMax();

  while (lcCurrentArc!=lcLastArc) {
   lcArc=(*lcCurrentArc).first;

   if ((*lcCurrentArc).second==+1)
    lcMaximum=mini(lcMaximum,agConformity.maximumIncreaseTension(*lcArc));
   else lcMaximum=mini(lcMaximum,agConformity.maximumDecreaseTension(*lcArc));

   lcCurrentArc++;
  }

  return (lcMaximum);
 }
}

// 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 _ t e n s i o n
// C o n f o r m 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_tension/conforming.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define GRAPH_PROBLEM_MIN_COST_TENSION_DLL

// Headers //---------------------------------------------------------------------------------------
#include <bpp/graph_problem/min_cost_tension/conforming.hpp> /*INTERFACE*/

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphProblemMinCostTensionConforming
#define private_area graphProblemMinCostTensionConforming_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Graph_problem/Min_cost_tension/Conforming");

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

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 static_error erMaximumDecreaseFlow;
 static_error erMaximumIncreaseFlow;
 static_error erMaximumDecreaseTension;
 static_error erMaximumIncreaseTension;
}

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

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

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

namespace private_area {
 //------------------------------------------------------------------------Operator << (Minty Color)
 function clOutStream & operator << (clOutStream & agStream,tyMintyColor agColor) {
  if (agColor==green) agStream << "Green";
  else if (agColor==black) agStream << "Black";
  else if (agColor==blue) agStream << "Blue";
  else agStream << "Red";

  return (agStream);
 }
}

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

    erMaximumDecreaseFlow.create("Min Cost Tension - The decrease flow is not valid.");
    erMaximumIncreaseFlow.create("Min Cost Tension - The increase flow is not valid.");
    erMaximumDecreaseTension.create("Min Cost Tension - The decrease tension is not valid.");
    erMaximumIncreaseTension.create("Min Cost Tension - The increase tension is not valid.");
   }

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

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