提交scripts
This commit is contained in:
1 parent
82caf72036
commit
07dabbd186
224 files changed
+130146
No files matched your search
@@ -0,0 +1,977 @@
|
||||
/*
|
||||
#########################################################
|
||||
# #
|
||||
# IBFSGraph - Software for solving #
|
||||
# Maximum s-t Flow / Minimum s-t Cut #
|
||||
# using the IBFS algorithm #
|
||||
# #
|
||||
# http://www.cs.tau.ac.il/~sagihed/ibfs/ #
|
||||
# #
|
||||
# Haim Kaplan (haimk@cs.tau.ac.il) #
|
||||
# Sagi Hed (sagihed@post.tau.ac.il) #
|
||||
# #
|
||||
#########################################################
|
||||
|
||||
This software implements the IBFS (Incremental Breadth First Search) maximum flow algorithm from
|
||||
"Maximum flows by incremental breadth-first search"
|
||||
Andrew V. Goldberg, Sagi Hed, Haim Kaplan, Robert E. Tarjan, and Renato F. Werneck.
|
||||
In Proceedings of the 19th European conference on Algorithms, ESA'11, pages 457-468.
|
||||
ISBN 978-3-642-23718-8
|
||||
2011
|
||||
|
||||
Copyright Haim Kaplan (haimk@cs.tau.ac.il) and Sagi Hed (sagihed@post.tau.ac.il)
|
||||
|
||||
###########
|
||||
# LICENSE #
|
||||
###########
|
||||
This software can be used for research purposes only.
|
||||
If you use this software for research purposes, you should cite the aforementioned paper
|
||||
in any resulting publication and appropriately credit it.
|
||||
|
||||
If you require another license, please contact the above.
|
||||
|
||||
*/
|
||||
|
||||
#include "Common.h"
|
||||
#include "IBFS.h"
|
||||
|
||||
using namespace IBFS;
|
||||
|
||||
|
||||
//
|
||||
// Orphan handling
|
||||
//
|
||||
#define ADD_ORPHAN_BACK(n) \
|
||||
if (orphanFirst != IB_ORPHANS_END) \
|
||||
{ \
|
||||
orphanLast = (orphanLast->nextPtr = (n)); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
orphanLast = (orphanFirst = (n)); \
|
||||
} \
|
||||
(n)->nextPtr = IB_ORPHANS_END
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define ADD_ORPHAN_FRONT(n) \
|
||||
if (orphanFirst == IB_ORPHANS_END) \
|
||||
{ \
|
||||
(n)->nextPtr = IB_ORPHANS_END; \
|
||||
orphanLast = (orphanFirst = (n)); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
(n)->nextPtr = orphanFirst; \
|
||||
orphanFirst = (n); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
IBFSGraph::IBFSGraph()
|
||||
{
|
||||
numNodes = 0;
|
||||
uniqOrphansS = uniqOrphansT = 0;
|
||||
augTimestamp = 0;
|
||||
verbose = IBTEST;
|
||||
compactSlowInitMode = false;
|
||||
arcs = arcEnd = NULL;
|
||||
nodes = nodeEnd = NULL;
|
||||
topLevelS = topLevelT = 0;
|
||||
flow = 0;
|
||||
orphanFirst = orphanLast = NULL;
|
||||
memArcs = NULL;
|
||||
tmpArcs = NULL;
|
||||
tmpEdges = tmpEdgeLast = NULL;
|
||||
}
|
||||
|
||||
|
||||
IBFSGraph::~IBFSGraph()
|
||||
{
|
||||
active0.release();
|
||||
activeS1.release();
|
||||
activeT1.release();
|
||||
orphanBuckets.release();
|
||||
delete[] memArcs;
|
||||
delete[] nodes;
|
||||
}
|
||||
|
||||
void IBFSGraph::initGraph()
|
||||
{
|
||||
if (compactSlowInitMode) {
|
||||
initGraphCompact();
|
||||
} else {
|
||||
initGraphFast();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IBFSGraph::initSize(int numNodes, int numEdges)
|
||||
{
|
||||
// allocate nodes
|
||||
if (verbose) {
|
||||
fprintf(stdout, "c allocating nodes... \t [%zu]\n", sizeof(Node)*(numNodes+1));
|
||||
fflush(stdout);
|
||||
}
|
||||
this->numNodes = numNodes;
|
||||
nodes = new Node[numNodes+1];
|
||||
memset(nodes, 0, sizeof(Node)*(numNodes+1));
|
||||
nodeEnd = nodes+numNodes;
|
||||
active0.init(numNodes);
|
||||
activeS1.init(numNodes);
|
||||
activeT1.init(numNodes);
|
||||
orphanBuckets.init(nodes, numNodes);
|
||||
|
||||
// allocate arcs
|
||||
size_t arcMemsize = sizeof(TmpArc)*(numEdges*2) + sizeof(TmpEdge)*numEdges;
|
||||
if (arcMemsize < sizeof(Arc)*(numEdges*2)) {
|
||||
arcMemsize = sizeof(Arc)*(numEdges*2);
|
||||
}
|
||||
if (verbose) {
|
||||
fprintf(stdout, "c allocating arcs... \t [%zu]\n", arcMemsize);
|
||||
fflush(stdout);
|
||||
}
|
||||
memArcs = new char[arcMemsize];
|
||||
memset(memArcs, 0, sizeof(char)*arcMemsize);
|
||||
tmpEdges = (TmpEdge*)(memArcs);
|
||||
tmpEdgeLast = tmpEdges; // will advance as edges are added
|
||||
tmpArcs = (TmpArc*)(memArcs +sizeof(TmpEdge)*numEdges);
|
||||
arcs = (Arc*)memArcs;
|
||||
arcEnd = arcs + numEdges*2;
|
||||
|
||||
// init members
|
||||
flow = 0;
|
||||
|
||||
if (verbose) {
|
||||
fprintf(stdout, "c sizeof(ptr) = %zu bytes\n", sizeof(Node*));
|
||||
fprintf(stdout, "c sizeof(node) = %zu bytes\n", sizeof(Node));
|
||||
fprintf(stdout, "c sizeof(arc) = %zu bytes\n", sizeof(Arc));
|
||||
fprintf(stdout, "c #nodes = %zu \n", nodeEnd-nodes);
|
||||
fprintf(stdout, "c #arcs = %zu \n", (arcEnd-arcs) + (nodeEnd-nodes));
|
||||
fprintf(stdout, "c #grid_arcs = %zu \n", arcEnd-arcs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IBFSGraph::initGraphFast()
|
||||
{
|
||||
Node *x;
|
||||
Arc *a;
|
||||
TmpArc *ta, *taEnd;
|
||||
TmpEdge *te;
|
||||
|
||||
// tmpEdges: edges read
|
||||
// node.label: out degree
|
||||
|
||||
// calculate start arc offsets every node
|
||||
nodes->firstArc = (Arc*)(tmpArcs);
|
||||
for (x=nodes; x != nodeEnd; x++) {
|
||||
(x+1)->firstArc = (Arc*)(((TmpArc*)(x->firstArc)) + x->label);
|
||||
x->label = (int)(((TmpArc*)(x->firstArc))-tmpArcs);
|
||||
}
|
||||
nodeEnd->label = (int)(arcEnd-arcs);
|
||||
|
||||
// tmpEdges: edges read
|
||||
// node.label: index into arcs array of first out arc
|
||||
// node.firstArc-tmpArcs: index into arcs array of next out arc to be allocated
|
||||
// (initially the first out arc)
|
||||
|
||||
// copy to temp arcs memory
|
||||
if (verbose) {
|
||||
IBDEBUG("c initFast copy1");
|
||||
}
|
||||
for (te=tmpEdges; te != tmpEdgeLast; te++) {
|
||||
ta = (TmpArc*)(te->tail->firstArc);
|
||||
ta->cap = te->cap;
|
||||
ta->rev = (TmpArc*)(te->head->firstArc);
|
||||
|
||||
ta = (TmpArc*)(te->head->firstArc);
|
||||
ta->cap = te->revCap;
|
||||
ta->rev = (TmpArc*)(te->tail->firstArc);
|
||||
|
||||
te->tail->firstArc = (Arc*)(((TmpArc*)(te->tail->firstArc))+1);
|
||||
te->head->firstArc = (Arc*)(((TmpArc*)(te->head->firstArc))+1);
|
||||
}
|
||||
|
||||
// tmpEdges: edges read
|
||||
// tmpArcs: arcs with reverse pointer but no node id
|
||||
// node.label: index into arcs array of first out arc
|
||||
// node.firstArc-tmpArcs: index into arcs array of last allocated out arc
|
||||
|
||||
// copy to permanent arcs array, but saving tail instead of head
|
||||
if (verbose) {
|
||||
IBDEBUG("c initFast copy2");
|
||||
}
|
||||
a = arcs;
|
||||
x = nodes;
|
||||
taEnd = (tmpArcs+(arcEnd-arcs));
|
||||
for (ta=tmpArcs; ta != taEnd; ta++) {
|
||||
while (x->label <= (ta-tmpArcs)) x++;
|
||||
a->head = (x-1);
|
||||
a->rCap = ta->cap;
|
||||
a->rev = arcs + (ta->rev-tmpArcs);
|
||||
a++;
|
||||
}
|
||||
|
||||
// tmpEdges: overwritten
|
||||
// tmpArcs: overwritten
|
||||
// arcs: arcs array
|
||||
// node.label: index into arcs array of first out arc
|
||||
// node.firstArc-tmpArcs: index into arcs array of last allocated out arc
|
||||
// arc.head = tail of arc
|
||||
|
||||
// swap the head and tail pointers and set isRevResidual
|
||||
if (verbose) {
|
||||
IBDEBUG("c initFast copy3");
|
||||
}
|
||||
for (a=arcs; a != arcEnd; a++) {
|
||||
if (a->rev <= a) continue;
|
||||
x = a->head;
|
||||
a->head = a->rev->head;
|
||||
a->rev->head = x;
|
||||
a->isRevResidual = (a->rev->rCap != 0);
|
||||
a->rev->isRevResidual = (a->rCap != 0);
|
||||
}
|
||||
|
||||
// set firstArc pointers in nodes array
|
||||
if (verbose) {
|
||||
IBDEBUG("c initFast nodes");
|
||||
}
|
||||
for (x=nodes; x <= nodeEnd; x++) {
|
||||
x->firstArc = (arcs + x->label);
|
||||
if (x->excess == 0) {
|
||||
x->label = numNodes;
|
||||
continue;
|
||||
}
|
||||
if (x->excess > 0) {
|
||||
x->label = 1;
|
||||
activeS1.add(x);
|
||||
} else {
|
||||
x->label = -1;
|
||||
activeT1.add(x);
|
||||
}
|
||||
}
|
||||
|
||||
// check consistency
|
||||
if (IBTEST) {
|
||||
IBDEBUG("c initFast test");
|
||||
for (x=nodes; x != nodeEnd; x++) {
|
||||
if ((x+1)->firstArc < x->firstArc) {
|
||||
fprintf(stderr, "INIT CONSISTENCY: arc pointers descending");
|
||||
exit(1);
|
||||
}
|
||||
for (a=x->firstArc; a !=(x+1)->firstArc; a++) {
|
||||
if (a->rev->head != x) {
|
||||
fprintf(stderr, "INIT CONSISTENCY: arc head pointer inconsistent");
|
||||
exit(1);
|
||||
}
|
||||
if (a->rev->rev != a) {
|
||||
fprintf(stderr, "INIT CONSISTENCY: arc reverse pointer inconsistent");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IBFSGraph::initGraphCompact()
|
||||
{
|
||||
Arc *a, aTmp;
|
||||
Node *x, *y;
|
||||
|
||||
// calculate start arc offsets every node
|
||||
for (x=(nodes+1); x != nodeEnd; x++) {
|
||||
x->label += (x-1)->label;
|
||||
}
|
||||
for (x=nodeEnd; x>nodes; x--) {
|
||||
x->label = (x-1)->label;
|
||||
x->firstArc = arcs + x->label;
|
||||
}
|
||||
nodes->label = 0;
|
||||
nodes->firstArc = arcs;
|
||||
|
||||
// swap arcs
|
||||
for (x=nodes; x != nodeEnd; x++)
|
||||
{
|
||||
for (; x->firstArc != (arcs+((x+1)->label)); x->firstArc++)
|
||||
{
|
||||
for (y = x->firstArc->rev->head; y != x; y = x->firstArc->rev->head)
|
||||
{
|
||||
// get and advance last arc fwd in proper node
|
||||
a = y->firstArc;
|
||||
y->firstArc++;
|
||||
|
||||
// prepare sister pointers
|
||||
if (a->rev == x->firstArc)
|
||||
{
|
||||
x->firstArc->rev = x->firstArc;
|
||||
a->rev = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
a->rev->rev = x->firstArc;
|
||||
x->firstArc->rev->rev = a;
|
||||
}
|
||||
|
||||
// swap
|
||||
aTmp = (*(x->firstArc));
|
||||
(*(x->firstArc)) = (*a);
|
||||
(*a) = aTmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// reset first arc pointers
|
||||
// and sister_rCap
|
||||
for (x=nodes; x <= nodeEnd; x++)
|
||||
{
|
||||
if (x != nodeEnd) {
|
||||
x->firstArc = arcs + x->label;
|
||||
x->label = 0;
|
||||
}
|
||||
if (x != nodes) {
|
||||
for (a=(x-1)->firstArc; a != x->firstArc; a++)
|
||||
{
|
||||
if (a->rev->rCap == 0) {
|
||||
a->isRevResidual = 0;
|
||||
} else {
|
||||
a->isRevResidual = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <bool sTree>
|
||||
void IBFSGraph::augmentTree(Node *x, EdgeCap bottleneck)
|
||||
{
|
||||
Node *y;
|
||||
Arc *a;
|
||||
|
||||
for (; ; x=a->head)
|
||||
{
|
||||
if (x->excess) break;
|
||||
a = x->parent;
|
||||
if (sTree) {
|
||||
a->rCap += bottleneck;
|
||||
a->rev->isRevResidual = 1;
|
||||
a->rev->rCap -= bottleneck;
|
||||
} else {
|
||||
a->rev->rCap += bottleneck;
|
||||
a->isRevResidual = 1;
|
||||
a->rCap -= bottleneck;
|
||||
}
|
||||
|
||||
// saturated?
|
||||
if ((sTree ? (a->rev->rCap) : (a->rCap)) == 0)
|
||||
{
|
||||
if (sTree) a->isRevResidual = 0;
|
||||
else a->rev->isRevResidual = 0;
|
||||
y=x->parent->head->firstSon;
|
||||
if (y == x) {
|
||||
x->parent->head->firstSon = x->nextPtr;
|
||||
} else {
|
||||
for (; y->nextPtr != x; y = y->nextPtr);
|
||||
y->nextPtr = x->nextPtr;
|
||||
}
|
||||
ADD_ORPHAN_FRONT(x);
|
||||
}
|
||||
}
|
||||
x->excess += (sTree ? -bottleneck : bottleneck);
|
||||
if (x->excess == 0) {
|
||||
ADD_ORPHAN_FRONT(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IBFSGraph::augment(Arc *bridge)
|
||||
{
|
||||
Node *x;
|
||||
Arc *a;
|
||||
EdgeCap bottleneck;
|
||||
Real pushesBefore;
|
||||
|
||||
// stats
|
||||
if (IBSTATS) pushesBefore=stats.getPushes();
|
||||
stats.incAugs();
|
||||
stats.incPushes();
|
||||
|
||||
// bottleneck in S
|
||||
bottleneck = bridge->rCap;
|
||||
for (x=bridge->rev->head; ; x=a->head)
|
||||
{
|
||||
stats.incPushes();
|
||||
if (x->excess) break;
|
||||
a = x->parent;
|
||||
if (bottleneck > a->rev->rCap) {
|
||||
bottleneck = a->rev->rCap;
|
||||
}
|
||||
}
|
||||
if (bottleneck > x->excess) {
|
||||
bottleneck = x->excess;
|
||||
}
|
||||
|
||||
// bottleneck in T
|
||||
for (x=bridge->head; ; x=a->head)
|
||||
{
|
||||
stats.incPushes();
|
||||
if (x->excess) break;
|
||||
a = x->parent;
|
||||
if (bottleneck > a->rCap) {
|
||||
bottleneck = a->rCap;
|
||||
}
|
||||
}
|
||||
if (bottleneck > (-x->excess)) {
|
||||
bottleneck = (-x->excess);
|
||||
}
|
||||
|
||||
// stats
|
||||
if (IBSTATS) {
|
||||
Real augLen = stats.getPushes() - pushesBefore;
|
||||
stats.addAugLen(augLen);
|
||||
}
|
||||
|
||||
// augment connecting arc
|
||||
bridge->rev->rCap += bottleneck;
|
||||
bridge->isRevResidual = 1;
|
||||
bridge->rCap -= bottleneck;
|
||||
if (bridge->rCap == 0) {
|
||||
bridge->rev->isRevResidual = 0;
|
||||
}
|
||||
|
||||
// augment T
|
||||
augTimestamp++;
|
||||
augmentTree<false>(bridge->head, bottleneck);
|
||||
adoption<false>();
|
||||
|
||||
// augment S
|
||||
augTimestamp++;
|
||||
augmentTree<true>(bridge->rev->head, bottleneck);
|
||||
adoption<true>();
|
||||
|
||||
flow += bottleneck;
|
||||
}
|
||||
|
||||
|
||||
template <bool sTree>
|
||||
void IBFSGraph::adoption()
|
||||
{
|
||||
Node *x, *y, *z;
|
||||
Arc *a, *aEnd;
|
||||
bool threePass;
|
||||
int minLabel, numOrphans, numOrphansUniq;
|
||||
|
||||
threePass=false;
|
||||
numOrphans=0;
|
||||
numOrphansUniq=0;
|
||||
while (orphanFirst != IB_ORPHANS_END)
|
||||
{
|
||||
x = orphanFirst;
|
||||
orphanFirst = x->nextPtr;
|
||||
//x->nextOrphan = NULL;
|
||||
testNode(x);
|
||||
stats.incOrphans();
|
||||
numOrphans++;
|
||||
if (x->lastAugTimestamp != augTimestamp) {
|
||||
x->lastAugTimestamp = augTimestamp;
|
||||
if (sTree) uniqOrphansS++;
|
||||
else uniqOrphansT++;
|
||||
numOrphansUniq++;
|
||||
}
|
||||
if (numOrphans >= 3*numOrphansUniq) {
|
||||
// switch to 3pass
|
||||
threePass = true;
|
||||
}
|
||||
|
||||
// check for same level connection
|
||||
if (x->isParentCurr) {
|
||||
a = x->parent;
|
||||
} else {
|
||||
a = x->firstArc;
|
||||
x->isParentCurr = 1;
|
||||
}
|
||||
x->parent = NULL;
|
||||
aEnd = (x+1)->firstArc;
|
||||
if (x->label != (sTree ? 1 : -1))
|
||||
{
|
||||
minLabel = x->label - (sTree ? 1 : -1);
|
||||
for (; a != aEnd; a++)
|
||||
{
|
||||
stats.incOrphanArcs1();
|
||||
y = a->head;
|
||||
if ((sTree ? a->isRevResidual : a->rCap) != 0 &&
|
||||
y->label == minLabel)
|
||||
{
|
||||
x->parent = a;
|
||||
x->nextPtr = y->firstSon;
|
||||
y->firstSon = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (x->parent != NULL) continue;
|
||||
|
||||
// give up on same level - relabel it!
|
||||
// (1) create orphan sons
|
||||
for (y=x->firstSon; y != NULL; y=z)
|
||||
{
|
||||
stats.incOrphanArcs3();
|
||||
z=y->nextPtr;
|
||||
ADD_ORPHAN_BACK(y);
|
||||
}
|
||||
x->firstSon = NULL;
|
||||
|
||||
// on the top level there is no need to relabel
|
||||
if (x->label == (sTree ? topLevelS : -topLevelT)) {
|
||||
x->label = numNodes;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 3pass relabeling: move to buckets structure
|
||||
if (threePass) {
|
||||
x->label += (sTree ? 1 : -1);
|
||||
orphanBuckets.add<sTree>(x);
|
||||
continue;
|
||||
}
|
||||
|
||||
// (2) relabel: find the lowest level parent
|
||||
minLabel = (sTree ? topLevelS : -topLevelT);
|
||||
if (x->label != minLabel) for (a=x->firstArc; a != aEnd; a++)
|
||||
{
|
||||
stats.incOrphanArcs2();
|
||||
y = a->head;
|
||||
if ((sTree ? a->isRevResidual : a->rCap) &&
|
||||
// y->label != numNodes ---> holds implicitly
|
||||
(sTree ? (y->label > 0) : (y->label < 0)) &&
|
||||
(sTree ? (y->label < minLabel) : (y->label > minLabel)))
|
||||
{
|
||||
minLabel = y->label;
|
||||
x->parent = a;
|
||||
if (minLabel == x->label) break;
|
||||
}
|
||||
}
|
||||
|
||||
// (3) relabel onto new parent
|
||||
if (x->parent != NULL) {
|
||||
x->label = minLabel + (sTree ? 1 : -1);
|
||||
x->nextPtr = x->parent->head->firstSon;
|
||||
x->parent->head->firstSon = x;
|
||||
// add to active list of the next growth phase
|
||||
if (sTree) {
|
||||
if (x->label == topLevelS) activeS1.add(x);
|
||||
} else {
|
||||
if (x->label == -topLevelT) activeT1.add(x);
|
||||
}
|
||||
} else {
|
||||
x->label = numNodes;
|
||||
}
|
||||
}
|
||||
|
||||
if (threePass) {
|
||||
adoption3Pass<sTree>();
|
||||
}
|
||||
}
|
||||
|
||||
template <bool sTree>
|
||||
void IBFSGraph::adoption3Pass()
|
||||
{
|
||||
Arc *a, *aEnd;
|
||||
Node *x, *y;
|
||||
int minLabel, destLabel;
|
||||
|
||||
for (int level=2; level <= orphanBuckets.maxBucket; level++)
|
||||
{
|
||||
while ((x = orphanBuckets.popFront(level)) != NULL)
|
||||
{
|
||||
testNode(x);
|
||||
aEnd = (x+1)->firstArc;
|
||||
|
||||
// pass 2: find lowest level parent
|
||||
if (x->parent == NULL) {
|
||||
minLabel = (sTree ? topLevelS : -topLevelT);
|
||||
destLabel = x->label - (sTree ? 1 : -1);
|
||||
for (a=x->firstArc; a != aEnd; a++) {
|
||||
y = a->head;
|
||||
if ((sTree ? a->isRevResidual : a->rCap) &&
|
||||
(y->excess || y->parent != NULL) &&
|
||||
//!y->isOrphan() &&
|
||||
(sTree ? (y->label > 0) : (y->label < 0)) &&
|
||||
(sTree ? (y->label < minLabel) : (y->label > minLabel)))
|
||||
{
|
||||
x->parent = a;
|
||||
if ((minLabel = y->label) == destLabel) break;
|
||||
}
|
||||
}
|
||||
if (x->parent == NULL) {
|
||||
x->label = numNodes;
|
||||
continue;
|
||||
}
|
||||
x->label = minLabel + (sTree ? 1 : -1);
|
||||
if (x->label != (sTree ? level : -level)) {
|
||||
orphanBuckets.add<sTree>(x);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// pass 3: lower potential sons and/or find first parent
|
||||
if (x->label != (sTree ? topLevelS : -topLevelT))
|
||||
{
|
||||
minLabel = x->label + (sTree ? 1 : -1);
|
||||
for (a=x->firstArc; a != aEnd; a++) {
|
||||
y = a->head;
|
||||
|
||||
// lower potential sons
|
||||
if ((sTree ? a->rCap : a->isRevResidual) &&
|
||||
((!sTree && y->label == numNodes) ||
|
||||
// the above implicitly holds by condition below when sTree=true
|
||||
(sTree ? (minLabel < y->label) : (minLabel > y->label))))
|
||||
{
|
||||
if (y->label != numNodes) orphanBuckets.remove<sTree>(y);
|
||||
y->label = minLabel;
|
||||
y->parent = a->rev;
|
||||
orphanBuckets.add<sTree>(y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// relabel onto new parent
|
||||
x->nextPtr = x->parent->head->firstSon;
|
||||
x->parent->head->firstSon = x;
|
||||
x->isParentCurr = 0;
|
||||
// add to active list of the next growth phase
|
||||
if (sTree) {
|
||||
if (x->label == topLevelS) activeS1.add(x);
|
||||
} else {
|
||||
if (x->label == -topLevelT) activeT1.add(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
orphanBuckets.maxBucket = 0;
|
||||
}
|
||||
|
||||
|
||||
template <bool dirS>
|
||||
void IBFSGraph::growth()
|
||||
{
|
||||
Node *x, *y;
|
||||
Arc *a, *aEnd;
|
||||
|
||||
for (Node **active=active0.list; active != (active0.list + active0.len); active++)
|
||||
{
|
||||
// get active node
|
||||
x = (*active);
|
||||
testNode(x);
|
||||
|
||||
// node no longer at level
|
||||
if (x->label != (dirS ? (topLevelS-1): -(topLevelT-1))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// grow or augment
|
||||
if (dirS) stats.incGrowthS();
|
||||
else stats.incGrowthT();
|
||||
aEnd = (x+1)->firstArc;
|
||||
for (a=x->firstArc; a != aEnd; a++)
|
||||
{
|
||||
stats.incGrowthArcs();
|
||||
if ((dirS ? a->rCap : a->isRevResidual) == 0) continue;
|
||||
y = a->head;
|
||||
if (y->label == numNodes)
|
||||
{
|
||||
// grow node
|
||||
testNode(y);
|
||||
y->isParentCurr = 0;
|
||||
y->label = x->label + (dirS ? 1 : -1);
|
||||
y->parent = a->rev;
|
||||
y->nextPtr = x->firstSon;
|
||||
x->firstSon = y;
|
||||
if (dirS) activeS1.add(y);
|
||||
else activeT1.add(y);
|
||||
}
|
||||
else if (dirS ? (y->label < 0) : (y->label > 0))
|
||||
{
|
||||
// augment
|
||||
augment(dirS ? a : (a->rev));
|
||||
if (x->label != (dirS ? (topLevelS-1) : -(topLevelT-1))) {
|
||||
break;
|
||||
}
|
||||
if (dirS ? (a->rCap) : (a->isRevResidual)) a--;
|
||||
}
|
||||
}
|
||||
}
|
||||
active0.clear();
|
||||
}
|
||||
|
||||
|
||||
void IBFSGraph::testTree()
|
||||
{
|
||||
Node *x;
|
||||
Arc *a;
|
||||
|
||||
for (x=nodes; x != nodeEnd; x++) {
|
||||
if (x->label != numNodes && (x->label > topLevelS || x->label < -topLevelT)) {
|
||||
IBDEBUG("ILLEGAL LABEL!");
|
||||
testExit();
|
||||
}
|
||||
if (x->parent == NULL) continue;
|
||||
bool sTree = (x->label > 0);
|
||||
if (x->label == (sTree ? topLevelS : -topLevelT)) {
|
||||
continue;
|
||||
}
|
||||
for (a=x->firstArc; a != (x+1)->firstArc; a++) {
|
||||
if (x->isParentCurr &&
|
||||
(sTree ? a->isRevResidual : a->rCap) &&
|
||||
(sTree ? (a->head->label > 0) : (a->head->label < 0)) &&
|
||||
a->head->label == (sTree ? (x->label-1) : (x->label+1)) &&
|
||||
a < x->parent) {
|
||||
IBDEBUG("ILLEGAL CURRENT ARC!");
|
||||
testExit();
|
||||
}
|
||||
if (!(sTree ? a->rCap : a->isRevResidual)) continue;
|
||||
if (a->head->parent == NULL) {
|
||||
IBDEBUG("CROSS OUT NODE!");
|
||||
testExit();
|
||||
}
|
||||
if (sTree ? (a->head->label < 0) : (a->head->label > 0)) {
|
||||
IBDEBUG("CROSS NODE!");
|
||||
testExit();
|
||||
}
|
||||
if (sTree ? (a->head->label > (x->label+1)) : (a->head->label < (x->label-1))) {
|
||||
IBDEBUG("EXTENDED ARC!");
|
||||
testExit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EdgeCap IBFSGraph::computeMaxFlow()
|
||||
{
|
||||
// init
|
||||
orphanFirst = IB_ORPHANS_END;
|
||||
topLevelS = topLevelT = 1;
|
||||
bool dirS = true;
|
||||
ActiveList::swapLists(&active0, &activeS1);
|
||||
|
||||
//
|
||||
// IBFS
|
||||
//
|
||||
while (true)
|
||||
{
|
||||
// BFS level
|
||||
if (dirS) topLevelS++;
|
||||
else topLevelT++;
|
||||
if (dirS) growth<true>();
|
||||
else growth<false>();
|
||||
if (IBTEST) {
|
||||
testTree();
|
||||
fprintf(stdout, "dirS=%d aug=%d S %d / T %d\n", dirS, augTimestamp, uniqOrphansS, uniqOrphansT);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
// switch to next level
|
||||
if (activeS1.len == 0 || activeT1.len == 0) {
|
||||
break;
|
||||
}
|
||||
if ((!IB_ALTERNATE_SMART && dirS) ||
|
||||
(IB_ALTERNATE_SMART && uniqOrphansT == uniqOrphansS && dirS) ||
|
||||
(IB_ALTERNATE_SMART && uniqOrphansT < uniqOrphansS)) {
|
||||
// grow T
|
||||
ActiveList::swapLists(&active0, &activeT1);
|
||||
dirS=false;
|
||||
} else {
|
||||
// grow S
|
||||
ActiveList::swapLists(&active0, &activeS1);
|
||||
dirS=true;
|
||||
}
|
||||
}
|
||||
|
||||
return flow;
|
||||
}
|
||||
|
||||
|
||||
#if IBIO>0
|
||||
bool IBFSGraph::readFromFile(char *filename)
|
||||
{
|
||||
return readFromFile(filename, false);
|
||||
}
|
||||
bool IBFSGraph::readFromFileCompile(char *filename)
|
||||
{
|
||||
return readFromFile(filename, true);
|
||||
}
|
||||
bool IBFSGraph::readFromFile(char *filename, bool checkCompile)
|
||||
{
|
||||
const int MAX_LINE_LEN = 100;
|
||||
char line[MAX_LINE_LEN];
|
||||
int declaredNumOfNodes, declaredNumOfEdges, nodeId1, nodeId2;
|
||||
int currentNumOfEdges = 0;
|
||||
char c, c1, c2, c3;
|
||||
EdgeCap capacity, capacity2;
|
||||
int numLines=0;
|
||||
// only for compile mode
|
||||
const int bufferSize = sizeof(char) + sizeof(EdgeCap)*4;
|
||||
char buffer[bufferSize];
|
||||
|
||||
char *filenameCompiled = new char[strlen(filename) + strlen(".compiled") + 1];
|
||||
strcpy(filenameCompiled, filename);
|
||||
strcat(filenameCompiled, ".compiled");
|
||||
|
||||
FILE *pFile;
|
||||
FILE *pFileCompiled = NULL;
|
||||
if (checkCompile) {
|
||||
if ((pFileCompiled = fopen(filenameCompiled, "rb")) != NULL) {
|
||||
delete[] filenameCompiled;
|
||||
return readCompiled(pFileCompiled);
|
||||
}
|
||||
fclose(pFileCompiled);
|
||||
}
|
||||
if ((pFile = fopen(filename, "r")) == NULL) {
|
||||
fprintf(stdout, "Could not open file %s\n", filename);
|
||||
delete[] filenameCompiled;
|
||||
return false;
|
||||
}
|
||||
if (checkCompile && (pFileCompiled = fopen(filenameCompiled, "wb")) == NULL) {
|
||||
fprintf(stdout, "Could not open file %s\n", filenameCompiled);
|
||||
delete[] filenameCompiled;
|
||||
fclose(pFile);
|
||||
return false;
|
||||
}
|
||||
delete[] filenameCompiled;
|
||||
|
||||
// read from file into temporary structure
|
||||
while (fgets(line, MAX_LINE_LEN, pFile) != NULL)
|
||||
{
|
||||
numLines++;
|
||||
switch (line[0])
|
||||
{
|
||||
case 'c':
|
||||
case '\n':
|
||||
case '\0':
|
||||
default:
|
||||
break;
|
||||
case 'p':
|
||||
sscanf(line, "%c %c%c%c", &c, &c1, &c2, &c3);
|
||||
if (c1=='m' && c2=='a' && c3=='x') {
|
||||
sscanf(line, "%c %c%c%c %d %d", &c, &c1, &c2, &c3, &declaredNumOfNodes, &declaredNumOfEdges);
|
||||
} else {
|
||||
sscanf(line, "%c %d %d", &c, &declaredNumOfNodes, &declaredNumOfEdges);
|
||||
}
|
||||
initSize(declaredNumOfNodes, declaredNumOfEdges);
|
||||
if (checkCompile) {
|
||||
fwrite(&declaredNumOfNodes, sizeof(int), 1, pFileCompiled);
|
||||
fwrite(&declaredNumOfEdges, sizeof(int), 1, pFileCompiled);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
sscanf(line, "%c %d %d %d ", &c, &nodeId1, &capacity, &capacity2);
|
||||
if (capacity != 0 || capacity2 != 0) {
|
||||
addNode(nodeId1, capacity, capacity2);
|
||||
if (checkCompile) {
|
||||
buffer[0] = 'n';
|
||||
memcpy(buffer+sizeof(char), &nodeId1, sizeof(int));
|
||||
memcpy(buffer+sizeof(char)+sizeof(int), &nodeId1, sizeof(int));
|
||||
memcpy(buffer+sizeof(char)+sizeof(int)+sizeof(int), &capacity, sizeof(int));
|
||||
memcpy(buffer+sizeof(char)+sizeof(int)+sizeof(int)+sizeof(int), &capacity2, sizeof(int));
|
||||
fwrite(&buffer, 1, bufferSize, pFileCompiled);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
sscanf(line, "%c %d %d %d %d", &c,
|
||||
&nodeId1, &nodeId2, &capacity, &capacity2);
|
||||
if (nodeId1 < 0 ||
|
||||
nodeId1 >= declaredNumOfNodes ||
|
||||
nodeId2 < 0 ||
|
||||
nodeId2 >= declaredNumOfNodes)
|
||||
{
|
||||
fprintf(stdout, "inconsistent node index (Line %d)\n", numLines);
|
||||
return false;
|
||||
}
|
||||
if (currentNumOfEdges >= declaredNumOfEdges)
|
||||
{
|
||||
fprintf(stdout, "inconsistent number of edges (Line %d)\n", numLines);
|
||||
return false;
|
||||
}
|
||||
addEdge(nodeId1, nodeId2, capacity, capacity2);
|
||||
currentNumOfEdges++;
|
||||
if (checkCompile) {
|
||||
buffer[0] = 'a';
|
||||
memcpy(buffer+sizeof(char), &nodeId1, sizeof(int));
|
||||
memcpy(buffer+sizeof(char)+sizeof(int), &nodeId2, sizeof(int));
|
||||
memcpy(buffer+sizeof(char)+sizeof(int)+sizeof(int), &capacity, sizeof(int));
|
||||
memcpy(buffer+sizeof(char)+sizeof(int)+sizeof(int)+sizeof(int), &capacity2, sizeof(int));
|
||||
fwrite(&buffer, 1, bufferSize, pFileCompiled);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(pFile);
|
||||
if (checkCompile) {
|
||||
buffer[0] = 'x';
|
||||
fwrite(&buffer, 1, bufferSize, pFileCompiled);
|
||||
}
|
||||
if (currentNumOfEdges != declaredNumOfEdges) {
|
||||
fprintf(stdout, "inconsistent number of edges: differs from declared %d != %d\n",
|
||||
currentNumOfEdges, declaredNumOfEdges);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool IBFSGraph::readCompiled(FILE *pFile)
|
||||
{
|
||||
int declaredNumOfNodes, declaredNumOfEdges, nodeId1, nodeId2;
|
||||
EdgeCap capacity, capacity2;
|
||||
const int bufferSize = sizeof(char)+sizeof(EdgeCap)*4;
|
||||
char buffer[bufferSize];
|
||||
|
||||
// read from file into htemporary structure
|
||||
fprintf(stdout, "c reading compiled file\n");
|
||||
if (fread(&declaredNumOfNodes, sizeof(int), 1, (pFile)) < 1 ||
|
||||
fread(&declaredNumOfEdges, sizeof(int), 1, (pFile)) < 1) {
|
||||
fprintf(stdout, "ERROR while reading compiled num nodes/edges, EOF=%d\n", feof(pFile));
|
||||
fclose(pFile);
|
||||
return false;
|
||||
}
|
||||
initSize(declaredNumOfNodes, declaredNumOfEdges);
|
||||
for (int line=0; !feof(pFile); line++) {
|
||||
if (fread(&buffer, 1, bufferSize, pFile) < bufferSize) {
|
||||
fprintf(stdout, "ERROR while reading compiled line %d, EOF=%d\n", line, feof(pFile));
|
||||
fclose(pFile);
|
||||
return false;
|
||||
}
|
||||
memcpy(&nodeId1, buffer+sizeof(char), sizeof(int));
|
||||
memcpy(&nodeId2, buffer+sizeof(char)+sizeof(int), sizeof(int));
|
||||
memcpy(&capacity, buffer+sizeof(char)+sizeof(int)+sizeof(int), sizeof(int));
|
||||
memcpy(&capacity2, buffer+sizeof(char)+sizeof(int)+sizeof(int)+sizeof(int), sizeof(int));
|
||||
if (buffer[0] == 'n') {
|
||||
if (capacity != 0 || capacity2 != 0) {
|
||||
addNode(nodeId1, capacity, capacity2);
|
||||
}
|
||||
} else if (buffer[0] == 'a') {
|
||||
if (nodeId1 < 0 ||
|
||||
nodeId1 >= declaredNumOfNodes ||
|
||||
nodeId2 < 0 ||
|
||||
nodeId2 >= declaredNumOfNodes)
|
||||
{
|
||||
fprintf(stdout, "inconsistent node index in compiled file %d,%d line %d\n", nodeId1, nodeId2, line);
|
||||
return false;
|
||||
}
|
||||
addEdge(nodeId1, nodeId2, capacity, capacity2);
|
||||
} else if (buffer[0] == 'x') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(pFile);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,449 @@
|
||||
/*
|
||||
#########################################################
|
||||
# #
|
||||
# IBFSGraph - Software for solving #
|
||||
# Maximum s-t Flow / Minimum s-t Cut #
|
||||
# using the IBFS algorithm #
|
||||
# #
|
||||
# http://www.cs.tau.ac.il/~sagihed/ibfs/ #
|
||||
# #
|
||||
# Haim Kaplan (haimk@cs.tau.ac.il) #
|
||||
# Sagi Hed (sagihed@post.tau.ac.il) #
|
||||
# #
|
||||
# 2015 - modified by cDc@seacave #
|
||||
# #
|
||||
#########################################################
|
||||
|
||||
This software implements the IBFS (Incremental Breadth First Search) maximum flow algorithm from
|
||||
"Maximum flows by incremental breadth-first search"
|
||||
Andrew V. Goldberg, Sagi Hed, Haim Kaplan, Robert E. Tarjan, and Renato F. Werneck.
|
||||
In Proceedings of the 19th European conference on Algorithms, ESA'11, pages 457-468.
|
||||
ISBN 978-3-642-23718-8
|
||||
2011
|
||||
|
||||
Copyright Haim Kaplan (haimk@cs.tau.ac.il) and Sagi Hed (sagihed@post.tau.ac.il)
|
||||
|
||||
###########
|
||||
# LICENSE #
|
||||
###########
|
||||
This software can be used for research purposes only.
|
||||
If you use this software for research purposes, you should cite the aforementioned paper
|
||||
in any resulting publication and appropriately credit it.
|
||||
|
||||
If you require another license, please contact the above.
|
||||
|
||||
###########
|
||||
# USAGE #
|
||||
###########
|
||||
|
||||
IBFSGraph g = new IBFSGraph();
|
||||
|
||||
// g.initSize(numNodes, numEdges) indicate the number of nodes and edges in the graph.
|
||||
// Number of edges does not include edges from the source and to the sink!
|
||||
g->initSize(4, 5);
|
||||
|
||||
// g.addNode(nodeID, capFromSource, capToSink) indicate node is connected
|
||||
// to source and sink with appropriate capacities
|
||||
// nodeID is between 0 ... numNodes as supplied in initSize.
|
||||
g->addNode(0, 500, 100);
|
||||
g->addNode(1, 200, 0);
|
||||
g->addNode(2, 50, 50);
|
||||
g->addNode(3, 0, 0); // can discard this line
|
||||
|
||||
// g.addEdge(fromNodeID, toNodeID, capForward, capReverse) indicate edge
|
||||
// connect fromNodeID and toNodeID
|
||||
// with appropriate forward capacity and reverse capacity.
|
||||
g->addEdge(0, 1, 100, 40);
|
||||
g->addEdge(0, 2, 200, 800);
|
||||
g->addEdge(0, 3, 500, 500);
|
||||
g->addEdge(1, 3, 300, 100);
|
||||
g->addEdge(2, 3, 500, 500);
|
||||
|
||||
long startTime = getTime();
|
||||
g->initGraph();
|
||||
g->computeMaxFlow();
|
||||
long time = getTime()-startTime;
|
||||
|
||||
fprintf(stdout, "time=%d\n", time);
|
||||
fprintf(stdout, "flow=%d\n", g->getFlow());
|
||||
for (int i=0; i < 3; i++)
|
||||
fprintf("node %d has label %d\n", i, g->isNodeOnSrcSide(i));
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _IBFS_H__
|
||||
#define _IBFS_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
#ifndef IBIO
|
||||
#define IBIO 0
|
||||
#endif
|
||||
#ifndef IBTEST
|
||||
#define IBTEST 0
|
||||
#endif
|
||||
#ifndef IBSTATS
|
||||
#define IBSTATS 0
|
||||
#endif
|
||||
#ifndef IBDEBUG
|
||||
#define IBDEBUG(X) fprintf(stdout, X"\n"); fflush(stdout)
|
||||
#endif
|
||||
|
||||
#define IB_ALTERNATE_SMART 1
|
||||
#define IB_ORPHANS_END ((Node*)1)
|
||||
|
||||
|
||||
namespace IBFS {
|
||||
|
||||
typedef float Real;
|
||||
typedef float EdgeCap;
|
||||
|
||||
class IBFSStats
|
||||
{
|
||||
public:
|
||||
IBFSStats()
|
||||
{
|
||||
Real C = (IBSTATS ? 0 : -1);
|
||||
augs=C;
|
||||
growthS=C;
|
||||
growthT=C;
|
||||
orphans=C;
|
||||
growthArcs=C;
|
||||
pushes=C;
|
||||
orphanArcs1=C;
|
||||
orphanArcs2=C;
|
||||
orphanArcs3=C;
|
||||
if (IBSTATS) augLenMin = (1 << 30);
|
||||
else augLenMin=C;
|
||||
augLenMax=C;
|
||||
}
|
||||
void inline incAugs() {if (IBSTATS) augs++;}
|
||||
Real inline getAugs() {return augs;}
|
||||
void inline incGrowthS() {if (IBSTATS) growthS++;}
|
||||
Real inline getGrowthS() {return growthS;}
|
||||
void inline incGrowthT() {if (IBSTATS) growthT++;}
|
||||
Real inline getGrowthT() {return growthT;}
|
||||
void inline incOrphans() {if (IBSTATS) orphans++;}
|
||||
Real inline getOrphans() {return orphans;}
|
||||
void inline incGrowthArcs() {if (IBSTATS) growthArcs++;}
|
||||
Real inline getGrowthArcs() {return growthArcs;}
|
||||
void inline incPushes() {if (IBSTATS) pushes++;}
|
||||
Real inline getPushes() {return pushes;}
|
||||
void inline incOrphanArcs1() {if (IBSTATS) orphanArcs1++;}
|
||||
Real inline getOrphanArcs1() {return orphanArcs1;}
|
||||
void inline incOrphanArcs2() {if (IBSTATS) orphanArcs2++;}
|
||||
Real inline getOrphanArcs2() {return orphanArcs2;}
|
||||
void inline incOrphanArcs3() {if (IBSTATS) orphanArcs3++;}
|
||||
Real inline getOrphanArcs3() {return orphanArcs3;}
|
||||
void inline addAugLen(Real len) {
|
||||
if (IBSTATS) {
|
||||
if (len > augLenMax) augLenMax = len;
|
||||
if (len < augLenMin) augLenMin = len;
|
||||
}
|
||||
}
|
||||
Real inline getAugLenMin() {return augLenMin;}
|
||||
Real inline getAugLenMax() {return augLenMax;}
|
||||
|
||||
private:
|
||||
Real augs;
|
||||
Real growthS;
|
||||
Real growthT;
|
||||
Real orphans;
|
||||
Real growthArcs;
|
||||
Real pushes;
|
||||
Real orphanArcs1;
|
||||
Real orphanArcs2;
|
||||
Real orphanArcs3;
|
||||
Real augLenMin;
|
||||
Real augLenMax;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class IBFSGraph
|
||||
{
|
||||
public:
|
||||
IBFSGraph();
|
||||
~IBFSGraph();
|
||||
void setVerbose(bool a_verbose) {
|
||||
verbose = a_verbose;
|
||||
}
|
||||
|
||||
void initSize(int numNodes, int numEdges);
|
||||
void addEdge(int nodeIndexFrom, int nodeIndexTo, EdgeCap capacity, EdgeCap reverseCapacity);
|
||||
void addNode(int nodeIndex, EdgeCap capacityFromSource, EdgeCap capacityToSink);
|
||||
|
||||
void setCompactSlowInitMode(bool a_compactSlowInitMode) {
|
||||
compactSlowInitMode = a_compactSlowInitMode;
|
||||
}
|
||||
void initGraph();
|
||||
EdgeCap computeMaxFlow();
|
||||
|
||||
inline IBFSStats getStats() {
|
||||
return stats;
|
||||
}
|
||||
inline EdgeCap getFlow() {
|
||||
return flow;
|
||||
}
|
||||
inline size_t getNumNodes() {
|
||||
return nodeEnd-nodes;
|
||||
}
|
||||
inline size_t getNumArcs() {
|
||||
return arcEnd-arcs;
|
||||
}
|
||||
bool isNodeOnSrcSide(int nodeIndex) const;
|
||||
|
||||
private:
|
||||
struct Node;
|
||||
struct Arc;
|
||||
|
||||
struct Arc
|
||||
{
|
||||
Node* head;
|
||||
Arc* rev;
|
||||
#if 0
|
||||
int isRevResidual :1;
|
||||
int rCap :31;
|
||||
#else
|
||||
EdgeCap rCap;
|
||||
unsigned char isRevResidual;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct Node
|
||||
{
|
||||
int lastAugTimestamp:31;
|
||||
int isParentCurr:1;
|
||||
Arc *firstArc;
|
||||
Arc *parent;
|
||||
Node *firstSon;
|
||||
Node *nextPtr;
|
||||
int label; // label > 0: distance from s, label < 0: -distance from t
|
||||
EdgeCap excess; // excess > 0: capacity from s, excess < 0: -capacity to t
|
||||
};
|
||||
|
||||
class ActiveList
|
||||
{
|
||||
public:
|
||||
inline ActiveList() {
|
||||
list = NULL;
|
||||
len = 0;
|
||||
}
|
||||
inline void init(int numNodes) {
|
||||
list = new Node*[numNodes];
|
||||
len = 0;
|
||||
}
|
||||
inline void release() {
|
||||
if (list != NULL) {
|
||||
delete[] list;
|
||||
list = NULL;
|
||||
}
|
||||
}
|
||||
inline void clear() {
|
||||
len = 0;
|
||||
}
|
||||
inline void add(Node* x) {
|
||||
list[len] = x;
|
||||
len++;
|
||||
}
|
||||
inline static void swapLists(ActiveList *a, ActiveList *b) {
|
||||
ActiveList tmp = (*a);
|
||||
(*a) = (*b);
|
||||
(*b) = tmp;
|
||||
}
|
||||
Node **list;
|
||||
int len;
|
||||
};
|
||||
|
||||
class Buckets
|
||||
{
|
||||
public:
|
||||
inline Buckets() {
|
||||
buckets = NULL;
|
||||
prevPtrs = NULL;
|
||||
maxBucket = 0;
|
||||
nodes = NULL;
|
||||
}
|
||||
inline void init(Node *a_nodes, int numNodes) {
|
||||
nodes = a_nodes;
|
||||
buckets = new Node*[numNodes];
|
||||
memset(buckets, 0, sizeof(Node*)*numNodes);
|
||||
prevPtrs = new Node*[numNodes];
|
||||
memset(prevPtrs, 0, sizeof(Node*)*numNodes);
|
||||
maxBucket = 0;
|
||||
}
|
||||
inline void release() {
|
||||
if (buckets != NULL) {
|
||||
delete[] buckets;
|
||||
buckets = NULL;
|
||||
}
|
||||
if (prevPtrs != NULL) {
|
||||
delete[] prevPtrs;
|
||||
prevPtrs = NULL;
|
||||
}
|
||||
}
|
||||
template <bool sTree> inline void add(Node* x) {
|
||||
int bucket = (sTree ? (x->label) : (-x->label));
|
||||
if (buckets[bucket] == NULL || buckets[bucket] == IB_ORPHANS_END) {
|
||||
x->nextPtr = IB_ORPHANS_END;
|
||||
} else {
|
||||
x->nextPtr = buckets[bucket];
|
||||
prevPtrs[x->nextPtr-nodes] = x;
|
||||
}
|
||||
buckets[bucket] = x;
|
||||
if (bucket > maxBucket) maxBucket = bucket;
|
||||
}
|
||||
inline Node* popFront(int bucket) {
|
||||
Node *x = buckets[bucket];
|
||||
if (x == NULL || x == IB_ORPHANS_END) return NULL;
|
||||
buckets[bucket] = x->nextPtr;
|
||||
//x->nextOrphan = NULL;
|
||||
return x;
|
||||
}
|
||||
template <bool sTree> inline void remove(Node *x) {
|
||||
int bucket = (sTree ? (x->label) : (-x->label));
|
||||
if (buckets[bucket] == x) {
|
||||
buckets[bucket] = x->nextPtr;
|
||||
} else {
|
||||
prevPtrs[x-nodes]->nextPtr = x->nextPtr;
|
||||
if (x->nextPtr != IB_ORPHANS_END) prevPtrs[x->nextPtr-nodes] = prevPtrs[x-nodes];
|
||||
}
|
||||
//x->nextOrphan = NULL;
|
||||
}
|
||||
|
||||
Node **buckets;
|
||||
Node **prevPtrs;
|
||||
Node *nodes;
|
||||
int maxBucket;
|
||||
};
|
||||
|
||||
// members
|
||||
IBFSStats stats;
|
||||
Node *nodes, *nodeEnd;
|
||||
Arc *arcs, *arcEnd;
|
||||
int numNodes;
|
||||
EdgeCap flow;
|
||||
unsigned short augTimestamp;
|
||||
unsigned int uniqOrphansS, uniqOrphansT;
|
||||
Node* orphanFirst;
|
||||
Node* orphanLast;
|
||||
int topLevelS, topLevelT;
|
||||
ActiveList active0, activeS1, activeT1;
|
||||
Buckets orphanBuckets;
|
||||
bool verbose;
|
||||
|
||||
void augment(Arc *bridge);
|
||||
template <bool sTree> void augmentTree(Node *x, EdgeCap bottleneck);
|
||||
template <bool sTree> void adoption();
|
||||
template <bool sTree> void adoption3Pass();
|
||||
template <bool dirS> void growth();
|
||||
|
||||
#if IBIO>0
|
||||
bool readFromFile(char *filename);
|
||||
bool readFromFileCompile(char *filename);
|
||||
bool readFromFile(char *filename, bool checkCompile);
|
||||
bool readCompiled(FILE *pFile);
|
||||
#endif
|
||||
|
||||
//
|
||||
// Initialization
|
||||
//
|
||||
struct TmpEdge
|
||||
{
|
||||
Node* head;
|
||||
Node* tail;
|
||||
EdgeCap cap;
|
||||
EdgeCap revCap;
|
||||
};
|
||||
struct TmpArc
|
||||
{
|
||||
TmpArc *rev;
|
||||
EdgeCap cap;
|
||||
};
|
||||
char *memArcs;
|
||||
TmpEdge *tmpEdges, *tmpEdgeLast;
|
||||
TmpArc *tmpArcs;
|
||||
bool compactSlowInitMode;
|
||||
void initGraphFast();
|
||||
void initGraphCompact();
|
||||
|
||||
//
|
||||
// Testing
|
||||
//
|
||||
void testTree();
|
||||
void testExit() {
|
||||
exit(1);
|
||||
}
|
||||
inline void testNode(Node *x) {
|
||||
if (IBTEST && x-nodes == -1) {
|
||||
IBDEBUG("*");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline void IBFSGraph::addNode(int nodeIndex, EdgeCap capacitySource, EdgeCap capacitySink)
|
||||
{
|
||||
EdgeCap f = nodes[nodeIndex].excess;
|
||||
if (f > 0) {
|
||||
capacitySource += f;
|
||||
} else {
|
||||
capacitySink -= f;
|
||||
}
|
||||
if (capacitySource < capacitySink) {
|
||||
flow += capacitySource;
|
||||
} else {
|
||||
flow += capacitySink;
|
||||
}
|
||||
nodes[nodeIndex].excess = capacitySource - capacitySink;
|
||||
}
|
||||
|
||||
inline void IBFSGraph::addEdge(int nodeIndexFrom, int nodeIndexTo, EdgeCap capacity, EdgeCap reverseCapacity)
|
||||
{
|
||||
assert((void*)tmpEdgeLast < (void*)tmpArcs);
|
||||
tmpEdgeLast->tail = nodes + nodeIndexFrom;
|
||||
tmpEdgeLast->head = nodes + nodeIndexTo;
|
||||
tmpEdgeLast->cap = capacity;
|
||||
tmpEdgeLast->revCap = reverseCapacity;
|
||||
tmpEdgeLast++;
|
||||
|
||||
// use label as a temporary storage
|
||||
// to count the out degree of nodes
|
||||
nodes[nodeIndexFrom].label++;
|
||||
nodes[nodeIndexTo].label++;
|
||||
|
||||
/*
|
||||
Arc *aFwd = arcLast;
|
||||
arcLast++;
|
||||
Arc *aRev = arcLast;
|
||||
arcLast++;
|
||||
|
||||
Node* x = nodes + nodeIndexFrom;
|
||||
x->label++;
|
||||
Node* y = nodes + nodeIndexTo;
|
||||
y->label++;
|
||||
|
||||
aRev->rev = aFwd;
|
||||
aFwd->rev = aRev;
|
||||
aFwd->rCap = capacity;
|
||||
aRev->rCap = reverseCapacity;
|
||||
aFwd->head = y;
|
||||
aRev->head = x;*/
|
||||
}
|
||||
|
||||
|
||||
inline bool IBFSGraph::isNodeOnSrcSide(int nodeIndex) const
|
||||
{
|
||||
if (nodes[nodeIndex].label == numNodes || nodes[nodeIndex].label == 0) {
|
||||
return activeT1.len == 0;
|
||||
}
|
||||
return (nodes[nodeIndex].label > 0);
|
||||
}
|
||||
|
||||
} // namespace IBFS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
#########################################################
|
||||
# #
|
||||
# IBFSGraph - Software for solving #
|
||||
# Maximum s-t Flow / Minimum s-t Cut #
|
||||
# using the IBFS algorithm #
|
||||
# #
|
||||
# http://www.cs.tau.ac.il/~sagihed/ibfs/ #
|
||||
# #
|
||||
# Haim Kaplan (haimk@cs.tau.ac.il) #
|
||||
# Sagi Hed (sagihed@post.tau.ac.il) #
|
||||
# #
|
||||
#########################################################
|
||||
|
||||
This software implements the IBFS (Incremental Breadth First Search) maximum flow algorithm from
|
||||
"Maximum flows by incremental breadth-first search"
|
||||
Andrew V. Goldberg, Sagi Hed, Haim Kaplan, Robert E. Tarjan, and Renato F. Werneck.
|
||||
In Proceedings of the 19th European conference on Algorithms, ESA'11, pages 457-468.
|
||||
ISBN 978-3-642-23718-8
|
||||
2011
|
||||
|
||||
Copyright Haim Kaplan (haimk@cs.tau.ac.il) and Sagi Hed (sagihed@post.tau.ac.il)
|
||||
|
||||
###########
|
||||
# LICENSE #
|
||||
###########
|
||||
This software can be used for research purposes only.
|
||||
If you use this software for research purposes, you should cite the aforementioned paper
|
||||
in any resulting publication and appropriately credit it.
|
||||
|
||||
If you require another license, please contact the above.
|
||||
|
||||
*/
|
||||
Reference in new issue
Block a user