Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 192 additions & 0 deletions maxflow/graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ namespace maxflow {
template <typename captype, typename tcaptype, typename flowtype>
Graph<captype, tcaptype, flowtype>::Graph(int node_num_max, int edge_num_max, void (*err_function)(const char *))
: node_num(0),
computing(0),
nodeptr_block(NULL),
error_function(err_function)
{
Expand Down Expand Up @@ -70,6 +71,7 @@ template <typename captype, typename tcaptype, typename flowtype>
node_last = nodes;
arc_last = arcs;
node_num = 0;
computing = 0;

if (nodeptr_block)
{
Expand Down Expand Up @@ -603,13 +605,203 @@ template <typename captype, typename tcaptype, typename flowtype>

/***********************************************************************/

template <typename captype, typename tcaptype, typename flowtype>
void Graph<captype,tcaptype,flowtype>::maxflow_prepare(bool reuse_trees, Block<node_id>* _changed_list)
{
if (computing)
{
if (error_function)
(*error_function)("Do not call maxflow_prepare() while you did not finish with maxflow_compute()!");
exit(1);
}

compute_node = NULL;
compute_reuse_trees = reuse_trees;
compute_iteration = 0;
compute_prev_progress = 0;
compute_max = node_num;
compute_step = node_num / 10;
compute_step = compute_step > 1000 ? compute_step : 1000;
computing = 1;

if (!nodeptr_block)
{
nodeptr_block = new DBlock<nodeptr>(NODEPTR_BLOCK_SIZE, error_function);
}

changed_list = _changed_list;
if (maxflow_iteration == 0 && reuse_trees) { if (error_function) (*error_function)("reuse_trees cannot be used in the first call to maxflow()!"); exit(1); }
if (changed_list && !reuse_trees) { if (error_function) (*error_function)("changed_list cannot be used without reuse_trees!"); exit(1); }

if (reuse_trees) maxflow_reuse_trees_init();
else maxflow_init();
}

template <typename captype, typename tcaptype, typename flowtype>
bool Graph<captype,tcaptype,flowtype>::maxflow_compute(float *progress)
{
bool more_to_do = 1;
node *i, *j;
arc *a;
nodeptr *np, *np_next;

if (! computing)
{
if (error_function)
(*error_function)("You did not call maxflow_prepare()!");
exit(1);
}

while ( 1 )
{
// test_consistency(compute_node);

if ((i=compute_node))
{
i -> next = NULL; /* remove active flag */
if (!i->parent) i = NULL;
}
if (!i)
{
if (!(i = next_active()))
{
more_to_do = 0;
break;
}

compute_iteration++;
}

/* growth */
if (!i->is_sink)
{
/* grow source tree */
for (a=i->first; a; a=a->next)
if (a->r_cap)
{
j = a -> head;
if (!j->parent)
{
j -> is_sink = 0;
j -> parent = a -> sister;
j -> TS = i -> TS;
j -> DIST = i -> DIST + 1;
if (! j->next)
compute_max++;
set_active(j);
add_to_changed_list(j);
}
else if (j->is_sink) break;
else if (j->TS <= i->TS &&
j->DIST > i->DIST)
{
/* heuristic - trying to make the distance from j to the source shorter */
j -> parent = a -> sister;
j -> TS = i -> TS;
j -> DIST = i -> DIST + 1;
}
}
}
else
{
/* grow sink tree */
for (a=i->first; a; a=a->next)
if (a->sister->r_cap)
{
j = a -> head;
if (!j->parent)
{
j -> is_sink = 1;
j -> parent = a -> sister;
j -> TS = i -> TS;
j -> DIST = i -> DIST + 1;
if (! j->next)
compute_max++;
set_active(j);
add_to_changed_list(j);
}
else if (!j->is_sink) { a = a -> sister; break; }
else if (j->TS <= i->TS &&
j->DIST > i->DIST)
{
/* heuristic - trying to make the distance from j to the sink shorter */
j -> parent = a -> sister;
j -> TS = i -> TS;
j -> DIST = i -> DIST + 1;
}
}
}

TIME ++;

if (a)
{
i -> next = i; /* set active flag */
compute_node = i;

/* augmentation */
augment(a);
/* augmentation end */

/* adoption */
while ((np=orphan_first))
{
np_next = np -> next;
np -> next = NULL;

while ((np=orphan_first))
{
orphan_first = np -> next;
i = np -> ptr;
nodeptr_block -> Delete(np);
if (!orphan_first) orphan_last = NULL;
if (i->is_sink) process_sink_orphan(i);
else process_source_orphan(i);
}

orphan_first = np_next;
}
/* adoption end */
}
else compute_node = NULL;

if (compute_iteration > compute_prev_progress + compute_step)
{
compute_prev_progress = compute_iteration;
*progress = (float) compute_iteration / compute_max;
break;
}
}
// test_consistency();

if (! more_to_do && (!compute_reuse_trees || (maxflow_iteration % 64) == 0))
{
delete nodeptr_block;
nodeptr_block = NULL;

maxflow_iteration++;

*progress = 1.0;
computing = 0;
}

return more_to_do;
}

template <typename captype, typename tcaptype, typename flowtype>
flowtype Graph<captype,tcaptype,flowtype>::maxflow(bool reuse_trees, Block<node_id>* _changed_list)
{
node *i, *j, *current_node = NULL;
arc *a;
nodeptr *np, *np_next;

if (computing)
{
if (error_function)
(*error_function)("Do not call maxflow() while iterating with maxflow_prepare() and maxflow_compute()!");
exit(1);
}

if (!nodeptr_block)
{
nodeptr_block = new DBlock<nodeptr>(NODEPTR_BLOCK_SIZE, error_function);
Expand Down
26 changes: 26 additions & 0 deletions maxflow/graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,24 @@ template <typename captype, typename tcaptype, typename flowtype> class Graph
// FOR DESCRIPTION OF changed_list, SEE remove_from_changed_list().
flowtype maxflow(bool reuse_trees = false, Block<node_id>* changed_list = NULL);

// Alternative to maxflow(). You must first call maxflow_prepare()
// with the same arguments you would have passed on maxflow(), then
// call maxflow_compute() in a loop, for as long as it doesn't
// return 0. This can be used when you wish to get approximate
// progression information, for instance to give GUI feedback.
// The returned progress value is a float between 0.0 and 1.0.
// Usage example:
//
// float progress;
// g->maxflow_prepare();
// while (g->maxflow_compute(&progress))
// report_progression(progress);
//
// IMPORTANT: do not mix maxflow() and maxflow_prepare/maxflow_compute().
void maxflow_prepare(bool reuse_trees = false, Block<node_id>* changed_list = NULL);
bool maxflow_compute(float *progress);


// After the maxflow is computed, this function returns to which
// segment the node 'i' belongs (Graph<captype,tcaptype,flowtype>::SOURCE or Graph<captype,tcaptype,flowtype>::SINK).
//
Expand Down Expand Up @@ -361,6 +379,14 @@ template <typename captype, typename tcaptype, typename flowtype> class Graph
void process_sink_orphan(node *i);

void test_consistency(node* current_node=NULL); // debug function

bool computing;
node *compute_node;
bool compute_reuse_trees;
int compute_max;
int compute_iteration;
int compute_prev_progress;
int compute_step;
};


Expand Down