//==================================================================================================
// G r a p h _ p r o b l e m                                                              Interface
// M i n _ s p a n n i n g_ t r e e
//                                                                                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 spanning tree problem in graphs. */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "graph_problem/min_spanning_tree.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guGraphProblemMinSpanningTree
#define guGraphProblemMinSpanningTree

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

namespace bpp {

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

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphProblemMinSpanningTree
#define private_area graphProblemMinSpanningTree_private

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

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniGraphProblemMinSpanningTree
has_initializer;

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

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

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area {
 //------------------------------------------------------------------------------------------Classes
 template <tdGraph> class clKruskalAlgo;
 template <tdGraph> class clPrimAlgo;
 template <tdGraph> class clSolveAlgo;
 //-----------------------------------------------------------------------------------Variable Types
 /*TYPE*/ /* Arc of a graph with a minimum spanning tree problem. */
 typedef clArc<clCostData,clNoData> clSpanningArc;

 /*TYPE*/ /* Graph with a minimum spanning tree problem. */
 typedef clGraph<clCostData,clNoData> clSpanningGraph;

 /*TYPE*/ /* Node of a graph with a minimum spanning tree problem. */
 typedef clNode<clCostData,clNoData> clSpanningNode;
 //-----------------------------------------------------------------------------------Constant Types
 typedef const clSpanningArc   ctSpanningArc;
 typedef const clSpanningGraph ctSpanningGraph;
 typedef const clSpanningNode  ctSpanningNode;
}

namespace private_area { template <class prArc> class clLessArc; }

// Functions Interface //---------------------------------------------------------------------------
namespace public_area {
 template <tdGraph> tyReal totalCost(const clGraph<tuGraph> &);
}

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

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

// Constants & Variables //-------------------------------------------------------------------------
extern_dynamic_constant(private,clString,goDataLocation,?);

// K r u s k a l A l g o  Interface //--------------------------------------------------------------
namespace public_area {
 /*CLASS clKruskalAlgo */
 /* Represents Kruskal's algorithm to solve the minimum spanning tree problem in a graph. */
 template <tdGraph> class clKruskalAlgo : public clSolveAlgo<tuGraph> {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clKruskalAlgo(const clKruskalAlgo &);
  private_property clKruskalAlgo & operator = (const clKruskalAlgo &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clKruskalAlgo(void);
  public_property virtual destructor clKruskalAlgo(void);

  public_property void run(clGraph<tuGraph> &,clGraph<tuGraph> &) const;
 };
}

// P r i m A l g o  Interface //--------------------------------------------------------------------
namespace public_area {
 /*CLASS clPrimAlgo */
 /* Represents Prim's algorithm to solve the minimum spanning tree problem in a graph. */
 template <tdGraph> class clPrimAlgo : public clSolveAlgo<tuGraph> {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clPrimAlgo(const clPrimAlgo &);
  private_property clPrimAlgo & operator = (const clPrimAlgo &);
  //------------------------------------------------------------------------------------------Public
  public_property constructor clPrimAlgo(void);
  public_property virtual destructor clPrimAlgo(void);

  public_property void run(clGraph<tuGraph> &,clGraph<tuGraph> &) const;
 };
}

// S o l v e A l g o  Interface //------------------------------------------------------------------
namespace public_area {
 /*CLASS clSolveAlgo */
 /* Represents an algorithm to solve the minimum spanning tree problem in a graph. It is an
    abstract class. */
 template <tdGraph> class clSolveAlgo {
  //-----------------------------------------------------------------------------------------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);

  /*AMETHOD clSolveAlgo */ /* Executes the algorithm. Abstract method. */
  public_property virtual void run(clGraph<tuGraph> & agGraph,clGraph<tuGraph> & agTree) const = 0;

  public_property static void defaultRun(clGraph<tuGraph> &,clGraph<tuGraph> &);
 };
}

// L e s s A r c  Interfacce //---------------------------------------------------------------------
namespace private_area {
 template <class prArc> class clLessArc : public std::binary_function<prArc,prArc,tyBoolean> {
  //------------------------------------------------------------------------------------------Public
  public_property constructor clLessArc(void);
  public_property destructor  clLessArc(void);

  public_property tyBoolean operator () (const prArc &,const prArc &) const;
 };
}

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

// K r u s k a l A l g o  Inline //-----------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clKruskalAlgo */
 /* Builds Kruskal's algorithm that solves the minimum spanning tree problem in a graph. */
 template <tdGraph> inline clKruskalAlgo<tuGraph>::clKruskalAlgo(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clKruskalAlgo */ /* Destructs the algorithm. */
 template <tdGraph> inline clKruskalAlgo<tuGraph>::~clKruskalAlgo(void) {}
}

// P r i m A l g o  Inline //-----------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clPrimAlgo */
 /* Builds Prim's algorithm that solves the minimum spanning tree problem in a graph. */
 template <tdGraph> inline clPrimAlgo<tuGraph>::clPrimAlgo(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clPrimAlgo */ /* Destructs the algorithm. */
 template <tdGraph> inline clPrimAlgo<tuGraph>::~clPrimAlgo(void) {}
}

// S o l v e A l g o  Inline //---------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clSolveAlgo */
 /* Builds an algorithm to solve the minimum spanning tree problem in a graph. */
 template <tdGraph> inline clSolveAlgo<tuGraph>::clSolveAlgo(void) {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clSolveAlgo */ /* Destructs the algorithm. */
 template <tdGraph> inline clSolveAlgo<tuGraph>::~clSolveAlgo(void) {}
}

// L e s s A r c  Inline //-------------------------------------------------------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------Constructor
 template <class prArc> clLessArc<prArc>::clLessArc(void)
 : std::binary_function<prArc,prArc,tyBoolean>() {}
 //---------------------------------------------------------------------------------------Destructor
 template <class prArc> clLessArc<prArc>::~clLessArc(void) {}
 //--------------------------------------------------------------------------------------Operator ()
 template <class prArc>
 tyBoolean clLessArc<prArc>::operator () (const prArc & agArc1,const prArc & agArc2) const
 { return (agArc1->data().cost()<agArc2->data().cost()); }
}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area {
 //----------------------------------------------------------------------------------------TotalCost
 /*FUNCTION*/ /* Computes the total cost of 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);
 }
}

namespace private_area {}

// K r u s k a l A l g o  Implementation //---------------------------------------------------------
namespace public_area {
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clKruskalAlgo */ /* Solves the minimum spanning tree problem in a graph. */
 template <tdGraph>
 void clKruskalAlgo<tuGraph>::run(clGraph<tuGraph> & agGraph,clGraph<tuGraph> & agTree) const {
  typedef clArc<tuGraph>                                     cpArc;
  typedef std_vector(clArc<tuGraph> *)                       cpArcS;
  typedef typename clGraph<tuGraph>::cpArcX::const_iterator  cpArcIterator1;
  typedef typename cpArcS::const_iterator                    cpArcIterator2;
  typedef clNode<tuGraph>                                    cpNode;
  typedef typename clGraph<tuGraph>::cpNodeX::const_iterator cpNodeIterator;

  cpArc *        lcArc;
  cpArcS         lcArcS;
  cpArcIterator1 lcCurrentArc1;
  cpArcIterator2 lcCurrentArc2;
  cpNodeIterator lcCurrentNode;
  clCycle        lcCycle;
  cpArcIterator1 lcLastArc1;
  cpArcIterator2 lcLastArc2;
  cpNodeIterator lcLastNode;
  cpArc *        lcNewArc;

  // Arcs Sorting //
  lcArcS.reserve(agGraph.arcs().size());
  lcCurrentArc1=agGraph.arcs().begin();
  lcLastArc1=agGraph.arcs().end();

  while (lcCurrentArc1!=lcLastArc1) {
   lcArcS.push_back((*lcCurrentArc1).second);
   lcCurrentArc1++;
  }

  std_sort(lcArcS.begin(),lcArcS.end(),private_area::clLessArc<clArc<tuGraph> *>());

  // Nodes Copy //
  agTree.clear();
  lcCurrentNode=agGraph.nodes().begin();
  lcLastNode=agGraph.nodes().end();

  while (lcCurrentNode!=lcLastNode) {
   new_object(cpNode(agTree,*((*lcCurrentNode).second)));
   lcCurrentNode++;
  }

  // Tree Construction //
  lcCurrentArc2=lcArcS.begin();
  lcLastArc2=lcArcS.end();

  while (lcCurrentArc2!=lcLastArc2 and (agTree.arcs().size()+1 < agTree.nodes().size())) {
   lcArc=*lcCurrentArc2;
   lcNewArc=new_object(cpArc(agTree,*lcArc));
   if (findCycle(agTree,lcNewArc->key(),lcCycle)) delete_object(lcNewArc);
   lcCurrentArc2++;
  }
 }
}

// P r i m A l g o  Implementation //---------------------------------------------------------------
namespace public_area {
 //----------------------------------------------------------------------------------------------Run
 /*METHOD clPrimAlgo */ /* Solves the minimum spanning tree problem in a graph. */
 template <tdGraph>
 void clPrimAlgo<tuGraph>::run(clGraph<tuGraph> & agGraph,clGraph<tuGraph> & agTree) const {
  method_name("primAlgo::run");

  typedef clArc<tuGraph>                                     cpArc;
  typedef clNode<tuGraph>                                    cpNode;
  typedef typename cpNode::cpArcX::const_iterator            cpArcIterator;
  typedef typename clGraph<tuGraph>::cpNodeX::const_iterator cpNodeIterator;

  cpArc *        lcArc;
  cpArcIterator  lcCurrentArc;
  cpNodeIterator lcCurrentNode;
  cpArcIterator  lcLastArc;
  cpNodeIterator lcLastNode;
  cpNode *       lcNode;
  cpArc *        lcSelectedArc;

  clGraph<tuGraph> lcGraph(agGraph);
  tyReal           lcMin = 0;

  // Nodes Copy //
  agTree.clear();
  lcCurrentNode=agGraph.nodes().begin();
  lcLastNode=agGraph.nodes().end();

  while (lcCurrentNode!=lcLastNode) {
   new_object(cpNode(agTree,*((*lcCurrentNode).second)));
   lcCurrentNode++;
  }

  // Tree Construction //
  while (lcGraph.nodes().size()>1) {
   lcNode=(*(lcGraph.nodes().begin())).second;
   lcCurrentArc=lcNode->outgoingArcs().begin();
   lcLastArc=lcNode->outgoingArcs().end();
   lcSelectedArc=nil;

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

    if (lcSelectedArc==nil or lcArc->data().cost()<lcMin) {
     lcSelectedArc=lcArc;
     lcMin=lcArc->data().cost();
    }

    lcCurrentArc++;
   }

   lcCurrentArc=lcNode->incomingArcs().begin();
   lcLastArc=lcNode->incomingArcs().end();

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

    if (lcSelectedArc==nil or lcArc->data().cost()<lcMin) {
     lcSelectedArc=lcArc;
     lcMin=lcArc->data().cost();
    }

    lcCurrentArc++;
   }

