//================================================================================================== // G r a p h _ p r o b l e m Interface // M a x _ f l o w // 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 maximum flow problem in graphs. */
// File Name //------------------------------------------------------------------------------------- #line __LINE__ "graph_problem/max_flow.hpp"
// Guardian //-------------------------------------------------------------------------------------- #ifndef guGraphProblemMaxFlow #define guGraphProblemMaxFlow
// Headers //--------------------------------------------------------------------------------------- #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 graphProblemMaxFlow #define private_area graphProblemMaxFlow_private
namespace public_area { /*NAMESPACE*/ using namespace graph; } namespace private_area { using namespace public_area; }
extern_module_name;
// Initialization //-------------------------------------------------------------------------------- #define iniGraphProblemMaxFlow has_initializer;
// Macrocommands //--------------------------------------------------------------------------------- /*ALIAS*/ #define tdGraph class prArcData,class prNodeData //
/*ALIAS*/ #define tuGraph prArcData,prNodeData //
// Types & Classes //------------------------------------------------------------------------------- namespace public_area { //-----------------------------------------------------------------------------------Variable Types /*TYPE*/ /* Arc of a graph with a maximum flow problem. */ typedef clArc<clFlowData,clNoData> clFlowArc;
/*TYPE*/ /* Graph with a maximum flow problem. */ typedef clGraph<clFlowData,clNoData> clFlowGraph;
/*TYPE*/ /* Node of a graph with a maximum flow problem. */ typedef clNode<clFlowData,clNoData> clFlowNode; //-----------------------------------------------------------------------------------Constant Types typedef const clFlowArc ctFlowArc; typedef const clFlowGraph ctFlowGraph; typedef const clFlowNode ctFlowNode; }
namespace private_area {}
// Functions Interface //--------------------------------------------------------------------------- namespace public_area { template <tdGraph> tyBoolean findIncreasingChain(clGraph<tuGraph> &,clNode<tuGraph> &, clNode<tuGraph> &, std_vector(clArc<tuGraph> *) &);
template <tdGraph> void findMaximumFlow(clGraph<tuGraph> &,clNode<tuGraph> &,clNode<tuGraph> &); template <tdGraph> void generateFlowGraph(clGraph<tuGraph> &,tyCardinal,tyCardinal,tyInteger);
template <tdGraph> tyReal totalIncomingFlow(const clNode<tuGraph> &); template <tdGraph> tyReal totalOutgoingFlow(const clNode<tuGraph> &); }
namespace private_area { testing_mode ( function void test(void); ) }
// Errors //---------------------------------------------------------------------------------------- namespace public_area {}
// Constants & Variables //------------------------------------------------------------------------- extern_dynamic_constant(private,clString,goDataLocation,?);
// Functions Inline //------------------------------------------------------------------------------ namespace public_area {} namespace private_area {}
// X X X Inline //--------------------------------------------------------------------------------- namespace {}
// Functions Implementation //---------------------------------------------------------------------- namespace public_area { //------------------------------------------------------------------------------FindIncreasingChain /*FUNCTION*/ /* Finds a chain that can increase the flow between two given nodes of a graph. */ template <tdGraph> tyBoolean findIncreasingChain(clGraph<tuGraph> & agGraph,clNode<tuGraph> & agSourceNode, clNode<tuGraph> & agTargetNode, std_vector(clArc<tuGraph> *) & agChain) { typedef clArc<tuGraph> cpArc; typedef clNode<tuGraph> cpNode; typedef std_vector(cpNode *) cpNodeS; typedef typename cpNode::cpArcX::const_iterator cpIterator;
tyMark lcMark = ++(agGraph.mark());
cpArc * lcArc; cpIterator lcCurrentArc; cpIterator lcLastArc; cpNode * lcNode1; cpNode * lcNode2; cpNodeS lcNodeS;
// Chain Searching // lcNodeS.push_back(&agSourceNode); agSourceNode.mark()=lcMark; agSourceNode.work()=nil;
while (lcNodeS.size()>0 and agTargetNode.mark()!=lcMark) { lcNode1=lcNodeS.back(); lcNodeS.pop_back();
// Outgoing Arcs // lcCurrentArc=lcNode1->outgoingArcs().begin(); lcLastArc=lcNode1->outgoingArcs().end();
while (lcCurrentArc!=lcLastArc) { lcArc=(*lcCurrentArc).second; lcNode2=lcArc->targetNode();
if (lcNode2->mark()!=lcMark and lcArc->data().flow()<lcArc->data().maximum()) { lcNode2->mark()=lcMark; lcNodeS.push_back(lcNode2); lcNode2->work()=lcArc; }
lcCurrentArc++; }
// Incoming Arcs // lcCurrentArc=lcNode1->incomingArcs().begin(); lcLastArc=lcNode1->incomingArcs().end();
while (lcCurrentArc!=lcLastArc) { lcArc=(*lcCurrentArc).second; lcNode2=lcArc->sourceNode();
if (lcNode2->mark()!=lcMark and lcArc->data().flow()>0.0) { lcNode2->mark()=lcMark; lcNodeS.push_back(lcNode2); lcNode2->work()=lcArc; }
lcCurrentArc++; } }
// Chain Construction // agChain.erase(agChain.begin(),agChain.end());
if (agTargetNode.mark()==lcMark) { lcNode1=&agTargetNode; lcArc=static_cast<cpArc *>(lcNode1->work());
while (lcArc!=nil) { agChain.push_back(lcArc);
if (lcArc->sourceNode()==lcNode1) lcNode1=lcArc->targetNode(); else lcNode1=lcArc->sourceNode();
lcArc=static_cast<cpArc *>(lcNode1->work()); }
return (true); } else return (false); } //----------------------------------------------------------------------------------FindMaximumFlow /*FUNCTION*/ /* Finds the maximum flow between two nodes of a graph using Ford and Fulkerson's method. */ template <tdGraph> void findMaximumFlow(clGraph<tuGraph> & agGraph,clNode<tuGraph> & agSourceNode, clNode<tuGraph> & agTargetNode) { typedef clArc<tuGraph> cpArc; typedef std_vector(cpArc *) cpChain; typedef typename clGraph<tuGraph>::cpArcX::const_iterator cpIterator1; typedef typename cpChain::const_iterator cpIterator2; typedef clNode<tuGraph> cpNode;
cpArc * lcArc; cpChain lcChain; cpIterator1 lcCurrentArc1; cpIterator2 lcCurrentArc2; tyReal lcIncrease; cpIterator1 lcLastArc1; cpIterator2 lcLastArc2; tyReal lcMin; cpNode * lcNode;
// Null Flow // lcCurrentArc1=agGraph.arcs().begin(); lcLastArc1=agGraph.arcs().end();
while (lcCurrentArc1!=lcLastArc1) { (*lcCurrentArc1).second->data().flow()=0.0; lcCurrentArc1++; }
// Flow Increasing // while (findIncreasingChain(agGraph,agSourceNode,agTargetNode,lcChain)) {
// Minimum Increase Value Search // lcCurrentArc2=lcChain.begin(); lcLastArc2=lcChain.end(); lcNode=&agTargetNode; lcMin=realMax();
while (lcCurrentArc2!=lcLastArc2) { lcArc=*lcCurrentArc2;
if (lcArc->sourceNode()==lcNode) { lcIncrease=lcArc->data().flow(); lcNode=lcArc->targetNode(); } else { lcIncrease=lcArc->data().maximum()-lcArc->data().flow(); lcNode=lcArc->sourceNode(); }
if (lcIncrease<lcMin) lcMin=lcIncrease; lcCurrentArc2++; }
// Flow Increasing // lcCurrentArc2=lcChain.begin(); lcLastArc2=lcChain.end(); lcNode=&agTargetNode;
while (lcCurrentArc2!=lcLastArc2) { lcArc=*lcCurrentArc2;
if (lcArc->sourceNode()==lcNode) { lcArc->data().flow()-=lcMin; lcNode=lcArc->targetNode(); } else { lcArc->data().flow()+=lcMin; lcNode=lcArc->sourceNode(); }
lcCurrentArc2++; } }
agGraph.solved()=true; } //--------------------------------------------------------------------------------GenerateFlowGraph /*FUNCTION*/ /* Generates randomly a maximum flow problem with a given flow capacity scale, in a graph with given numbers of arcs and nodes (the unique source and target nodes, as well as the arcs that link them to the graph, are not counted, i.e. the numbers of arcs and nodes are a little more than given). */ template <tdGraph> void generateFlowGraph(clGraph<tuGraph> & agGraph,tyCardinal agNbNode,tyCardinal agNbArc, tyInteger agCapacityScale) { typedef clNode<tuGraph> cpNode; typedef typename clGraph<tuGraph>::cpArcX::const_iterator cpArcIterator1; typedef typename cpNode::cpArcX::const_iterator cpArcIterator2;
clArc<tuGraph> * lcArc; cpArcIterator1 lcCurrentArc1; cpArcIterator2 lcCurrentArc2; cpArcIterator1 lcLastArc1; cpArcIterator2 lcLastArc2; cpNode * lcNode; tyNodeKey lcNodeKey; std_vector(cpNode *) lcNodeS;
// Graph Generation // generateConnexGraph(agGraph,agNbNode,agNbArc,true); lcCurrentArc1=agGraph.arcs().begin(); lcLastArc1=agGraph.arcs().end();
while (lcCurrentArc1!=lcLastArc1) { lcArc=(*lcCurrentArc1).second; lcArc->data().maximum()=randomCardinal(agCapacityScale); lcCurrentArc1++; }
// Source Node Creation // lcNodeKey=addSourceNode(agGraph,prArcData(),prNodeData()); lcNode=&(agGraph.node(lcNodeKey)); lcCurrentArc2=lcNode->outgoingArcs().begin(); lcLastArc2=lcNode->outgoingArcs().end();
while (lcCurrentArc2!=lcLastArc2) { lcArc=(*lcCurrentArc2).second; lcArc->data().maximum()=randomCardinal(agCapacityScale); lcCurrentArc2++; }
// Target Node Creation // lcNodeKey=addTargetNode(agGraph,prArcData(),prNodeData()); lcNode=&(agGraph.node(lcNodeKey)); lcCurrentArc2=lcNode->incomingArcs().begin(); lcLastArc2=lcNode->incomingArcs().end();
while (lcCurrentArc2!=lcLastArc2) { lcArc=(*lcCurrentArc2).second; lcArc->data().maximum()=randomCardinal(agCapacityScale); lcCurrentArc2++; } } //--------------------------------------------------------------------------------TotalIncomingFlow /*FUNCTION*/ /* Returns the amount of flow that enters a node. */ template <tdGraph> tyReal totalIncomingFlow(const clNode<tuGraph> & agNode) { typedef typename clGraph<tuGraph>::cpArcX::const_iterator cpIterator;
cpIterator lcCurrentArc = agNode.incomingArcs().begin(); tyReal lcFlow = 0.0; cpIterator lcLastArc = agNode.incomingArcs().end();
while (lcCurrentArc!=lcLastArc) { lcFlow+=(*lcCurrentArc).second->data().flow(); lcCurrentArc++; }
return (lcFlow); } //--------------------------------------------------------------------------------TotalOutgoingFlow /*FUNCTION*/ /* Returns the amount of flow that leaves a node. */ template <tdGraph> tyReal totalOutgoingFlow(const clNode<tuGraph> & agNode) { typedef typename clGraph<tuGraph>::cpArcX::const_iterator cpIterator;
cpIterator lcCurrentArc = agNode.outgoingArcs().begin(); tyReal lcFlow = 0.0; cpIterator lcLastArc = agNode.outgoingArcs().end();
while (lcCurrentArc!=lcLastArc) { lcFlow+=(*lcCurrentArc).second->data().flow(); lcCurrentArc++; }
return (lcFlow); } }
namespace private_area {}
// 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 a x _ f l o w // 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/max_flow.cpp"
// DLL Belonging //--------------------------------------------------------------------------------- #define GRAPH_PROBLEM_DLL
// Headers //--------------------------------------------------------------------------------------- #include <bpp/graph_problem/max_flow.hpp> /*INTERFACE*/
namespace bpp {
// Namespaces //------------------------------------------------------------------------------------ #define public_area graphProblemMaxFlow #define private_area graphProblemMaxFlow_private #define dll_export DLL_EXPORT
namespace public_area {} namespace private_area {}
static_module_name("Graph_problem/Max_flow");
// Initialization //-------------------------------------------------------------------------------- #undef iniGraphProblemMaxFlow 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 {}
// 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()+"max_flow")); }
initializer_catch; } } //---------------------------------------------------------------------------------------------Stop property void clInitializer::stop(void) { try { environment::informTermination(goModuleName);
delete_object(goDataLocation); }
initializer_catch; } }
// End //------------------------------------------------------------------------------------------- } |
|