ISCE_INSAR/contrib/Snaphu/src/snaphu_solver.c

2427 lines
66 KiB
C

/*************************************************************************
snaphu network-flow solver source file
Written by Curtis W. Chen
Copyright 2002 Board of Trustees, Leland Stanford Jr. University
Please see the supporting documentation for terms of use.
No warranty.
*************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <signal.h>
#include <limits.h>
#include <float.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "snaphu.h"
/* function: TreeSolve()
* ---------------------
* Solves the nonlinear network optimization problem.
*/
long TreeSolve(nodeT **nodes, nodesuppT **nodesupp, nodeT *ground,
nodeT *source, candidateT **candidatelistptr,
candidateT **candidatebagptr, long *candidatelistsizeptr,
long *candidatebagsizeptr, bucketT *bkts, short **flows,
void **costs, incrcostT **incrcosts, nodeT ***apexes,
signed char **iscandidate, long ngroundarcs, long nflow,
float **mag, float **wrappedphase, char *outfile,
long nnoderow, short *nnodesperrow, long narcrow,
short *narcsperrow, long nrow, long ncol,
outfileT *outfiles, paramT *params){
long i, row, col, arcrow, arccol, arcdir, arcnum, upperarcnum;
long arcrow1, arccol1, arcdir1, arcrow2, arccol2, arcdir2;
long treesize, candidatelistsize, candidatebagsize;
long violation, groupcounter, fromgroup, group1, apexlistbase, apexlistlen;
long cyclecost, outcostto, startlevel, dlevel, doutcost, dincost;
long candidatelistlen, candidatebagnext;
long inondegen, ipivots, nnodes, nnewnodes, maxnewnodes, templong;
signed char fromside;
candidateT *candidatelist, *candidatebag, *tempcandidateptr;
nodeT *from, *to, *cycleapex, *node1, *node2, *leavingparent, *leavingchild;
nodeT *root, *mntpt, *oldmntpt, *skipthread, *tempnode1, *tempnode2;
nodeT *firstfromnode, *firsttonode;
nodeT **apexlist;
float **unwrappedphase;
/* dereference some pointers and store as local variables */
candidatelist=(*candidatelistptr);
candidatebag=(*candidatebagptr);
candidatelistsize=(*candidatelistsizeptr);
candidatebagsize=(*candidatebagsizeptr);
candidatelistlen=0;
candidatebagnext=0;
/* set up */
bkts->curr=bkts->maxind;
nnodes=InitTree(source,nodes,nodesupp,ground,ngroundarcs,bkts,nflow,
incrcosts,apexes,iscandidate,nnoderow,nnodesperrow,
narcrow,narcsperrow,nrow,ncol,params);
apexlistlen=INITARRSIZE;
apexlist=MAlloc(apexlistlen*sizeof(nodeT *));
groupcounter=2;
ipivots=0;
inondegen=0;
maxnewnodes=ceil(nnodes*params->maxnewnodeconst);
nnewnodes=0;
treesize=1;
fprintf(sp3,"Treesize: %-10ld Pivots: %-11ld Improvements: %-11ld",
treesize,ipivots,inondegen);
/* loop over each entering node (note, source already on tree) */
while(treesize<nnodes){
nnewnodes=0;
while(nnewnodes<maxnewnodes && treesize<nnodes){
/* get node with lowest outcost */
to=MinOutCostNode(bkts);
from=to->pred;
/* add new node to the tree */
GetArc(from,to,&arcrow,&arccol,&arcdir,nrow,ncol,nodesupp);
to->group=1;
to->level=from->level+1;
to->incost=from->incost+GetCost(incrcosts,arcrow,arccol,-arcdir);
to->next=from->next;
to->prev=from;
to->next->prev=to;
from->next=to;
/* scan new node's neighbors */
from=to;
if(from->row!=GROUNDROW){
arcnum=-5;
upperarcnum=-1;
}else{
arcnum=-1;
upperarcnum=ngroundarcs-1;
}
while(arcnum<upperarcnum){
/* get row, col indices and distance of next node */
to=NeighborNode(from,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,nodesupp);
/* if to node is on tree */
if(to->group>0){
if(to!=from->pred){
cycleapex=FindApex(from,to);
apexes[arcrow][arccol]=cycleapex;
CheckArcReducedCost(from,to,cycleapex,arcrow,arccol,arcdir,nflow,
nodes,ground,&candidatebag,&candidatebagnext,
&candidatebagsize,incrcosts,iscandidate,
params);
}else{
apexes[arcrow][arccol]=NULL;
}
}else{
/* if to is not on tree, update outcost and add to bucket */
AddNewNode(from,to,arcdir,bkts,nflow,incrcosts,arcrow,arccol,params);
}
}
nnewnodes++;
treesize++;
}
/* keep looping until no more arcs have negative reduced costs */
while(candidatebagnext){
/* if we received SIGINT or SIGHUP signal, dump results */
/* keep this stuff out of the signal handler so we don't risk */
/* writing a non-feasible solution (ie, if signal during augment) */
/* signal handler disabled for all but primary (grid) networks */
if(dumpresults_global){
fprintf(sp0,"\n\nDumping current solution to file %s\n",
outfile);
if(requestedstop_global){
Free2DArray((void **)costs,2*nrow-1);
}
unwrappedphase=(float **)Get2DMem(nrow,ncol,sizeof(float *),
sizeof(float));
IntegratePhase(wrappedphase,unwrappedphase,flows,nrow,ncol);
FlipPhaseArraySign(unwrappedphase,params,nrow,ncol);
WriteOutputFile(mag,unwrappedphase,outfiles->outfile,outfiles,
nrow,ncol);
if(requestedstop_global){
fprintf(sp0,"Program exiting\n");
exit(ABNORMAL_EXIT);
}
Free2DArray((void **)unwrappedphase,nrow);
dumpresults_global=FALSE;
fprintf(sp0,"\n\nProgram continuing\n");
}
/* swap candidate bag and candidate list pointers and sizes */
tempcandidateptr=candidatebag;
candidatebag=candidatelist;
candidatelist=tempcandidateptr;
templong=candidatebagsize;
candidatebagsize=candidatelistsize;
candidatelistsize=templong;
candidatelistlen=candidatebagnext;
candidatebagnext=0;
/* sort candidate list by violation, with augmenting arcs always first */
qsort((void *)candidatelist,candidatelistlen,sizeof(candidateT),
CandidateCompare);
/* set all arc directions to be plus/minus 1 */
for(i=0;i<candidatelistlen;i++){
if(candidatelist[i].arcdir>1){
candidatelist[i].arcdir=1;
}else if(candidatelist[i].arcdir<-1){
candidatelist[i].arcdir=-1;
}
}
/* this doesn't seem to make it any faster, so just do all of them */
/* set the number of candidates to process */
/* (must change candidatelistlen to ncandidates in for loop below) */
/*
maxcandidates=MAXCANDIDATES;
if(maxcandidates>candidatelistlen){
ncandidates=candidatelistlen;
}else{
ncandidates=maxcandidates;
}
*/
/* now pivot for each arc in the candidate list */
for(i=0;i<candidatelistlen;i++){
/* get arc info */
from=candidatelist[i].from;
to=candidatelist[i].to;
arcdir=candidatelist[i].arcdir;
arcrow=candidatelist[i].arcrow;
arccol=candidatelist[i].arccol;
/* unset iscandidate */
iscandidate[arcrow][arccol]=FALSE;
/* make sure the next arc still has a negative violation */
outcostto=from->outcost+
GetCost(incrcosts,arcrow,arccol,arcdir);
cyclecost=outcostto + to->incost
-apexes[arcrow][arccol]->outcost
-apexes[arcrow][arccol]->incost;
/* if violation no longer negative, check reverse arc */
if(!((outcostto < to->outcost) || (cyclecost < 0))){
from=to;
to=candidatelist[i].from;
arcdir=-arcdir;
outcostto=from->outcost+
GetCost(incrcosts,arcrow,arccol,arcdir);
cyclecost=outcostto + to->incost
-apexes[arcrow][arccol]->outcost
-apexes[arcrow][arccol]->incost;
}
/* see if the cycle is negative (see if there is a violation) */
if((outcostto < to->outcost) || (cyclecost < 0)){
/* make sure the group counter hasn't gotten too big */
if(++groupcounter>MAXGROUPBASE){
for(row=0;row<nnoderow;row++){
for(col=0;col<nnodesperrow[row];col++){
if(nodes[row][col].group>0){
nodes[row][col].group=1;
}
}
}
if(ground!=NULL && ground->group>0){
ground->group=1;
}
groupcounter=2;
}
/* if augmenting cycle (nondegenerate pivot) */
if(cyclecost<0){
/* augment flow along cycle and select leaving arc */
/* if we are augmenting non-zero flow, any arc with zero flow */
/* after the augmentation is a blocking arc */
while(TRUE){
fromside=TRUE;
node1=from;
node2=to;
leavingchild=NULL;
flows[arcrow][arccol]+=arcdir*nflow;
ReCalcCost(costs,incrcosts,flows[arcrow][arccol],arcrow,arccol,
nflow,nrow,params);
violation=GetCost(incrcosts,arcrow,arccol,arcdir);
if(node1->level > node2->level){
while(node1->level != node2->level){
GetArc(node1->pred,node1,&arcrow1,&arccol1,&arcdir1,
nrow,ncol,nodesupp);
flows[arcrow1][arccol1]+=(arcdir1*nflow);
ReCalcCost(costs,incrcosts,flows[arcrow1][arccol1],
arcrow1,arccol1,nflow,nrow,params);
if(leavingchild==NULL
&& !flows[arcrow1][arccol1]){
leavingchild=node1;
}
violation+=GetCost(incrcosts,arcrow1,arccol1,arcdir1);
node1->group=groupcounter+1;
node1=node1->pred;
}
}else{
while(node1->level != node2->level){
GetArc(node2->pred,node2,&arcrow2,&arccol2,&arcdir2,
nrow,ncol,nodesupp);
flows[arcrow2][arccol2]-=(arcdir2*nflow);
ReCalcCost(costs,incrcosts,flows[arcrow2][arccol2],
arcrow2,arccol2,nflow,nrow,params);
if(!flows[arcrow2][arccol2]){
leavingchild=node2;
fromside=FALSE;
}
violation+=GetCost(incrcosts,arcrow2,arccol2,-arcdir2);
node2->group=groupcounter;
node2=node2->pred;
}
}
while(node1!=node2){
GetArc(node1->pred,node1,&arcrow1,&arccol1,&arcdir1,nrow,ncol,
nodesupp);
GetArc(node2->pred,node2,&arcrow2,&arccol2,&arcdir2,nrow,ncol,
nodesupp);
flows[arcrow1][arccol1]+=(arcdir1*nflow);
flows[arcrow2][arccol2]-=(arcdir2*nflow);
ReCalcCost(costs,incrcosts,flows[arcrow1][arccol1],
arcrow1,arccol1,nflow,nrow,params);
ReCalcCost(costs,incrcosts,flows[arcrow2][arccol2],
arcrow2,arccol2,nflow,nrow,params);
violation+=(GetCost(incrcosts,arcrow1,arccol1,arcdir1)
+GetCost(incrcosts,arcrow2,arccol2,-arcdir2));
if(!flows[arcrow2][arccol2]){
leavingchild=node2;
fromside=FALSE;
}else if(leavingchild==NULL
&& !flows[arcrow1][arccol1]){
leavingchild=node1;
}
node1->group=groupcounter+1;
node2->group=groupcounter;
node1=node1->pred;
node2=node2->pred;
}
if(violation>=0){
break;
}
}
inondegen++;
}else{
/* We are not augmenting flow, but just updating potentials. */
/* Arcs with zero flow are implicitly directed upwards to */
/* maintain a strongly feasible spanning tree, so arcs with zero */
/* flow on the path between to node and apex are blocking arcs. */
/* Leaving arc is last one whose child's new outcost is less */
/* than its old outcost. Such an arc must exist, or else */
/* we'd be augmenting flow on a negative cycle. */
/* trace the cycle and select leaving arc */
fromside=FALSE;
node1=from;
node2=to;
leavingchild=NULL;
if(node1->level > node2->level){
while(node1->level != node2->level){
node1->group=groupcounter+1;
node1=node1->pred;
}
}else{
while(node1->level != node2->level){
if(outcostto < node2->outcost){
leavingchild=node2;
GetArc(node2->pred,node2,&arcrow2,&arccol2,&arcdir2,
nrow,ncol,nodesupp);
outcostto+=GetCost(incrcosts,arcrow2,arccol2,-arcdir2);
}else{
outcostto=VERYFAR;
}
node2->group=groupcounter;
node2=node2->pred;
}
}
while(node1!=node2){
if(outcostto < node2->outcost){
leavingchild=node2;
GetArc(node2->pred,node2,&arcrow2,&arccol2,&arcdir2,nrow,ncol,
nodesupp);
outcostto+=GetCost(incrcosts,arcrow2,arccol2,-arcdir2);
}else{
outcostto=VERYFAR;
}
node1->group=groupcounter+1;
node2->group=groupcounter;
node1=node1->pred;
node2=node2->pred;
}
}
cycleapex=node1;
/* set leaving parent */
if(leavingchild==NULL){
fromside=TRUE;
leavingparent=from;
}else{
leavingparent=leavingchild->pred;
}
/* swap from and to if leaving arc is on the from side */
if(fromside){
groupcounter++;
fromgroup=groupcounter-1;
tempnode1=from;
from=to;
to=tempnode1;
}else{
fromgroup=groupcounter+1;
}
/* if augmenting pivot */
if(cyclecost<0){
/* find first child of apex on either cycle path */
firstfromnode=NULL;
firsttonode=NULL;
if(cycleapex->row!=GROUNDROW){
arcnum=-5;
upperarcnum=-1;
}else{
arcnum=-1;
upperarcnum=ngroundarcs-1;
}
while(arcnum<upperarcnum){
tempnode1=NeighborNode(cycleapex,++arcnum,&upperarcnum,nodes,
ground,&arcrow,&arccol,&arcdir,nrow,ncol,
nodesupp);
if(tempnode1->group==groupcounter
&& apexes[arcrow][arccol]==NULL){
firsttonode=tempnode1;
if(firstfromnode!=NULL){
break;
}
}else if(tempnode1->group==fromgroup
&& apexes[arcrow][arccol]==NULL){
firstfromnode=tempnode1;
if(firsttonode!=NULL){
break;
}
}
}
/* update potentials, mark stationary parts of tree */
cycleapex->group=groupcounter+2;
if(firsttonode!=NULL){
NonDegenUpdateChildren(cycleapex,leavingparent,firsttonode,0,
ngroundarcs,nflow,nodes,nodesupp,ground,
apexes,incrcosts,nrow,ncol,params);
}
if(firstfromnode!=NULL){
NonDegenUpdateChildren(cycleapex,from,firstfromnode,1,
ngroundarcs,nflow,nodes,nodesupp,ground,
apexes,incrcosts,nrow,ncol,params);
}
groupcounter=from->group;
apexlistbase=cycleapex->group;
/* children of cycleapex are not marked, so we set fromgroup */
/* equal to cycleapex group for use with apex updates below */
/* all other children of cycle will be in apexlist if we had an */
/* augmenting pivot, so fromgroup only important for cycleapex */
fromgroup=cycleapex->group;
}else{
/* set this stuff for use with apex updates below */
cycleapex->group=fromgroup;
groupcounter+=2;
apexlistbase=groupcounter+1;
}
/* remount subtree at new mount point */
if(leavingchild==NULL){
skipthread=to;
}else{
root=from;
oldmntpt=to;
/* for each node on the path from to node to leaving child */
while(oldmntpt!=leavingparent){
/* remount the subtree at the new mount point */
mntpt=root;
root=oldmntpt;
oldmntpt=root->pred;
root->pred=mntpt;
GetArc(mntpt,root,&arcrow,&arccol,&arcdir,nrow,ncol,nodesupp);
/* calculate differences for updating potentials and levels */
dlevel=mntpt->level-root->level+1;
doutcost=mntpt->outcost - root->outcost
+ GetCost(incrcosts,arcrow,arccol,arcdir);
dincost=mntpt->incost - root->incost
+ GetCost(incrcosts,arcrow,arccol,-arcdir);
/* update all children */
/* group of each remounted tree used to reset apexes below */
node1=root;
startlevel=root->level;
groupcounter++;
while(TRUE){
/* update the level, potentials, and group of the node */
node1->level+=dlevel;
node1->outcost+=doutcost;
node1->incost+=dincost;
node1->group=groupcounter;
/* break when node1 is no longer descendent of the root */
if(node1->next->level <= startlevel){
break;
}
node1=node1->next;
}
/* update threads */
root->prev->next=node1->next;
node1->next->prev=root->prev;
node1->next=mntpt->next;
mntpt->next->prev=node1;
mntpt->next=root;
root->prev=mntpt;
}
skipthread=node1->next;
/* reset apex pointers for entering and leaving arcs */
GetArc(from,to,&arcrow,&arccol,&arcdir,nrow,ncol,nodesupp);
apexes[arcrow][arccol]=NULL;
GetArc(leavingparent,leavingchild,&arcrow,&arccol,
&arcdir,nrow,ncol,nodesupp);
apexes[arcrow][arccol]=cycleapex;
/* make sure we have enough memory for the apex list */
if(groupcounter-apexlistbase+1>apexlistlen){
apexlistlen=1.5*(groupcounter-apexlistbase+1);
apexlist=ReAlloc(apexlist,apexlistlen*sizeof(nodeT *));
}
/* set the apex list */
node2=leavingchild;
for(group1=groupcounter;group1>=apexlistbase;group1--){
apexlist[group1-apexlistbase]=node2;
node2=node2->pred;
}
/* reset apex pointers on remounted tree */
/* only nodes which are in different groups need new apexes */
node1=to;
startlevel=to->level;
while(TRUE){
/* loop over outgoing arcs */
if(node1->row!=GROUNDROW){
arcnum=-5;
upperarcnum=-1;
}else{
arcnum=-1;
upperarcnum=ngroundarcs-1;
}
while(arcnum<upperarcnum){
node2=NeighborNode(node1,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,nodesupp);
/* if node2 on tree */
if(node2->group>0){
/* if node2 is either not part of remounted tree or */
/* it is higher on remounted tree than node1, */
/* and arc isn't already on tree */
if(node2->group < node1->group
&& apexes[arcrow][arccol]!=NULL){
/* if new apex in apexlist */
/* node2 on remounted tree, if nonaugmenting pivot */
if(node2->group >= apexlistbase){
apexes[arcrow][arccol]=apexlist[node2->group
-apexlistbase];
}else{
/* if old apex below level of cycleapex, */
/* node2 is on "to" node's side of tree */
/* implicitly, if old apex above cycleapex, */
/* we do nothing since apex won't change */
if(apexes[arcrow][arccol]->level > cycleapex->level){
/* since new apex not in apexlist (tested above), */
/* node2 above leaving arc so new apex is cycleapex */
apexes[arcrow][arccol]=cycleapex;
}else{
/* node2 not on "to" side of tree */
/* if old apex is cycleapex, node2 is on "from" side */
if(apexes[arcrow][arccol]==cycleapex){
/* new apex will be on cycle, so trace node2->pred */
/* until we hit a node with group==fromgroup */
tempnode2=node2;
while(tempnode2->group != fromgroup){
tempnode2=tempnode2->pred;
}
apexes[arcrow][arccol]=tempnode2;
}
}
}
/* check outgoing arcs for negative reduced costs */
CheckArcReducedCost(node1,node2,apexes[arcrow][arccol],
arcrow,arccol,arcdir,nflow,nodes,
ground,&candidatebag,
&candidatebagnext,&candidatebagsize,
incrcosts,iscandidate,params);
} /* end if node2 below node1 and arc not on tree */
}else{
/* node2 is not on tree, so put it in correct bucket */
AddNewNode(node1,node2,arcdir,bkts,nflow,incrcosts,
arcrow,arccol,params);
} /* end if node2 on tree */
} /* end loop over node1 outgoing arcs */
/* move to next node in thread, break if we left the subtree */
node1=node1->next;
if(node1->level <= startlevel){
break;
}
}
} /* end if leavingchild!=NULL */
/* if we had an augmenting cycle */
/* we need to check outarcs from descendents of any cycle node */
/* (except apex, since apex potentials don't change) */
if(cyclecost<0){
/* check descendents of cycle children of apex */
while(TRUE){
/* firstfromnode, firsttonode may have changed */
if(firstfromnode!=NULL && firstfromnode->pred==cycleapex){
node1=firstfromnode;
firstfromnode=NULL;
}else if(firsttonode!=NULL && firsttonode->pred==cycleapex){
node1=firsttonode;
firsttonode=NULL;
}else{
break;
}
startlevel=node1->level;
/* loop over all descendents */
while(TRUE){
/* loop over outgoing arcs */
if(node1->row!=GROUNDROW){
arcnum=-5;
upperarcnum=-1;
}else{
arcnum=-1;
upperarcnum=ngroundarcs-1;
}
while(arcnum<upperarcnum){
node2=NeighborNode(node1,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,
nodesupp);
/* check for outcost updates or negative reduced costs */
if(node2->group>0){
if(apexes[arcrow][arccol]!=NULL
&& (node2->group!=node1->group
|| node1->group==apexlistbase)){
CheckArcReducedCost(node1,node2,apexes[arcrow][arccol],
arcrow,arccol,arcdir,nflow,nodes,
ground,&candidatebag,
&candidatebagnext,&candidatebagsize,
incrcosts,iscandidate,params);
}
}else{
AddNewNode(node1,node2,arcdir,bkts,nflow,incrcosts,
arcrow,arccol,params);
}
}
/* move to next node in thread, break if left the subtree */
/* but skip the remounted tree, since we checked it above */
node1=node1->next;
if(node1==to){
node1=skipthread;
}
if(node1->level <= startlevel){
break;
}
}
}
}
ipivots++;
} /* end if cyclecost<0 || outcostto<to->outcost */
} /* end of for loop over candidates in list */
/* this is needed only if we don't process all candidates above */
/* copy remaining candidates into candidatebag */
/*
while(candidatebagnext+(candidatelistlen-ncandidates)>candidatebagsize){
candidatebagsize+=CANDIDATEBAGSTEP;
candidatebag=ReAlloc(candidatebag,candidatebagsize*sizeof(candidateT));
}
for(i=ncandidates;i<candidatelistlen;i++){
candidatebag[candidatebagnext++]=candidatelist[i];
}
*/
/* display status */
fprintf(sp3,"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
"\b\b\b\b\b\b"
"Treesize: %-10ld Pivots: %-11ld Improvements: %-11ld",
treesize,ipivots,inondegen);
fflush(sp3);
} /* end of while loop on candidatebagnext */
} /* end while treesize<number of total nodes */
/* clean up: set pointers for outputs */
fprintf(sp3,"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
"\b\b\b\b\b\b"
"Treesize: %-10ld Pivots: %-11ld Improvements: %-11ld\n",
treesize,ipivots,inondegen);
fflush(sp3);
*candidatelistptr=candidatelist;
*candidatebagptr=candidatebag;
*candidatelistsizeptr=candidatelistsize;
*candidatebagsizeptr=candidatebagsize;
free(apexlist);
/* return the number of nondegenerate pivots (number of improvements) */
return(inondegen);
}
/* function: AddNewNode()
* ----------------------
* Adds a node to a bucket if it is not already in a bucket. Updates
* outcosts of to node if the new distance is less or if to's pred is
* from (then we have to do the update).
*/
void AddNewNode(nodeT *from, nodeT *to, long arcdir, bucketT *bkts,
long nflow, incrcostT **incrcosts, long arcrow, long arccol,
paramT *params){
long newoutcost;
newoutcost=from->outcost
+GetCost(incrcosts,arcrow,arccol,arcdir);
if(newoutcost<to->outcost || to->pred==from){
if(to->group==-1){ /* if to is already in a bucket */
if(to->outcost<bkts->maxind){
if(to->outcost>bkts->minind){
BucketRemove(to,to->outcost,bkts);
}else{
BucketRemove(to,bkts->minind,bkts);
}
}else{
BucketRemove(to,bkts->maxind,bkts);
}
}
to->outcost=newoutcost;
to->pred=from;
if(newoutcost<bkts->maxind){
if(newoutcost>bkts->minind){
BucketInsert(to,newoutcost,bkts);
if(newoutcost<bkts->curr){
bkts->curr=newoutcost;
}
}else{
BucketInsert(to,bkts->minind,bkts);
bkts->curr=bkts->minind;
}
}else{
BucketInsert(to,bkts->maxind,bkts);
}
to->group=-1;
}
}
/* function: CheckArcReducedCost()
* -------------------------------
* Given a from and to node, checks for negative reduced cost, and adds
* the arc to the entering arc candidate bag if one is found.
*/
void CheckArcReducedCost(nodeT *from, nodeT *to, nodeT *apex,
long arcrow, long arccol, long arcdir,
long nflow, nodeT **nodes, nodeT *ground,
candidateT **candidatebagptr,
long *candidatebagnextptr,
long *candidatebagsizeptr, incrcostT **incrcosts,
signed char **iscandidate, paramT *params){
long apexcost, fwdarcdist, revarcdist, violation;
nodeT *temp;
/* do nothing if already candidate */
/* illegal corner arcs have iscandidate=TRUE set ahead of time */
if(iscandidate[arcrow][arccol]){
return;
}
/* set the apex cost */
apexcost=apex->outcost+apex->incost;
/* check forward arc */
fwdarcdist=GetCost(incrcosts,arcrow,arccol,arcdir);
violation=fwdarcdist+from->outcost+to->incost-apexcost;
if(violation<0){
arcdir*=2; /* magnitude 2 for sorting */
}else{
revarcdist=GetCost(incrcosts,arcrow,arccol,-arcdir);
violation=revarcdist+to->outcost+from->incost-apexcost;
if(violation<0){
arcdir*=-2; /* magnitude 2 for sorting */
temp=from;
from=to;
to=temp;
}else{
violation=fwdarcdist+from->outcost-to->outcost;
if(violation>=0){
violation=revarcdist+to->outcost-from->outcost;
if(violation<0){
arcdir=-arcdir;
temp=from;
from=to;
to=temp;
}
}
}
}
/* see if we have a violation, and if so, add arc to candidate bag */
if(violation<0){
if((*candidatebagnextptr)>=(*candidatebagsizeptr)){
(*candidatebagsizeptr)+=CANDIDATEBAGSTEP;
(*candidatebagptr)=ReAlloc(*candidatebagptr,
(*candidatebagsizeptr)*sizeof(candidateT));
}
(*candidatebagptr)[*candidatebagnextptr].violation=violation;
(*candidatebagptr)[*candidatebagnextptr].from=from;
(*candidatebagptr)[*candidatebagnextptr].to=to;
(*candidatebagptr)[*candidatebagnextptr].arcrow=arcrow;
(*candidatebagptr)[*candidatebagnextptr].arccol=arccol;
(*candidatebagptr)[*candidatebagnextptr].arcdir=arcdir;
(*candidatebagnextptr)++;
iscandidate[arcrow][arccol]=TRUE;
}
}
/* function: InitTree()
* --------------------
*/
long InitTree(nodeT *source, nodeT **nodes, nodesuppT **nodesupp,
nodeT *ground, long ngroundarcs, bucketT *bkts, long nflow,
incrcostT **incrcosts, nodeT ***apexes,
signed char **iscandidate, long nnoderow, short *nnodesperrow,
long narcrow, short *narcsperrow, long nrow, long ncol,
paramT *params){
long row, col, arcnum, upperarcnum, arcrow, arccol, arcdir, nnodes;
nodeT *to;
/* loop over each node and initialize values */
nnodes=0;
for(row=0;row<nnoderow;row++){
for(col=0;col<nnodesperrow[row];col++){
nodes[row][col].group=0;
nodes[row][col].outcost=VERYFAR;
nodes[row][col].pred=NULL;
nnodes++;
}
}
/* initialize the ground node */
if(ground!=NULL){
ground->group=0;
ground->outcost=VERYFAR;
ground->pred=NULL;
nnodes++;
}
/* initialize arcs */
for(row=0;row<narcrow;row++){
for(col=0;col<narcsperrow[row];col++){
apexes[row][col]=NONTREEARC;
iscandidate[row][col]=FALSE;
}
}
/* if in grid mode, ground will exist */
if(ground!=NULL){
/* set iscandidate=TRUE for illegal corner arcs so they're never used */
iscandidate[nrow-1][0]=TRUE;
iscandidate[2*nrow-2][0]=TRUE;
iscandidate[nrow-1][ncol-2]=TRUE;
iscandidate[2*nrow-2][ncol-2]=TRUE;
}
/* put source on tree */
source->group=1;
source->outcost=0;
source->incost=0;
source->pred=NULL;
source->prev=source;
source->next=source;
source->level=0;
/* loop over outgoing arcs and add to buckets */
if(source->row!=GROUNDROW){
arcnum=-5;
upperarcnum=-1;
}else{
arcnum=-1;
upperarcnum=ngroundarcs-1;
}
while(arcnum<upperarcnum){
/* get node reached by outgoing arc */
to=NeighborNode(source,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,nodesupp);
/* add to node to bucket */
AddNewNode(source,to,arcdir,bkts,nflow,incrcosts,arcrow,arccol,params);
}
/* return the number of nodes in the network */
return(nnodes);
}
/* function: FindApex()
* --------------------
* Given pointers to two nodes on a spanning tree, the function finds
* and returns a pointer to their deepest common ancestor, the apex of
* a cycle formed by joining the two nodes with an arc.
*/
nodeT *FindApex(nodeT *from, nodeT *to){
if(from->level > to->level){
while(from->level != to->level){
from=from->pred;
}
}else{
while(from->level != to->level){
to=to->pred;
}
}
while(from != to){
from=from->pred;
to=to->pred;
}
return(from);
}
/* function: CandidateCompare()
* ----------------------------
* Compares the violations of candidate arcs for sorting. First checks
* if either candidate has an arcdir magnitude greater than 1, denoting
* an augmenting cycle. Augmenting candidates are always placed before
* non-augmenting candidates. Otherwise, returns positive if the first
* candidate has a greater (less negative) violation than the second, 0
* if they are the same, and negative otherwise.
*/
int CandidateCompare(const void *c1, const void *c2){
if(labs(((candidateT *)c1)->arcdir) > 1){
if(labs(((candidateT *)c2)->arcdir) < 2){
return(-1);
}
}else if(labs(((candidateT *)c2)->arcdir) > 1){
return(1);
}
return(((candidateT *)c1)->violation - ((candidateT *)c2)->violation);
/*
if(((candidateT *)c1)->violation > ((candidateT *)c2)->violation){
return(1);
}else if(((candidateT *)c1)->violation < ((candidateT *)c2)->violation){
return(-1);
}else{
return(0);
}
*/
}
/* function: NeighborNodeGrid()
* ----------------------------
* Return the neighboring node of the given node corresponding to the
* given arc number for a grid network with a ground node.
*/
nodeT *NeighborNodeGrid(nodeT *node1, long arcnum, long *upperarcnumptr,
nodeT **nodes, nodeT *ground, long *arcrowptr,
long *arccolptr, long *arcdirptr, long nrow,
long ncol, nodesuppT **nodesupp){
long row, col;
row=node1->row;
col=node1->col;
switch(arcnum){
case -4:
*arcrowptr=row;
*arccolptr=col+1;
*arcdirptr=1;
if(col==ncol-2){
return(ground);
}else{
return(&nodes[row][col+1]);
}
break;
case -3:
*arcrowptr=nrow+row;
*arccolptr=col;
*arcdirptr=1;
if(row==nrow-2){
return(ground);
}else{
return(&nodes[row+1][col]);
}
break;
case -2:
*arcrowptr=row;
*arccolptr=col;
*arcdirptr=-1;
if(col==0){
return(ground);
}else{
return(&nodes[row][col-1]);
}
break;
case -1:
*arcrowptr=nrow-1+row;
*arccolptr=col;
*arcdirptr=-1;
if(row==0){
return(ground);
}else{
return(&nodes[row-1][col]);
}
break;
default:
if(arcnum<nrow-1){
*arcrowptr=arcnum;
*arccolptr=0;
*arcdirptr=1;
return(&nodes[*arcrowptr][0]);
}else if(arcnum<2*(nrow-1)){
*arcrowptr=arcnum-(nrow-1);
*arccolptr=ncol-1;
*arcdirptr=-1;
return(&nodes[*arcrowptr][ncol-2]);
}else if(arcnum<2*(nrow-1)+ncol-3){
*arcrowptr=nrow-1;
*arccolptr=arcnum-2*(nrow-1)+1;
*arcdirptr=1;
return(&nodes[0][*arccolptr]);
}else{
*arcrowptr=2*nrow-2;
*arccolptr=arcnum-(2*(nrow-1)+ncol-3)+1;
*arcdirptr=-1;
return(&nodes[nrow-2][*arccolptr]);
}
break;
}
}
/* function: NeighborNodeNonGrid()
* -------------------------------
* Return the neighboring node of the given node corresponding to the
* given arc number for a nongrid network (ie, arbitrary topology).
*/
nodeT *NeighborNodeNonGrid(nodeT *node1, long arcnum, long *upperarcnumptr,
nodeT **nodes, nodeT *ground, long *arcrowptr,
long *arccolptr, long *arcdirptr, long nrow,
long ncol, nodesuppT **nodesupp){
long tilenum, nodenum;
scndryarcT *outarc;
/* set up */
tilenum=node1->row;
nodenum=node1->col;
*upperarcnumptr=nodesupp[tilenum][nodenum].noutarcs-5;
/* set the arc row (tilenumber) and column (arcnumber) */
outarc=nodesupp[tilenum][nodenum].outarcs[arcnum+4];
*arcrowptr=outarc->arcrow;
*arccolptr=outarc->arccol;
if(node1==outarc->from){
*arcdirptr=1;
}else{
*arcdirptr=-1;
}
/* return the neighbor node */
return(nodesupp[tilenum][nodenum].neighbornodes[arcnum+4]);
}
/* function: GetArcGrid()
* ----------------------
* Given a from node and a to node, sets pointers for indices into
* arc arrays, assuming primary (grid) network.
*/
void GetArcGrid(nodeT *from, nodeT *to, long *arcrow, long *arccol,
long *arcdir, long nrow, long ncol, nodesuppT **nodesupp){
long fromrow, fromcol, torow, tocol;
fromrow=from->row;
fromcol=from->col;
torow=to->row;
tocol=to->col;
if(fromcol==tocol-1){ /* normal arcs (neither endpoint ground) */
*arcrow=fromrow;
*arccol=fromcol+1;
*arcdir=1;
}else if(fromcol==tocol+1){
*arcrow=fromrow;
*arccol=fromcol;
*arcdir=-1;
}else if(fromrow==torow-1){
*arcrow=fromrow+1+nrow-1;
*arccol=fromcol;
*arcdir=1;
}else if(fromrow==torow+1){
*arcrow=fromrow+nrow-1;
*arccol=fromcol;
*arcdir=-1;
}else if(fromcol==0){ /* arcs to ground */
*arcrow=fromrow;
*arccol=0;
*arcdir=-1;
}else if(fromcol==ncol-2){
*arcrow=fromrow;
*arccol=ncol-1;
*arcdir=1;
}else if(fromrow==0){
*arcrow=nrow-1;
*arccol=fromcol;
*arcdir=-1;
}else if(fromrow==nrow-2){
*arcrow=2*(nrow-1);
*arccol=fromcol;
*arcdir=1;
}else if(tocol==0){ /* arcs from ground */
*arcrow=torow;
*arccol=0;
*arcdir=1;
}else if(tocol==ncol-2){
*arcrow=torow;
*arccol=ncol-1;
*arcdir=-1;
}else if(torow==0){
*arcrow=nrow-1;
*arccol=tocol;
*arcdir=1;
}else{
*arcrow=2*(nrow-1);
*arccol=tocol;
*arcdir=-1;
}
}
/* function: GetArcNonGrid()
* -------------------------
* Given a from node and a to node, sets pointers for indices into
* arc arrays, assuming secondary (arbitrary topology) network.
*/
void GetArcNonGrid(nodeT *from, nodeT *to, long *arcrow, long *arccol,
long *arcdir, long nrow, long ncol, nodesuppT **nodesupp){
long tilenum, nodenum, arcnum;
scndryarcT *outarc;
/* get tile and node numbers for from node */
tilenum=from->row;
nodenum=from->col;
/* loop over all outgoing arcs of from node */
arcnum=0;
while(TRUE){
outarc=nodesupp[tilenum][nodenum].outarcs[arcnum++];
if(outarc->from==to){
*arcrow=outarc->arcrow;
*arccol=outarc->arccol;
*arcdir=-1;
return;
}else if(outarc->to==to){
*arcrow=outarc->arcrow;
*arccol=outarc->arccol;
*arcdir=1;
return;
}
}
}
/* Function: NonDegenUpdateChildren()
* ----------------------------------
* Updates potentials and groups of all childredn along an augmenting path,
* until a stop node is hit.
*/
void NonDegenUpdateChildren(nodeT *startnode, nodeT *lastnode,
nodeT *nextonpath, long dgroup,
long ngroundarcs, long nflow, nodeT **nodes,
nodesuppT **nodesupp, nodeT *ground,
nodeT ***apexes, incrcostT **incrcosts,
long nrow, long ncol, paramT *params){
nodeT *node1, *node2;
long dincost, doutcost, arcnum, upperarcnum, startlevel;
long group1, pathgroup, arcrow, arccol, arcdir;
/* loop along flow path */
node1=startnode;
pathgroup=lastnode->group;
while(node1!=lastnode){
/* update potentials along the flow path by calculating arc distances */
node2=nextonpath;
GetArc(node2->pred,node2,&arcrow,&arccol,&arcdir,nrow,ncol,nodesupp);
doutcost=node1->outcost - node2->outcost
+ GetCost(incrcosts,arcrow,arccol,arcdir);
node2->outcost+=doutcost;
dincost=node1->incost - node2->incost
+ GetCost(incrcosts,arcrow,arccol,-arcdir);
node2->incost+=dincost;
node2->group=node1->group+dgroup;
/* update potentials of children of this node in the flow path */
node1=node2;
if(node1->row!=GROUNDROW){
arcnum=-5;
upperarcnum=-1;
}else{
arcnum=-1;
upperarcnum=ngroundarcs-1;
}
while(arcnum<upperarcnum){
node2=NeighborNode(node1,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,nodesupp);
if(node2->pred==node1 && node2->group>0){
if(node2->group==pathgroup){
nextonpath=node2;
}else{
startlevel=node2->level;
group1=node1->group;
while(TRUE){
node2->group=group1;
node2->incost+=dincost;
node2->outcost+=doutcost;
node2=node2->next;
if(node2->level <= startlevel){
break;
}
}
}
}
}
}
}
/* function: InitNetowrk()
* -----------------------
*/
void InitNetwork(short **flows, long *ngroundarcsptr, long *ncycleptr,
long *nflowdoneptr, long *mostflowptr, long *nflowptr,
long *candidatebagsizeptr, candidateT **candidatebagptr,
long *candidatelistsizeptr, candidateT **candidatelistptr,
signed char ***iscandidateptr, nodeT ****apexesptr,
bucketT **bktsptr, long *iincrcostfileptr,
incrcostT ***incrcostsptr, nodeT ***nodesptr, nodeT *ground,
long *nnoderowptr, short **nnodesperrowptr, long *narcrowptr,
short **narcsperrowptr, long nrow, long ncol,
signed char *notfirstloopptr, totalcostT *totalcostptr,
paramT *params){
long i;
/* get and initialize memory for nodes */
if(ground!=NULL && *nodesptr==NULL){
*nodesptr=(nodeT **)Get2DMem(nrow-1,ncol-1,sizeof(nodeT *),sizeof(nodeT));
InitNodeNums(nrow-1,ncol-1,*nodesptr,ground);
}
/* take care of ambiguous flows to ground at corners */
if(ground!=NULL){
flows[0][0]+=flows[nrow-1][0];
flows[nrow-1][0]=0;
flows[0][ncol-1]-=flows[nrow-1][ncol-2];
flows[nrow-1][ncol-2]=0;
flows[nrow-2][0]-=flows[2*nrow-2][0];
flows[2*nrow-2][0]=0;
flows[nrow-2][ncol-1]+=flows[2*nrow-2][ncol-2];
flows[2*nrow-2][ncol-2]=0;
}
/* initialize network solver variables */
*ncycleptr=0;
*nflowptr=1;
*candidatebagsizeptr=INITARRSIZE;
*candidatebagptr=MAlloc(*candidatebagsizeptr*sizeof(candidateT));
*candidatelistsizeptr=INITARRSIZE;
*candidatelistptr=MAlloc(*candidatelistsizeptr*sizeof(candidateT));
if(ground!=NULL){
*nflowdoneptr=0;
*mostflowptr=Short2DRowColAbsMax(flows,nrow,ncol);
if(*mostflowptr*params->nshortcycle>LARGESHORT){
fprintf(sp1,"Maximum flow on network: %ld\n",*mostflowptr);
fprintf(sp0,"((Maximum flow) * NSHORTCYCLE) too large\nAbort\n");
exit(ABNORMAL_EXIT);
}
if(ncol>2){
*ngroundarcsptr=2*(nrow+ncol-2)-4; /* don't include corner column arcs */
}else{
*ngroundarcsptr=2*(nrow+ncol-2)-2;
}
*iscandidateptr=(signed char **)Get2DRowColMem(nrow,ncol,
sizeof(signed char *),
sizeof(signed char));
*apexesptr=(nodeT ***)Get2DRowColMem(nrow,ncol,sizeof(nodeT **),
sizeof(nodeT *));
}
/* set up buckets for TreeSolve (MSTInitFlows() has local set of buckets) */
*bktsptr=MAlloc(sizeof(bucketT));
if(ground!=NULL){
(*bktsptr)->minind=-LRound((params->maxcost+1)*(nrow+ncol)
*NEGBUCKETFRACTION);
(*bktsptr)->maxind=LRound((params->maxcost+1)*(nrow+ncol)
*POSBUCKETFRACTION);
}else{
(*bktsptr)->minind=-LRound((params->maxcost+1)*(nrow)
*NEGBUCKETFRACTION);
(*bktsptr)->maxind=LRound((params->maxcost+1)*(nrow)
*POSBUCKETFRACTION);
}
(*bktsptr)->size=(*bktsptr)->maxind-(*bktsptr)->minind+1;
(*bktsptr)->bucketbase=(nodeT **)MAlloc((*bktsptr)->size*sizeof(nodeT *));
(*bktsptr)->bucket=&((*bktsptr)->bucketbase[-(*bktsptr)->minind]);
for(i=0;i<(*bktsptr)->size;i++){
(*bktsptr)->bucketbase[i]=NULL;
}
/* get memory for incremental cost arrays */
*iincrcostfileptr=0;
if(ground!=NULL){
(*incrcostsptr)=(incrcostT **)Get2DRowColMem(nrow,ncol,sizeof(incrcostT *),
sizeof(incrcostT));
}
/* set number of nodes and arcs per row */
if(ground!=NULL){
(*nnoderowptr)=nrow-1;
(*nnodesperrowptr)=(short *)MAlloc((nrow-1)*sizeof(short));
for(i=0;i<nrow-1;i++){
(*nnodesperrowptr)[i]=ncol-1;
}
(*narcrowptr)=2*nrow-1;
(*narcsperrowptr)=(short *)MAlloc((2*nrow-1)*sizeof(short));
for(i=0;i<nrow-1;i++){
(*narcsperrowptr)[i]=ncol;
}
for(i=nrow-1;i<2*nrow-1;i++){
(*narcsperrowptr)[i]=ncol-1;
}
}
/* initialize variables for main optimizer loop */
(*notfirstloopptr)=FALSE;
(*totalcostptr)=INITTOTALCOST;
}
/* function: InitNodeNums()
* ------------------------
*/
void InitNodeNums(long nrow, long ncol, nodeT **nodes, nodeT *ground){
long row, col;
/* loop over each element and initialize values */
for(row=0;row<nrow;row++){
for(col=0;col<ncol;col++){
nodes[row][col].row=row;
nodes[row][col].col=col;
}
}
/* initialize the ground node */
if(ground!=NULL){
ground->row=GROUNDROW;
ground->col=GROUNDCOL;
}
}
/* function: InitBuckets()
* -----------------------
*/
void InitBuckets(bucketT *bkts, nodeT *source, long nbuckets){
long i;
/* set up bucket array parameters */
bkts->curr=0;
bkts->wrapped=FALSE;
/* initialize the buckets */
for(i=0;i<nbuckets;i++){
bkts->bucketbase[i]=NULL;
}
/* put the source in the zeroth distance index bucket */
bkts->bucket[0]=source;
source->next=NULL;
source->prev=NULL;
source->group=INBUCKET;
source->outcost=0;
}
/* function: InitNodes()
* ---------------------
*/
void InitNodes(long nnrow, long nncol, nodeT **nodes, nodeT *ground){
long row, col;
/* loop over each element and initialize values */
for(row=0;row<nnrow;row++){
for(col=0;col<nncol;col++){
nodes[row][col].group=NOTINBUCKET;
nodes[row][col].outcost=VERYFAR;
nodes[row][col].pred=NULL;
}
}
/* initialize the ground node */
if(ground!=NULL){
ground->group=NOTINBUCKET;
ground->outcost=VERYFAR;
ground->pred=NULL;
}
}
/* function: BucketInsert()
* ------------------------
*/
void BucketInsert(nodeT *node, long ind, bucketT *bkts){
/* put node at beginning of bucket list */
node->next=bkts->bucket[ind];
if((bkts->bucket[ind])!=NULL){
bkts->bucket[ind]->prev=node;
}
bkts->bucket[ind]=node;
node->prev=NULL;
/* mark node in bucket array */
node->group=INBUCKET;
}
/* function: BucketRemove()
* ------------------------
*/
void BucketRemove(nodeT *node, long ind, bucketT *bkts){
/* remove node from doubly linked list */
if((node->next)!=NULL){
node->next->prev=node->prev;
}
if(node->prev!=NULL){
node->prev->next=node->next;
}else if(node->next==NULL){
bkts->bucket[ind]=NULL;
}else{
bkts->bucket[ind]=node->next;
}
}
/* function: ClosestNode()
* -----------------------
*/
nodeT *ClosestNode(bucketT *bkts){
nodeT *node;
/* find the first bucket with nodes in it */
while(TRUE){
/* see if we got to the last bucket */
if((bkts->curr)>(bkts->maxind)){
return(NULL);
}
/* see if we found a nonempty bucket; if so, return it */
if((bkts->bucket[bkts->curr])!=NULL){
node=bkts->bucket[bkts->curr];
node->group=ONTREE;
bkts->bucket[bkts->curr]=node->next;
if((node->next)!=NULL){
node->next->prev=NULL;
}
return(node);
}
/* move to next bucket */
bkts->curr++;
}
}
/* function: ClosestNodeCircular()
* -------------------------------
* Similar to ClosestNode(), but assumes circular buckets. This
* function should NOT be used if negative arc weights exist on the
* network; initial value of bkts->minind should always be zero.
*/
nodeT *ClosestNodeCircular(bucketT *bkts){
nodeT *node;
/* find the first bucket with nodes in it */
while(TRUE){
/* see if we got to the last bucket */
if((bkts->curr+bkts->minind)>(bkts->maxind)){
if(bkts->wrapped){
bkts->wrapped=FALSE;
bkts->curr=0;
bkts->minind+=bkts->size;
bkts->maxind+=bkts->size;
}else{
return(NULL);
}
}
/* see if we found a nonempty bucket; if so, return it */
if((bkts->bucket[bkts->curr])!=NULL){
node=bkts->bucket[bkts->curr];
node->group=ONTREE;
bkts->bucket[bkts->curr]=node->next;
if((node->next)!=NULL){
node->next->prev=NULL;
}
return(node);
}
/* move to next bucket */
bkts->curr++;
}
}
/* function: MinOutCostNode()
* --------------------------
* Similar to ClosestNode(), but always returns closest node even if its
* outcost is less than the minimum bucket index. Does not handle circular
* buckets. Does not handle no nodes left condition (this should be handled
* by calling function).
*/
nodeT *MinOutCostNode(bucketT *bkts){
long minoutcost;
nodeT *node1, *node2;
/* move to next non-empty bucket */
while(bkts->curr<bkts->maxind && bkts->bucket[bkts->curr]==NULL){
bkts->curr++;
}
/* scan the whole bucket if it is the overflow or underflow bag */
if(bkts->curr==bkts->minind || bkts->curr==bkts->maxind){
node2=bkts->bucket[bkts->curr];
node1=node2;
minoutcost=node1->outcost;
while(node2!=NULL){
if(node2->outcost<minoutcost){
minoutcost=node2->outcost;
node1=node2;
}
node2=node2->next;
}
BucketRemove(node1,bkts->curr,bkts);
}else{
node1=bkts->bucket[bkts->curr];
bkts->bucket[bkts->curr]=node1->next;
if(node1->next!=NULL){
node1->next->prev=NULL;
}
}
return(node1);
}
/* function: SelectSource()
* ------------------------
* If params->sourcemode is zero, the ground is returned as the source.
* Otherwise, the returned source is the endpoint of the longest chain of
* arcs carrying at least nflow units of flow. This function does
* check for the case where two arcs both carry nflow into or out of a node,
* but if there are flow cycles (not unexpected for nonlinear costs), the
* longest chain is not guaranteed. Which end of the longest chain is
* determined by the sign of params->sourcemode (should be 1 or -1 if not 0).
*/
nodeT *SelectSource(nodeT **nodes, nodeT *ground, long nflow,
short **flows, long ngroundarcs,
long nrow, long ncol, paramT *params){
long row, col, maxflowlength, arcnum, upperarcnum;
long arcrow, arccol, arcdir, endptsign;
signed char checknode;
nodeT *source, *node1, *node2, *nextnode;
nodesuppT **nodesupp;
/* if sourcemode==0, return ground node; otherwise, it should be 1 or -1 */
if(!params->sourcemode){
return(ground);
}else{
endptsign=params->sourcemode;
}
/* initialize variables */
/* group: 0=unvisited, 1=descended, 2=done */
/* outcost: longest distance to a chain end */
/* pred: parent node */
nodesupp=NULL;
source=ground;
maxflowlength=0;
ground->group=0;
ground->outcost=0;
ground->pred=NULL;
for(row=0;row<nrow-1;row++){
for(col=0;col<ncol-1;col++){
nodes[row][col].group=0;
nodes[row][col].outcost=0;
nodes[row][col].pred=NULL;
}
}
/* loop over all nodes (upper row limit is nrow-1 so we can check ground) */
for(row=0;row<nrow;row++){
for(col=0;col<ncol-1;col++){
/* set the current node */
if(row!=nrow-1){
node1=&nodes[row][col];
}else{
if(col==0){
node1=ground;
}else{
break;
}
}
/* see if this node is an endpoint */
checknode=FALSE;
if(!node1->group){
if(node1!=ground){
arcnum=-5;
upperarcnum=-1;
}else{
arcnum=-1;
upperarcnum=ngroundarcs-1;
}
while(arcnum<upperarcnum){
node2=NeighborNode(node1,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,nodesupp);
/* node is not beginning of a chain (may be the end, though) */
if(-endptsign*arcdir*flows[arcrow][arccol] >= nflow){
checknode=FALSE;
break;
}
/* node may be beginning of a chain */
if(endptsign*arcdir*flows[arcrow][arccol] >= nflow){
checknode=TRUE;
}
}
}
/* if it is an endpoint, trace the flow and determine longest chain */
if(checknode){
/* loop until we've walked the whole tree */
nextnode=node1;
while(TRUE){
node1=nextnode;
nextnode=NULL;
/* loop over all outgoing arcs */
if(node1!=ground){
arcnum=-5;
upperarcnum=-1;
}else{
arcnum=-1;
upperarcnum=ngroundarcs-1;
}
while(arcnum<upperarcnum){
node2=NeighborNode(node1,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,nodesupp);
/* see if next node is or should be on tree */
/* otherwise, keep node if it is predecessor, but keep looping */
if(endptsign*arcdir*flows[arcrow][arccol] >= nflow){
if(node2->group==2){
if(node2->outcost+1 > node1->outcost){
node1->outcost=node2->outcost+1;
}
}else if(node2->group==0){
nextnode=node2;
break;
}
}else if(node2==node1->pred){
nextnode=node2;
}
}
/* we are back to the root if we didn't find any eligible nodes */
if(nextnode==NULL){
/* see if the tree root should be the new source */
if(node1->outcost > maxflowlength){
source=node1;
maxflowlength=node1->outcost;
}
node1->group=2;
break;
}
/* if nextnode is pred, mark current node and go back up the tree */
if(nextnode->group==1){
node1->group=2;
}else{
node1->group=1;
nextnode->pred=node1;
}
}
}
}
}
/* return source */
return(source);
}
/* function: GetCost()
* -------------------
* Returns incremental flow cost for current flow increment dflow from
* lookup array.
*/
short GetCost(incrcostT **incrcosts, long arcrow, long arccol,
long arcdir){
/* look up cost and return it for the appropriate arc direction */
/* we may want add a check here for clipped incremental costs */
if(arcdir>0){
return(incrcosts[arcrow][arccol].poscost);
}else{
return(incrcosts[arcrow][arccol].negcost);
}
}
/* function: ReCalcCost()
* ----------------------
* Updates the incremental cost for an arc.
*/
long ReCalcCost(void **costs, incrcostT **incrcosts, long flow,
long arcrow, long arccol, long nflow, long nrow,
paramT *params){
long poscost, negcost, iclipped;
/* calculate new positive and negative nflow costs, as long ints */
CalcCost(costs,flow,arcrow,arccol,nflow,nrow,params,
&poscost,&negcost);
/* clip costs to short int */
iclipped=0;
if(poscost>LARGESHORT){
incrcosts[arcrow][arccol].poscost=LARGESHORT;
iclipped++;
}else{
if(poscost<-LARGESHORT){
incrcosts[arcrow][arccol].poscost=-LARGESHORT;
iclipped++;
}else{
incrcosts[arcrow][arccol].poscost=poscost;
}
}
if(negcost>LARGESHORT){
incrcosts[arcrow][arccol].negcost=LARGESHORT;
iclipped++;
}else{
if(negcost<-LARGESHORT){
incrcosts[arcrow][arccol].negcost=-LARGESHORT;
iclipped++;
}else{
incrcosts[arcrow][arccol].negcost=negcost;
}
}
/* return the number of clipped incremental costs (0, 1, or 2) */
return(iclipped);
}
/* function: SetupIncrFlowCosts()
* ------------------------------
* Calculates the costs for positive and negative dflow flow increment
* if there is zero flow on the arc.
*/
void SetupIncrFlowCosts(void **costs, incrcostT **incrcosts, short **flows,
long nflow, long nrow, long narcrow,
short *narcsperrow, paramT *params){
long arcrow, arccol, iclipped, narcs;
char pl[2];
/* loop over all rows and columns */
narcs=0;
iclipped=0;
for(arcrow=0;arcrow<narcrow;arcrow++){
narcs+=narcsperrow[arcrow];
for(arccol=0;arccol<narcsperrow[arcrow];arccol++){
/* calculate new positive and negative nflow costs, as long ints */
iclipped+=ReCalcCost(costs,incrcosts,flows[arcrow][arccol],
arcrow,arccol,nflow,nrow,params);
}
}
/* print overflow warning if applicable */
if(iclipped){
if(iclipped>1){
strcpy(pl,"s");
}else{
strcpy(pl,"");
}
fprintf(sp0,"%ld incremental cost%s clipped to avoid overflow (%.3f%%)\n",
iclipped,pl,((double )iclipped)/(2*narcs));
}
}
/* function: EvaluateTotalCost()
* -----------------------------
* Computes the total cost of the flow array and prints it out. Pass nrow
* and ncol if in grid mode (primary network), or pass nrow=ntiles and
* ncol=0 for nongrid mode (secondary network).
*/
totalcostT EvaluateTotalCost(void **costs, short **flows, long nrow, long ncol,
short *narcsperrow,paramT *params){
totalcostT rowcost, totalcost;
long row, col, maxrow, maxcol;
/* sum cost for each row and column arc */
totalcost=0;
if(ncol){
maxrow=2*nrow-1;
}else{
maxrow=nrow;
}
for(row=0;row<maxrow;row++){
rowcost=0;
if(ncol){
if(row<nrow-1){
maxcol=ncol;
}else{
maxcol=ncol-1;
}
}else{
maxcol=narcsperrow[row];
}
for(col=0;col<maxcol;col++){
rowcost+=EvalCost(costs,flows,row,col,nrow,params);
}
totalcost+=rowcost;
}
return(totalcost);
}
/* function: MSTInitFlows()
* ------------------------
* Initializes the flow on a the network using minimum spanning tree
* algorithm.
*/
void MSTInitFlows(float **wrappedphase, short ***flowsptr,
short **mstcosts, long nrow, long ncol,
nodeT ***nodesptr, nodeT *ground, long maxflow){
long row, col, i, maxcost;
signed char **residue, **arcstatus;
short **flows;
nodeT *source;
bucketT bkts[1];
/* get and initialize memory for ground, nodes, buckets, and child array */
*nodesptr=(nodeT **)Get2DMem(nrow-1,ncol-1,sizeof(nodeT *),sizeof(nodeT));
InitNodeNums(nrow-1,ncol-1,*nodesptr,ground);
/* find maximum cost */
maxcost=0;
for(row=0;row<2*nrow-1;row++){
if(row<nrow-1){
i=ncol;
}else{
i=ncol-1;
}
for(col=0;col<i;col++){
if(mstcosts[row][col]>maxcost
&& !((row==nrow-1 || 2*nrow-2) && (col==0 || col==ncol-2))){
maxcost=mstcosts[row][col];
}
}
}
/* get memory for buckets and arc status */
bkts->size=LRound((maxcost+1)*(nrow+ncol+1));
bkts->bucketbase=(nodeT **)MAlloc(bkts->size*sizeof(nodeT *));
bkts->minind=0;
bkts->maxind=bkts->size-1;
bkts->bucket=bkts->bucketbase;
arcstatus=(signed char **)Get2DRowColMem(nrow,ncol,sizeof(signed char *),
sizeof(signed char));
/* calculate phase residues (integer numbers of cycles) */
fprintf(sp1,"Initializing flows with MST algorithm\n");
residue=(signed char **)Get2DMem(nrow-1,ncol-1,sizeof(signed char *),
sizeof(signed char));
CycleResidue(wrappedphase,residue,nrow,ncol);
/* get memory for flow arrays */
(*flowsptr)=(short **)Get2DRowColZeroMem(nrow,ncol,
sizeof(short *),sizeof(short));
flows=*flowsptr;
/* loop until no flows exceed the maximum flow */
fprintf(sp2,"Running approximate minimum spanning tree solver\n");
while(TRUE){
/* set up the source to be the first non-zero residue that we find */
source=NULL;
for(row=0;row<nrow-1 && source==NULL;row++){
for(col=0;col<ncol-1 && source==NULL;col++){
if(residue[row][col]){
source=&(*nodesptr)[row][col];
}
}
}
if(source==NULL){
fprintf(sp1,"No residues found\n");
break;
}
/* initialize data structures */
InitNodes(nrow-1,ncol-1,*nodesptr,ground);
InitBuckets(bkts,source,bkts->size);
/* solve the mst problem */
SolveMST(*nodesptr,source,ground,bkts,mstcosts,residue,arcstatus,
nrow,ncol);
/* find flows on minimum tree (only one feasible flow exists) */
DischargeTree(source,mstcosts,flows,residue,arcstatus,
*nodesptr,ground,nrow,ncol);
/* do pushes to clip the flows and make saturated arcs ineligible */
/* break out of loop if there is no flow greater than the limit */
if(ClipFlow(residue,flows,mstcosts,nrow,ncol,maxflow)){
break;
}
}
/* free memory and return */
Free2DArray((void **)residue,nrow-1);
Free2DArray((void **)arcstatus,2*nrow-1);
Free2DArray((void **)mstcosts,2*nrow-1);
free(bkts->bucketbase);
return;
}
/* function: SolveMST()
* --------------------
* Finds tree which spans all residue nodes of approximately minimal length.
* Note that this function may produce a Steiner tree (tree may split at
* non-residue node), though finding the exactly minimum Steiner tree is
* NP-hard. This function uses Prim's algorithm, nesting Dijkstra's
* shortest path algorithm in each iteration to find next closest residue
* node to tree. See Ahuja, Orlin, and Magnanti 1993 for details.
*
* Dijkstra implementation and some associated functions adapted from SPLIB
* shortest path codes written by Cherkassky, Goldberg, and Radzik.
*/
void SolveMST(nodeT **nodes, nodeT *source, nodeT *ground,
bucketT *bkts, short **mstcosts, signed char **residue,
signed char **arcstatus, long nrow, long ncol){
nodeT *from, *to, *pathfrom, *pathto;
nodesuppT **nodesupp;
long fromdist, newdist, arcdist, ngroundarcs, groundcharge;
long fromrow, fromcol, row, col, arcnum, upperarcnum, maxcol;
long pathfromrow, pathfromcol;
long arcrow, arccol, arcdir;
/* initialize some variables */
nodesupp=NULL;
/* calculate the number of ground arcs */
ngroundarcs=2*(nrow+ncol-2)-4;
/* calculate charge on ground */
groundcharge=0;
for(row=0;row<nrow-1;row++){
for(col=0;col<ncol-1;col++){
groundcharge-=residue[row][col];
}
}
/* initialize arc status array */
for(arcrow=0;arcrow<2*nrow-1;arcrow++){
if(arcrow<nrow-1){
maxcol=ncol;
}else{
maxcol=ncol-1;
}
for(arccol=0;arccol<maxcol;arccol++){
arcstatus[arcrow][arccol]=0;
}
}
/* loop until there are no more nodes in any bucket */
while((from=ClosestNode(bkts))!=NULL){
/* info for current node */
fromrow=from->row;
fromcol=from->col;
/* if we found a residue */
if(((fromrow!=GROUNDROW && residue[fromrow][fromcol]) ||
(fromrow==GROUNDROW && groundcharge)) && from!=source){
/* set node and its predecessor */
pathto=from;
pathfrom=from->pred;
/* go back and make arcstatus -1 along path */
while(TRUE){
/* give to node zero distance label */
pathto->outcost=0;
/* get arc indices for arc between pathfrom and pathto */
GetArc(pathfrom,pathto,&arcrow,&arccol,&arcdir,nrow,ncol,nodesupp);
/* set arc status to -1 to mark arc on tree */
arcstatus[arcrow][arccol]=-1;
/* stop when we get to a residue */
pathfromrow=pathfrom->row;
pathfromcol=pathfrom->col;
if((pathfromrow!=GROUNDROW && residue[pathfromrow][pathfromcol])
|| (pathfromrow==GROUNDROW && groundcharge)){
break;
}
/* move up to previous node pair in path */
pathto=pathfrom;
pathfrom=pathfrom->pred;
} /* end while loop marking costs on path */
} /* end if we found a residue */
/* set a variable for from node's distance */
fromdist=from->outcost;
/* scan from's neighbors */
if(fromrow!=GROUNDROW){
arcnum=-5;
upperarcnum=-1;
}else{
arcnum=-1;
upperarcnum=ngroundarcs-1;
}
while(arcnum<upperarcnum){
/* get row, col indices and distance of next node */
to=NeighborNode(from,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,nodesupp);
row=to->row;
col=to->col;
/* get cost of arc to new node (if arc on tree, cost is 0) */
if(arcstatus[arcrow][arccol]<0){
arcdist=0;
}else if((arcdist=mstcosts[arcrow][arccol])==LARGESHORT){
arcdist=VERYFAR;
}
/* compare distance of new nodes to temp labels */
if((newdist=fromdist+arcdist)<(to->outcost)){
/* if to node is already in a bucket, remove it */
if(to->group==INBUCKET){
if(to->outcost<bkts->maxind){
BucketRemove(to,to->outcost,bkts);
}else{
BucketRemove(to,bkts->maxind,bkts);
}
}
/* update to node */
to->outcost=newdist;
to->pred=from;
/* insert to node into appropriate bucket */
if(newdist<bkts->maxind){
BucketInsert(to,newdist,bkts);
if(newdist<bkts->curr){
bkts->curr=newdist;
}
}else{
BucketInsert(to,bkts->maxind,bkts);
}
} /* end if newdist < old dist */
} /* end loop over outgoing arcs */
} /* end while ClosestNode()!=NULL */
}
/* function: DischargeTree()
* -------------------------
* Does depth-first search on result tree from SolveMST. Integrates
* charges from tree leaves back up to set arc flows. This implementation
* is non-recursive; a recursive implementation might be faster, but
* would also use much more stack memory. This method is equivalent to
* walking the tree, so it should be nore more than a factor of 2 slower.
*/
long DischargeTree(nodeT *source, short **mstcosts, short **flows,
signed char **residue, signed char **arcstatus,
nodeT **nodes, nodeT *ground, long nrow, long ncol){
long row, col, todir, arcrow, arccol, arcdir;
long arcnum, upperarcnum, ngroundarcs;
nodeT *from, *to, *nextnode;
nodesuppT **nodesupp;
/* set up */
/* use group member of node structure to temporarily store charge */
nextnode=source;
ground->group=0;
for(row=0;row<nrow-1;row++){
for(col=0;col<ncol-1;col++){
nodes[row][col].group=residue[row][col];
ground->group-=residue[row][col];
}
}
ngroundarcs=2*(nrow+ncol-2)-4;
nodesupp=NULL;
/* keep looping unitl we've walked the entire tree */
while(TRUE){
from=nextnode;
nextnode=NULL;
/* loop over outgoing arcs from this node */
if(from->row!=GROUNDROW){
arcnum=-5;
upperarcnum=-1;
}else{
arcnum=-1;
upperarcnum=ngroundarcs-1;
}
while(arcnum<upperarcnum){
/* get row, col indices and distance of next node */
to=NeighborNode(from,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,nodesupp);
/* see if the arc is on the tree and if it has been followed yet */
if(arcstatus[arcrow][arccol]==-1){
/* arc has not yet been followed: move down the tree */
nextnode=to;
row=arcrow;
col=arccol;
break;
}else if(arcstatus[arcrow][arccol]==-2){
/* arc has already been followed and leads back up the tree: */
/* save it, but keep looking for downwards arc */
nextnode=to;
row=arcrow;
col=arccol;
todir=arcdir;
}
}
/* break if no unfollowed arcs (ie, we are done examining the tree) */
if(nextnode==NULL){
break;
}
/* if we found leaf and we're moving back up the tree, do a push */
/* otherwise, just mark the path by decrementing arcstatus */
if((--arcstatus[row][col])==-3){
flows[row][col]+=todir*from->group;
nextnode->group+=from->group;
from->group=0;
}
}
/* finish up */
return(from->group);
} /* end of DischargeTree() */
/* function: ClipFlow()
* ---------------------
* Given a flow, clips flow magnitudes to a computed limit, resets
* residues so sum of solution of network problem with new residues
* and solution of clipped problem give total solution. Upper flow limit
* is 2/3 the maximum flow on the network or the passed value maxflow,
* whichever is greater. Clipped flow arcs get costs of passed variable
* maxcost. Residues should have been set to zero by DischargeTree().
*/
signed char ClipFlow(signed char **residue, short **flows,
short **mstcosts, long nrow, long ncol,
long maxflow){
long row, col, cliplimit, maxcol, excess, tempcharge, sign;
long mostflow, maxcost;
/* find maximum flow */
mostflow=Short2DRowColAbsMax(flows,nrow,ncol);
/* if there is no flow greater than the maximum, return TRUE */
if(mostflow<=maxflow){
return(TRUE);
}
fprintf(sp2,"Maximum flow on network: %ld\n",mostflow);
/* set upper flow limit */
cliplimit=(long )ceil(mostflow*CLIPFACTOR)+1;
if(maxflow>cliplimit){
cliplimit=maxflow;
}
/* find maximum cost (excluding ineligible corner arcs) */
maxcost=0;
for(row=0;row<2*nrow-1;row++){
if(row<nrow-1){
maxcol=ncol;
}else{
maxcol=ncol-1;
}
for(col=0;col<maxcol;col++){
if(mstcosts[row][col]>maxcost && mstcosts[row][col]<LARGESHORT){
maxcost=mstcosts[row][col];
}
}
}
/* set the new maximum cost and make sure it doesn't overflow short int */
maxcost+=INITMAXCOSTINCR;
if(maxcost>=LARGESHORT){
fprintf(sp0,"WARNING: escaping ClipFlow loop to prevent cost overflow\n");
return(TRUE);
}
/* clip flows and do pushes */
for(row=0;row<2*nrow-1;row++){
if(row<nrow-1){
maxcol=ncol;
}else{
maxcol=ncol-1;
}
for(col=0;col<maxcol;col++){
if(labs(flows[row][col])>cliplimit){
if(flows[row][col]>0){
sign=1;
excess=flows[row][col]-cliplimit;
}else{
sign=-1;
excess=flows[row][col]+cliplimit;
}
if(row<nrow-1){
if(col!=0){
tempcharge=residue[row][col-1]+excess;
if(tempcharge>MAXRES || tempcharge<MINRES){
fprintf(sp0,"Overflow of residue data type\nAbort\n");
exit(ABNORMAL_EXIT);
}
residue[row][col-1]=tempcharge;
}
if(col!=ncol-1){
tempcharge=residue[row][col]-excess;
if(tempcharge<MINRES || tempcharge>MAXRES){
fprintf(sp0,"Overflow of residue data type\nAbort\n");
exit(ABNORMAL_EXIT);
}
residue[row][col]=tempcharge;
}
}else{
if(row!=nrow-1){
tempcharge=residue[row-nrow][col]+excess;
if(tempcharge>MAXRES || tempcharge<MINRES){
fprintf(sp0,"Overflow of residue data type\nAbort\n");
exit(ABNORMAL_EXIT);
}
residue[row-nrow][col]=tempcharge;
}
if(row!=2*nrow-2){
tempcharge=residue[row-nrow+1][col]-excess;
if(tempcharge<MINRES || tempcharge>MAXRES){
fprintf(sp0,"Overflow of residue data type\nAbort\n");
exit(ABNORMAL_EXIT);
}
residue[row-nrow+1][col]=tempcharge;
}
}
flows[row][col]=sign*cliplimit;
mstcosts[row][col]=maxcost;
}
}
}
/* return value indicates that flows have been clipped */
fprintf(sp2,"Flows clipped to %ld. Rerunning MST solver.\n",cliplimit);
return(FALSE);
}
/* function: MCFInitFlows()
* ------------------------
* Initializes the flow on a the network using minimum cost flow
* algorithm.
*/
void MCFInitFlows(float **wrappedphase, short ***flowsptr, short **mstcosts,
long nrow, long ncol, long cs2scalefactor){
signed char **residue;
#ifndef NO_CS2
/* calculate phase residues (integer numbers of cycles) */
fprintf(sp1,"Initializing flows with MCF algorithm\n");
residue=(signed char **)Get2DMem(nrow-1,ncol-1,sizeof(signed char *),
sizeof(signed char));
CycleResidue(wrappedphase,residue,nrow,ncol);
/* run the solver (memory freed within solver) */
SolveCS2(residue,mstcosts,nrow,ncol,cs2scalefactor,flowsptr);
#endif
}