   if (lcSelectedArc==nil) send_error(erGraphNotConnex);
   new_object(cpArc(agTree,agGraph.arc(lcSelectedArc->key())));
   lcGraph.mergeNodes(*(lcSelectedArc->targetNode()),*(lcSelectedArc->sourceNode()));
  }
 }
}

// S o l v e A l g o  Implementation //-------------------------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------------DefaultRun
 /*METHOD clSolveAlgo */
 /* Solves the minimum spanning tree problem in a graph using the default version of the algorithm
    (Kruskal's method). Static method. */
 template <tdGraph> inline void
 clSolveAlgo<tuGraph>::defaultRun(clGraph<tuGraph> & agGraph,clGraph<tuGraph> & agTree)
 { clKruskalAlgo<tuGraph>().run(agGraph,agTree); }
}

// 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 _ s p a n n i n g _ t r e e
//                                                                                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_spanning_tree.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define GRAPH_PROBLEM_DLL

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

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  graphProblemMinSpanningTree
#define private_area graphProblemMinSpanningTree_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Graph_problem/Min_spanning_tree");

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

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

// Constants & Variables //-------------------------------------------------------------------------
dynamic_constant(clString,goDataLocation);

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

    goDataLocation = new_object(clString(environment::dataLocation()+fileNameSeparator()
                     +"graph_problem"+fileNameSeparator()+"min_spanning_tree"));
   }

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

   delete_object(goDataLocation);
  }

  initializer_catch;
 }
}

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