You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

977 lines
24 KiB

/*
#########################################################
# #
# 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