#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 <time.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "snaphu.h"
extern char dumpresults_global;
extern char requestedstop_global;
extern FILE *sp0, *sp1, *sp2, *sp3;
extern nodeT NONTREEARC[1];
extern void (*CalcCost)(void **, long, long, long, long, long,
paramT *, long *, long *);
extern long (*EvalCost)(void **, short **, long, long, long, paramT *);
static nodeT *(*NeighborNode)(nodeT *, long, long *, nodeT **, nodeT *, long *,
long *, long *, long, long, boundaryT *,
nodesuppT **);
static void (*GetArc)(nodeT *, nodeT *, long *, long *, long *, long, long,
nodeT **, nodesuppT **);
static
void AddNewNode(nodeT *from, nodeT *to, long arcdir, bucketT *bkts,
long nflow, incrcostT **incrcosts, long arcrow, long arccol,
paramT *params);
static
void CheckArcReducedCost(nodeT *from, nodeT *to, nodeT *apex,
long arcrow, long arccol, long arcdir,
candidateT **candidatebagptr,
long *candidatebagnextptr,
long *candidatebagsizeptr, incrcostT **incrcosts,
signed char **iscandidate, paramT *params);
static
nodeT *InitBoundary(nodeT *source, nodeT **nodes,
boundaryT *boundary, nodesuppT **nodesupp, float **mag,
nodeT *ground, long ngroundarcs, long nrow, long ncol,
paramT *params, long *nconnectedptr);
static
long CheckBoundary(nodeT **nodes, float **mag, nodeT *ground, long ngroundarcs,
boundaryT *boundary, long nrow, long ncol,
paramT *params, nodeT *start);
static
int IsRegionEdgeArc(float **mag, long arcrow, long arccol,
long nrow, long ncol);
static
int IsRegionInteriorArc(float **mag, long arcrow, long arccol,
long nrow, long ncol);
static
int IsRegionArc(float **mag, long arcrow, long arccol,
long nrow, long ncol);
static
int IsRegionEdgeNode(float **mag, long row, long col, long nrow, long ncol);
static
int CleanUpBoundaryNodes(nodeT *source, boundaryT *boundary, float **mag,
nodeT **nodes, nodeT *ground,
long nrow, long ncol, long ngroundarcs,
nodesuppT **nodesupp);
static
int DischargeBoundary(nodeT **nodes, nodeT *ground,
boundaryT *boundary, nodesuppT **nodesupp, short **flows,
signed char **iscandidate, float **mag,
float **wrappedphase, long ngroundarcs,
long nrow, long ncol);
static
int InitTree(nodeT *source, nodeT **nodes,
boundaryT *boundary, nodesuppT **nodesupp,
nodeT *ground, long ngroundarcs, bucketT *bkts, long nflow,
incrcostT **incrcosts, long nrow, long ncol, paramT *params);
static
nodeT *FindApex(nodeT *from, nodeT *to);
static
int CandidateCompare(const void *c1, const void *c2);
static
nodeT *NeighborNodeGrid(nodeT *node1, long arcnum, long *upperarcnumptr,
nodeT **nodes, nodeT *ground, long *arcrowptr,
long *arccolptr, long *arcdirptr, long nrow,
long ncol, boundaryT *boundary, nodesuppT **nodesupp);
static inline
long GetArcNumLims(long fromrow, long *upperarcnumptr,
long ngroundarcs, boundaryT *boundary);
static
nodeT *NeighborNodeNonGrid(nodeT *node1, long arcnum, long *upperarcnumptr,
nodeT **nodes, nodeT *ground, long *arcrowptr,
long *arccolptr, long *arcdirptr, long nrow,
long ncol, boundaryT *boundary,
nodesuppT **nodesupp);
static
void GetArcGrid(nodeT *from, nodeT *to, long *arcrow, long *arccol,
long *arcdir, long nrow, long ncol,
nodeT **nodes, nodesuppT **nodesupp);
static
void GetArcNonGrid(nodeT *from, nodeT *to, long *arcrow, long *arccol,
long *arcdir, long nrow, long ncol,
nodeT **nodes, nodesuppT **nodesupp);
static
void NonDegenUpdateChildren(nodeT *startnode, nodeT *lastnode,
nodeT *nextonpath, long dgroup,
long ngroundarcs, long nflow, nodeT **nodes,
nodesuppT **nodesupp, nodeT *ground,
boundaryT *boundary,
nodeT ***apexes, incrcostT **incrcosts,
long nrow, long ncol, paramT *params);
static
long PruneTree(nodeT *source, nodeT **nodes, nodeT *ground, boundaryT *boundary,
nodesuppT **nodesupp, incrcostT **incrcosts,
short **flows, long ngroundarcs, long prunecostthresh,
long nrow, long ncol);
static
int CheckLeaf(nodeT *node1, nodeT **nodes, nodeT *ground, boundaryT *boundary,
nodesuppT **nodesupp, incrcostT **incrcosts,
short **flows, long ngroundarcs, long nrow, long ncol,
long prunecostthresh);
static
int GridNodeMaskStatus(long row, long col, float **mag);
static
int GroundMaskStatus(long nrow, long ncol, float **mag);
static
int InitBuckets(bucketT *bkts, nodeT *source, long nbuckets);
static
nodeT *MinOutCostNode(bucketT *bkts);
static
nodeT *SelectConnNodeSource(nodeT **nodes, float **mag,
nodeT *ground, long ngroundarcs,
long nrow, long ncol,
paramT *params, nodeT *start, long *nconnectedptr);
static
long ScanRegion(nodeT *start, nodeT **nodes, float **mag,
nodeT *ground, long ngroundarcs,
long nrow, long ncol, int groupsetting);
static
short GetCost(incrcostT **incrcosts, long arcrow, long arccol,
long arcdir);
static
void SolveMST(nodeT **nodes, nodeT *source, nodeT *ground,
bucketT *bkts, short **mstcosts, signed char **residue,
signed char **arcstatus, long nrow, long ncol);
static
long DischargeTree(nodeT *source, short **mstcosts, short **flows,
signed char **residue, signed char **arcstatus,
nodeT **nodes, nodeT *ground, long nrow, long ncol);
static
signed char ClipFlow(signed char **residue, short **flows,
short **mstcosts, long nrow, long ncol,
long maxflow);
int SetGridNetworkFunctionPointers(void){
NeighborNode=NeighborNodeGrid;
GetArc=GetArcGrid;
return(0);
}
int SetNonGridNetworkFunctionPointers(void){
NeighborNode=NeighborNodeNonGrid;
GetArc=GetArcNonGrid;
return(0);
}
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, int *nnodesperrow, long narcrow,
int *narcsperrow, long nrow, long ncol,
outfileT *outfiles, long nconnected, 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, nnewnodes, maxnewnodes, templong;
long nmajor, nmajorprune, npruned, prunecostthresh;
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;
boundaryT boundary[1];
float **unwrappedphase;
memset(boundary,0,sizeof(boundaryT));
from=NULL;
to=NULL;
cycleapex=NULL;
node1=NULL;
node2=NULL;
leavingparent=NULL;
leavingchild=NULL;
root=NULL;
mntpt=NULL;
oldmntpt=NULL;
skipthread=NULL;
tempnode1=NULL;
tempnode2=NULL;
firstfromnode=NULL;
firsttonode=NULL;
candidatelist=(*candidatelistptr);
candidatebag=(*candidatebagptr);
candidatelistsize=(*candidatelistsizeptr);
candidatebagsize=(*candidatebagsizeptr);
candidatelistlen=0;
candidatebagnext=0;
source=InitBoundary(source,nodes,boundary,nodesupp,mag,
ground,ngroundarcs,nrow,ncol,params,&nconnected);
bkts->curr=bkts->maxind;
InitTree(source,nodes,boundary,nodesupp,ground,ngroundarcs,bkts,nflow,
incrcosts,nrow,ncol,params);
apexlistlen=INITARRSIZE;
apexlist=MAlloc(apexlistlen*sizeof(nodeT *));
groupcounter=2;
ipivots=0;
inondegen=0;
maxnewnodes=ceil(nconnected*params->maxnewnodeconst);
nnewnodes=0;
treesize=1;
npruned=0;
nmajor=0;
nmajorprune=params->nmajorprune;
prunecostthresh=params->prunecostthresh;;
fprintf(sp3,"Treesize: %-10ld Pivots: %-11ld Improvements: %-11ld",
treesize,ipivots,inondegen);
while(treesize<nconnected){
nnewnodes=0;
while(nnewnodes<maxnewnodes && treesize<nconnected){
to=MinOutCostNode(bkts);
from=to->pred;
GetArc(from,to,&arcrow,&arccol,&arcdir,nrow,ncol,nodes,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;
from=to;
arcnum=GetArcNumLims(from->row,&upperarcnum,ngroundarcs,boundary);
while(arcnum<upperarcnum){
to=NeighborNode(from,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,boundary,nodesupp);
if(to->group>0){
if(to!=from->pred){
cycleapex=FindApex(from,to);
apexes[arcrow][arccol]=cycleapex;
CheckArcReducedCost(from,to,cycleapex,arcrow,arccol,arcdir,
&candidatebag,&candidatebagnext,
&candidatebagsize,incrcosts,iscandidate,
params);
}else{
apexes[arcrow][arccol]=NULL;
}
}else if(to->group!=PRUNED && to->group!=MASKED){
AddNewNode(from,to,arcdir,bkts,nflow,incrcosts,arcrow,arccol,params);
}
}
nnewnodes++;
treesize++;
}
while(candidatebagnext){
if(dumpresults_global){
fflush(NULL);
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){
fflush(NULL);
fprintf(sp0,"Program exiting\n");
exit(ABNORMAL_EXIT);
}
Free2DArray((void **)unwrappedphase,nrow);
dumpresults_global=FALSE;
fflush(NULL);
fprintf(sp0,"\n\nProgram continuing\n");
}
tempcandidateptr=candidatebag;
candidatebag=candidatelist;
candidatelist=tempcandidateptr;
templong=candidatebagsize;
candidatebagsize=candidatelistsize;
candidatelistsize=templong;
candidatelistlen=candidatebagnext;
candidatebagnext=0;
qsort((void *)candidatelist,candidatelistlen,sizeof(candidateT),
CandidateCompare);
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;
}
}
for(i=0;i<candidatelistlen;i++){
from=candidatelist[i].from;
to=candidatelist[i].to;
arcdir=candidatelist[i].arcdir;
arcrow=candidatelist[i].arcrow;
arccol=candidatelist[i].arccol;
iscandidate[arcrow][arccol]=FALSE;
outcostto=from->outcost+
GetCost(incrcosts,arcrow,arccol,arcdir);
cyclecost=outcostto + to->incost
-apexes[arcrow][arccol]->outcost
-apexes[arcrow][arccol]->incost;
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;
}
if((outcostto < to->outcost) || (cyclecost < 0)){
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;
}
if(boundary->node->group>0){
boundary->node->group=1;
}
groupcounter=2;
}
if(cyclecost<0){
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,nodes,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,nodes,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,
nodes,nodesupp);
GetArc(node2->pred,node2,&arcrow2,&arccol2,&arcdir2,nrow,ncol,
nodes,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{
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,nodes,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,
nodes,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;
if(leavingchild==NULL){
fromside=TRUE;
leavingparent=from;
}else{
leavingparent=leavingchild->pred;
}
if(fromside){
groupcounter++;
fromgroup=groupcounter-1;
tempnode1=from;
from=to;
to=tempnode1;
}else{
fromgroup=groupcounter+1;
}
if(cyclecost<0){
firstfromnode=NULL;
firsttonode=NULL;
arcnum=GetArcNumLims(cycleapex->row,&upperarcnum,
ngroundarcs,boundary);
while(arcnum<upperarcnum){
tempnode1=NeighborNode(cycleapex,++arcnum,&upperarcnum,nodes,
ground,&arcrow,&arccol,&arcdir,nrow,ncol,
boundary,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;
}
}
}
cycleapex->group=groupcounter+2;
if(firsttonode!=NULL){
NonDegenUpdateChildren(cycleapex,leavingparent,firsttonode,0,
ngroundarcs,nflow,nodes,nodesupp,ground,
boundary,apexes,incrcosts,nrow,ncol,
params);
}
if(firstfromnode!=NULL){
NonDegenUpdateChildren(cycleapex,from,firstfromnode,1,
ngroundarcs,nflow,nodes,nodesupp,ground,
boundary,apexes,incrcosts,nrow,ncol,
params);
}
groupcounter=from->group;
apexlistbase=cycleapex->group;
fromgroup=cycleapex->group;
}else{
cycleapex->group=fromgroup;
groupcounter+=2;
apexlistbase=groupcounter+1;
}
if(leavingchild==NULL){
skipthread=to;
}else{
root=from;
oldmntpt=to;
while(oldmntpt!=leavingparent){
mntpt=root;
root=oldmntpt;
oldmntpt=root->pred;
root->pred=mntpt;
GetArc(mntpt,root,&arcrow,&arccol,&arcdir,nrow,ncol,
nodes,nodesupp);
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);
node1=root;
startlevel=root->level;
groupcounter++;
while(TRUE){
node1->level+=dlevel;
node1->outcost+=doutcost;
node1->incost+=dincost;
node1->group=groupcounter;
if(node1->next->level <= startlevel){
break;
}
node1=node1->next;
}
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;
GetArc(from,to,&arcrow,&arccol,&arcdir,nrow,ncol,nodes,nodesupp);
apexes[arcrow][arccol]=NULL;
GetArc(leavingparent,leavingchild,&arcrow,&arccol,
&arcdir,nrow,ncol,nodes,nodesupp);
apexes[arcrow][arccol]=cycleapex;
if(groupcounter-apexlistbase+1>apexlistlen){
apexlistlen=1.5*(groupcounter-apexlistbase+1);
apexlist=ReAlloc(apexlist,apexlistlen*sizeof(nodeT *));
}
node2=leavingchild;
for(group1=groupcounter;group1>=apexlistbase;group1--){
apexlist[group1-apexlistbase]=node2;
node2=node2->pred;
}
node1=to;
startlevel=to->level;
while(TRUE){
arcnum=GetArcNumLims(node1->row,&upperarcnum,
ngroundarcs,boundary);
while(arcnum<upperarcnum){
node2=NeighborNode(node1,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,
boundary,nodesupp);
if(node2->group>0){
if(node2->group < node1->group
&& apexes[arcrow][arccol]!=NULL){
if(node2->group >= apexlistbase){
apexes[arcrow][arccol]=apexlist[node2->group
-apexlistbase];
}else{
if(apexes[arcrow][arccol]->level > cycleapex->level){
apexes[arcrow][arccol]=cycleapex;
}else{
if(apexes[arcrow][arccol]==cycleapex){
tempnode2=node2;
while(tempnode2->group != fromgroup){
tempnode2=tempnode2->pred;
}
apexes[arcrow][arccol]=tempnode2;
}
}
}
CheckArcReducedCost(node1,node2,apexes[arcrow][arccol],
arcrow,arccol,arcdir,&candidatebag,
&candidatebagnext,&candidatebagsize,
incrcosts,iscandidate,params);
}
}else if(node2->group!=PRUNED && node2->group!=MASKED){
AddNewNode(node1,node2,arcdir,bkts,nflow,incrcosts,
arcrow,arccol,params);
}
}
node1=node1->next;
if(node1->level <= startlevel){
break;
}
}
}
if(cyclecost<0){
while(TRUE){
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;
while(TRUE){
arcnum=GetArcNumLims(node1->row,&upperarcnum,
ngroundarcs,boundary);
while(arcnum<upperarcnum){
node2=NeighborNode(node1,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,
boundary,nodesupp);
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,&candidatebag,
&candidatebagnext,&candidatebagsize,
incrcosts,iscandidate,params);
}
}else if(node2->group!=PRUNED && node2->group!=MASKED){
AddNewNode(node1,node2,arcdir,bkts,nflow,incrcosts,
arcrow,arccol,params);
}
}
node1=node1->next;
if(node1==to){
node1=skipthread;
}
if(node1->level <= startlevel){
break;
}
}
}
}
ipivots++;
}
}
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);
}
if(!((++nmajor) % nmajorprune)){
npruned+=PruneTree(source,nodes,ground,boundary,nodesupp,incrcosts,flows,
ngroundarcs,prunecostthresh,nrow,ncol);
}
}
node1=source->next;
while(node1!=source){
if(node1->pred->level!=node1->level-1){
printf("Error detected: row %d, col%d, level %d "
"has pred row %d, col%d, level %d\n",
node1->row,node1->col,node1->level,node1->pred->row,node1->pred->col,
node1->pred->level);
}
node1=node1->next;
}
DischargeBoundary(nodes,ground,boundary,nodesupp,flows,iscandidate,
mag,wrappedphase,ngroundarcs,nrow,ncol);
for(i=0;i<bkts->size;i++){
if(bkts->bucketbase[i]!=NULL){
printf("ERROR: bucket %ld not empty after TreeSolve (row=%d, col=%d)\n",
i,bkts->bucketbase[i]->row,bkts->bucketbase[i]->col);
break;
}
}
CleanUpBoundaryNodes(source,boundary,mag,nodes,ground,nrow,ncol,ngroundarcs,
nodesupp);
if(boundary->neighborlist!=NULL){
free(boundary->neighborlist);
}
if(boundary->boundarylist!=NULL){
free(boundary->boundarylist);
}
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(inondegen);
}
static
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==INBUCKET){
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=INBUCKET;
}
return;
}
static
void CheckArcReducedCost(nodeT *from, nodeT *to, nodeT *apex,
long arcrow, long arccol, long arcdir,
candidateT **candidatebagptr,
long *candidatebagnextptr,
long *candidatebagsizeptr, incrcostT **incrcosts,
signed char **iscandidate, paramT *params){
long apexcost, fwdarcdist, revarcdist, violation;
nodeT *temp;
if(iscandidate[arcrow][arccol]){
return;
}
apexcost=apex->outcost+apex->incost;
fwdarcdist=GetCost(incrcosts,arcrow,arccol,arcdir);
violation=fwdarcdist+from->outcost+to->incost-apexcost;
if(violation<0){
arcdir*=2;
}else{
revarcdist=GetCost(incrcosts,arcrow,arccol,-arcdir);
violation=revarcdist+to->outcost+from->incost-apexcost;
if(violation<0){
arcdir*=-2;
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;
}
}
}
}
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;
}
return;
}
static
nodeT *InitBoundary(nodeT *source, nodeT **nodes,
boundaryT *boundary, nodesuppT **nodesupp, float **mag,
nodeT *ground, long ngroundarcs, long nrow, long ncol,
paramT *params, long *nconnectedptr){
int iseligible, isinteriornode;
long k, nlist, ninteriorneighbor;
long nlistmem, nboundarymem, nneighbormem;
long arcnum, upperarcnum;
long neighborarcnum, neighborupperarcnum;
long arcrow, arccol, arcdir;
long nconnected;
nodeT **nodelist, **boundarylist, *from, *to, *end;
neighborT *neighborlist;
boundary->node->row=BOUNDARYROW;
boundary->node->col=BOUNDARYCOL;
boundary->node->next=NULL;
boundary->node->prev=NULL;
boundary->node->pred=NULL;
boundary->node->level=0;
boundary->node->group=0;
boundary->node->incost=VERYFAR;
boundary->node->outcost=VERYFAR;
boundary->neighborlist=NULL;
boundary->boundarylist=NULL;
boundary->nneighbor=0;
boundary->nboundary=0;
if(nodesupp!=NULL){
return(source);
}
if(mag==NULL){
return(source);
}
nconnected=ScanRegion(source,nodes,mag,ground,ngroundarcs,nrow,ncol,MASKED);
if(source==ground){
return(source);
}
if(!IsRegionEdgeNode(mag,source->row,source->col,nrow,ncol)){
fprintf(sp0,"WARNING: Non edge node as source in InitBoundary()\n");
}
nlistmem=NLISTMEMINCR;
nodelist=(nodeT **)MAlloc(nlistmem*sizeof(nodeT *));
nodelist[0]=source;
nlist=1;
source->next=NULL;
source->group=BOUNDARYCANDIDATE;
from=source;
end=source;
while(TRUE){
arcnum=GetArcNumLims(from->row,&upperarcnum,ngroundarcs,NULL);
while(arcnum<upperarcnum){
to=NeighborNode(from,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,NULL,nodesupp);
if(IsRegionEdgeArc(mag,arcrow,arccol,nrow,ncol)
&& to->group!=BOUNDARYCANDIDATE){
if(nlist==nlistmem){
nlistmem+=NLISTMEMINCR;
nodelist=(nodeT **)ReAlloc(nodelist,nlistmem*sizeof(nodeT *));
}
nodelist[nlist++]=to;
to->group=BOUNDARYCANDIDATE;
end->next=to;
to->next=NULL;
end=to;
}
}
if(from->next==NULL){
break;
}
from=from->next;
}
nboundarymem=NLISTMEMINCR;
boundarylist=(nodeT **)MAlloc(nboundarymem*sizeof(nodeT *));
for(k=0;k<nlist;k++){
if(nodelist[k]->row!=GROUNDROW){
iseligible=TRUE;
ninteriorneighbor=0;
arcnum=GetArcNumLims(nodelist[k]->row,&upperarcnum,ngroundarcs,NULL);
while(arcnum<upperarcnum){
from=NeighborNode(nodelist[k],++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,NULL,nodesupp);
isinteriornode=(IsRegionInteriorArc(mag,arcrow,arccol,nrow,ncol)
&& from->group!=MASKED
&& from->level!=BOUNDARYLEVEL);
if(isinteriornode){
ninteriorneighbor++;
}
if(isinteriornode || (from->group==BOUNDARYCANDIDATE
&& from->level!=BOUNDARYLEVEL)){
neighborarcnum=GetArcNumLims(from->row,&neighborupperarcnum,
ngroundarcs,NULL);
while(neighborarcnum<neighborupperarcnum){
to=NeighborNode(from,++neighborarcnum,&neighborupperarcnum,
nodes,ground,&arcrow,&arccol,&arcdir,
nrow,ncol,NULL,nodesupp);
if(to->level==BOUNDARYLEVEL){
iseligible=FALSE;
break;
}
}
}
if(!iseligible){
break;
}
}
if(iseligible && ninteriorneighbor>0){
nodelist[k]->level=BOUNDARYLEVEL;
if(++boundary->nboundary > nboundarymem){
nboundarymem+=NLISTMEMINCR;
boundarylist=(nodeT **)ReAlloc(boundarylist,
nboundarymem*sizeof(nodeT *));
}
boundarylist[boundary->nboundary-1]=nodelist[k];
}
}
}
for(k=0;k<nlist;k++){
nodelist[k]->group=0;
nodelist[k]->next=NULL;
}
free(nodelist);
if(boundary->nboundary<MINBOUNDARYSIZE){
for(k=0;k<boundary->nboundary;k++){
boundarylist[k]->level=0;
boundarylist[k]->group=0;
}
free(boundarylist);
boundary->node->row=BOUNDARYROW;
boundary->node->col=BOUNDARYCOL;
boundary->node->next=NULL;
boundary->node->prev=NULL;
boundary->node->pred=NULL;
boundary->node->level=0;
boundary->node->group=0;
boundary->node->incost=VERYFAR;
boundary->node->outcost=VERYFAR;
boundary->neighborlist=NULL;
boundary->boundarylist=NULL;
boundary->nneighbor=0;
boundary->nboundary=0;
return(source);
}
nneighbormem=NLISTMEMINCR;
neighborlist=(neighborT *)MAlloc(nneighbormem*sizeof(neighborT));
for(k=0;k<boundary->nboundary;k++){
arcnum=GetArcNumLims(boundarylist[k]->row,&upperarcnum,ngroundarcs,NULL);
while(arcnum<upperarcnum){
to=NeighborNode(boundarylist[k],++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,NULL,nodesupp);
if(to->group!=MASKED && to->level!=BOUNDARYLEVEL){
boundary->nneighbor++;
if(boundary->nneighbor>nneighbormem){
nneighbormem+=NLISTMEMINCR;
neighborlist=(neighborT *)ReAlloc(neighborlist,
nneighbormem*sizeof(neighborT));
}
neighborlist[boundary->nneighbor-1].neighbor=to;
neighborlist[boundary->nneighbor-1].arcrow=arcrow;
neighborlist[boundary->nneighbor-1].arccol=arccol;
neighborlist[boundary->nneighbor-1].arcdir=arcdir;
}
}
}
for(k=0;k<boundary->nboundary;k++){
boundarylist[k]->group=BOUNDARYPTR;
boundarylist[k]->level=0;
}
boundary->neighborlist=(neighborT *)ReAlloc(neighborlist,
(boundary->nneighbor
*sizeof(neighborT)));
boundary->boundarylist=(nodeT **)ReAlloc(boundarylist,(boundary->nboundary
*sizeof(nodeT *)));
nconnected=CheckBoundary(nodes,mag,ground,ngroundarcs,boundary,nrow,ncol,
params,boundary->node);
if(nconnectedptr!=NULL){
if(nconnected+boundary->nboundary-1!=(*nconnectedptr)){
fprintf(sp1,
"WARNING: Changed number of connected nodes in InitBoundary()\n");
}
(*nconnectedptr)=nconnected;
}
return(boundary->node);
}
static
long CheckBoundary(nodeT **nodes, float **mag, nodeT *ground, long ngroundarcs,
boundaryT *boundary, long nrow, long ncol,
paramT *params, nodeT *start){
long arcrow, arccol, arcdir, arcnum, upperarcnum;
long nontree, nboundaryarc, nboundarynode, nconnected;
nodeT *node1, *node2, *end;
nodesuppT **nodesupp;
if(start->group==MASKED){
fflush(NULL);
fprintf(sp0,"ERROR: ineligible starting node in CheckBoundary()\n");
exit(ABNORMAL_EXIT);
}
nconnected=0;
end=start;
nodesupp=NULL;
node1=start;
node1->group=INBUCKET;
while(node1!=NULL){
arcnum=GetArcNumLims(node1->row,&upperarcnum,ngroundarcs,boundary);
while(arcnum<upperarcnum){
node2=NeighborNode(node1,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,boundary,nodesupp);
if(node2->group!=MASKED && node2->group!=ONTREE
&& node2->group!=INBUCKET){
node2->group=INBUCKET;
end->next=node2;
node2->next=NULL;
end=node2;
}
}
node1->group=ONTREE;
nconnected++;
node1=node1->next;
}
node1=start;
nontree=0;
nboundaryarc=0;
nboundarynode=0;
while(node1!=NULL){
arcnum=GetArcNumLims(node1->row,&upperarcnum,ngroundarcs,boundary);
while(arcnum<upperarcnum){
node2=NeighborNode(node1,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,boundary,nodesupp);
if(node2->row==BOUNDARYROW){
nboundaryarc++;
}
}
if(node1->row==BOUNDARYROW){
nboundarynode++;
}
nontree++;
if(node1->group==ONTREE){
node1->group=0;
}
node1=node1->next;
}
if(nontree!=nconnected){
fflush(NULL);
fprintf(sp0,
"ERROR: inconsistent num connected nodes in CheckBoundary()\n");
exit(ABNORMAL_EXIT);
}
if(nboundaryarc!=boundary->nneighbor){
fflush(NULL);
fprintf(sp0,
"ERROR: inconsistent num neighbor nodes in CheckBoundary()\n");
exit(ABNORMAL_EXIT);
}
if(nboundarynode!=1){
fflush(NULL);
fprintf(sp0,
"ERROR: number of boundary nodes is not 1 in CheckBoundary()\n");
exit(ABNORMAL_EXIT);
}
return(nconnected);
}
static
int IsRegionEdgeArc(float **mag, long arcrow, long arccol,
long nrow, long ncol){
long row1, col1, row2, col2, nzeromag;
if(mag==NULL){
return(FALSE);
}
if(arcrow<nrow-1){
row1=arcrow;
row2=row1+1;
col1=arccol;
col2=col1;
}else{
row1=arcrow-(nrow-1);
row2=row1;
col1=arccol;
col2=col1+1;
}
nzeromag=0;
if(mag[row1][col1]==0){
nzeromag++;
}
if(mag[row2][col2]==0){
nzeromag++;
}
if(nzeromag==1){
return(TRUE);
}
return(FALSE);
}
static
int IsRegionInteriorArc(float **mag, long arcrow, long arccol,
long nrow, long ncol){
long row1, col1, row2, col2;
if(mag==NULL){
return(TRUE);
}
if(arcrow<nrow-1){
row1=arcrow;
row2=row1+1;
col1=arccol;
col2=col1;
}else{
row1=arcrow-(nrow-1);
row2=row1;
col1=arccol;
col2=col1+1;
}
if(mag[row1][col1]>0 && mag[row2][col2]>0){
return(TRUE);
}
return(FALSE);
}
static
int IsRegionArc(float **mag, long arcrow, long arccol,
long nrow, long ncol){
long row1, col1, row2, col2;
if(mag==NULL){
return(TRUE);
}
if(arcrow<nrow-1){
row1=arcrow;
row2=row1+1;
col1=arccol;
col2=col1;
}else{
row1=arcrow-(nrow-1);
row2=row1;
col1=arccol;
col2=col1+1;
}
if(mag[row1][col1]>0 || mag[row2][col2]>0){
return(TRUE);
}
return(FALSE);
}
#if 0#endif
static
int IsRegionEdgeNode(float **mag, long row, long col, long nrow, long ncol){
int onezeromag, onenonzeromag;
if(mag==NULL){
return(FALSE);
}
if(row==GROUNDROW){
return(FALSE);
}
onezeromag=FALSE;
onenonzeromag=FALSE;
if(mag[row][col]==0 || mag[row+1][col]==0
|| mag[row][col+1]==0 || mag[row+1][col+1]==0){
onezeromag=TRUE;
}
if(mag[row][col]!=0 || mag[row+1][col]!=0
|| mag[row][col+1]!=0 || mag[row+1][col+1]!=0){
onenonzeromag=TRUE;
}
if(onezeromag && onenonzeromag){
return(TRUE);
}
return(FALSE);
}
static
int CleanUpBoundaryNodes(nodeT *source, boundaryT *boundary, float **mag,
nodeT **nodes, nodeT *ground,
long nrow, long ncol, long ngroundarcs,
nodesuppT **nodesupp){
long nconnected;
nodeT *start;
if(nodesupp!=NULL){
return(0);
}
if(source->row==BOUNDARYROW){
start=boundary->neighborlist[0].neighbor;
}else{
start=source;
}
nconnected=ScanRegion(start,nodes,mag,ground,ngroundarcs,nrow,ncol,0);
return(nconnected);
}
static
int DischargeBoundary(nodeT **nodes, nodeT *ground,
boundaryT *boundary, nodesuppT **nodesupp, short **flows,
signed char **iscandidate, float **mag,
float **wrappedphase, long ngroundarcs,
long nrow, long ncol){
long nedgenode;
long row, col, fromrow, fromcol, todir;
long arcnum, upperarcnum, arcrow, arccol, arcdir, narccol;
long surplus, residue, excess;
nodeT *from, *to, *nextnode;
if(nodesupp!=NULL || boundary==NULL
|| boundary->nboundary==0 || boundary->nneighbor==0){
return(0);
}
nextnode=boundary->boundarylist[0];
row=nextnode->row;
col=nextnode->col;
if(!IsRegionEdgeNode(mag,row,col,nrow,ncol)){
fprintf(sp0,"ERROR: DischargeBoundary() start node %ld, %ld not on edge\n",
row,col);
exit(ABNORMAL_EXIT);
}
row=0;
col=0;
todir=0;
for(row=0;row<2*nrow-1;row++){
if(row<nrow-1){
narccol=ncol;
}else{
narccol=ncol-1;
}
for(col=0;col<narccol;col++){
iscandidate[row][col]=0;
}
}
nedgenode=1;
while(TRUE){
from=nextnode;
from->outcost=-1;
nextnode=NULL;
arcnum=GetArcNumLims(from->row,&upperarcnum,ngroundarcs,NULL);
while(arcnum<upperarcnum){
to=NeighborNode(from,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,NULL,nodesupp);
if(IsRegionEdgeArc(mag,arcrow,arccol,nrow,ncol)
&& (iscandidate[arcrow][arccol]==-1 ||
(iscandidate[arcrow][arccol]==0 && to->outcost!=-1))){
nextnode=to;
row=arcrow;
col=arccol;
todir=arcdir;
if(!iscandidate[arcrow][arccol]){
break;
}
}
}
if(nextnode==NULL){
break;
}
if((--iscandidate[row][col])==-2){
fromrow=from->row;
fromcol=from->col;
surplus=(flows[fromrow][fromcol]
-flows[fromrow][fromcol+1]
+flows[fromrow+nrow-1][fromcol]
-flows[fromrow+1+nrow-1][fromcol]);
residue=NodeResidue(wrappedphase,fromrow,fromcol);
excess=surplus+residue;
flows[row][col]+=todir*excess;
nedgenode++;
}
}
for(row=0;row<nrow;row++){
for(col=0;col<ncol;col++){
if(row<nrow-1){
if(iscandidate[row][col]){
if(col>0){
nodes[row][col-1].outcost=0;
}
if(col<ncol-1){
nodes[row][col].outcost=0;
}
}
iscandidate[row][col]=FALSE;
}
if(col<ncol-1){
if(iscandidate[row+nrow-1][col]){
if(row>0){
nodes[row-1][col].outcost=0;
}
if(row<nrow-1){
nodes[row][col].outcost=0;
}
}
iscandidate[row+nrow-1][col]=FALSE;
}
}
}
iscandidate[nrow-1][0]=TRUE;
iscandidate[2*nrow-2][0]=TRUE;
iscandidate[nrow-1][ncol-2]=TRUE;
iscandidate[2*nrow-2][ncol-2]=TRUE;
return(nedgenode);
}
static
int InitTree(nodeT *source, nodeT **nodes,
boundaryT *boundary, nodesuppT **nodesupp,
nodeT *ground, long ngroundarcs, bucketT *bkts, long nflow,
incrcostT **incrcosts, long nrow, long ncol, paramT *params){
long arcnum, upperarcnum, arcrow, arccol, arcdir;
nodeT *to;
source->group=1;
source->outcost=0;
source->incost=0;
source->pred=NULL;
source->prev=source;
source->next=source;
source->level=0;
arcnum=GetArcNumLims(source->row,&upperarcnum,ngroundarcs,boundary);
while(arcnum<upperarcnum){
to=NeighborNode(source,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,boundary,nodesupp);
if(to->group!=PRUNED && to->group!=MASKED){
AddNewNode(source,to,arcdir,bkts,nflow,incrcosts,arcrow,arccol,params);
}
}
return(0);
}
static
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);
}
static
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);
}
static inline
long GetArcNumLims(long fromrow, long *upperarcnumptr,
long ngroundarcs, boundaryT *boundary){
long arcnum;
if(fromrow<0){
arcnum=-1;
if(fromrow==GROUNDROW){
*upperarcnumptr=ngroundarcs-1;
}else{
*upperarcnumptr=boundary->nneighbor-1;
}
}else{
arcnum=-5;
*upperarcnumptr=-1;
}
return(arcnum);
}
static
nodeT *NeighborNodeGrid(nodeT *node1, long arcnum, long *upperarcnumptr,
nodeT **nodes, nodeT *ground, long *arcrowptr,
long *arccolptr, long *arcdirptr, long nrow,
long ncol, boundaryT *boundary, nodesuppT **nodesupp){
long row, col;
nodeT *neighbor;
row=node1->row;
col=node1->col;
if(row==BOUNDARYROW){
neighbor=boundary->neighborlist[arcnum].neighbor;
*arcrowptr=boundary->neighborlist[arcnum].arcrow;
*arccolptr=boundary->neighborlist[arcnum].arccol;
*arcdirptr=boundary->neighborlist[arcnum].arcdir;
}else{
switch(arcnum){
case -4:
*arcrowptr=row;
*arccolptr=col+1;
*arcdirptr=1;
if(col==ncol-2){
neighbor=ground;
}else{
neighbor=&nodes[row][col+1];
}
break;
case -3:
*arcrowptr=nrow+row;
*arccolptr=col;
*arcdirptr=1;
if(row==nrow-2){
neighbor=ground;
}else{
neighbor=&nodes[row+1][col];
}
break;
case -2:
*arcrowptr=row;
*arccolptr=col;
*arcdirptr=-1;
if(col==0){
neighbor=ground;
}else{
neighbor=&nodes[row][col-1];
}
break;
case -1:
*arcrowptr=nrow-1+row;
*arccolptr=col;
*arcdirptr=-1;
if(row==0){
neighbor=ground;
}else{
neighbor=&nodes[row-1][col];
}
break;
default:
if(arcnum<nrow-1){
*arcrowptr=arcnum;
*arccolptr=0;
*arcdirptr=1;
neighbor=&nodes[*arcrowptr][0];
}else if(arcnum<2*(nrow-1)){
*arcrowptr=arcnum-(nrow-1);
*arccolptr=ncol-1;
*arcdirptr=-1;
neighbor=&nodes[*arcrowptr][ncol-2];
}else if(arcnum<2*(nrow-1)+ncol-3){
*arcrowptr=nrow-1;
*arccolptr=arcnum-2*(nrow-1)+1;
*arcdirptr=1;
neighbor=&nodes[0][*arccolptr];
}else{
*arcrowptr=2*nrow-2;
*arccolptr=arcnum-(2*(nrow-1)+ncol-3)+1;
*arcdirptr=-1;
neighbor=&nodes[nrow-2][*arccolptr];
}
break;
}
if(neighbor->group==BOUNDARYPTR && boundary!=NULL){
neighbor=boundary->node;
}
}
return(neighbor);
}
static
nodeT *NeighborNodeNonGrid(nodeT *node1, long arcnum, long *upperarcnumptr,
nodeT **nodes, nodeT *ground, long *arcrowptr,
long *arccolptr, long *arcdirptr, long nrow,
long ncol, boundaryT *boundary,
nodesuppT **nodesupp){
long tilenum, nodenum;
scndryarcT *outarc;
tilenum=node1->row;
nodenum=node1->col;
*upperarcnumptr=nodesupp[tilenum][nodenum].noutarcs-5;
outarc=nodesupp[tilenum][nodenum].outarcs[arcnum+4];
*arcrowptr=outarc->arcrow;
*arccolptr=outarc->arccol;
if(node1==outarc->from){
*arcdirptr=1;
}else{
*arcdirptr=-1;
}
return(nodesupp[tilenum][nodenum].neighbornodes[arcnum+4]);
}
static
void GetArcGrid(nodeT *from, nodeT *to, long *arcrow, long *arccol,
long *arcdir, long nrow, long ncol,
nodeT **nodes, nodesuppT **nodesupp){
long fromrow, fromcol, torow, tocol;
fromrow=from->row;
fromcol=from->col;
torow=to->row;
tocol=to->col;
if(fromcol==tocol-1){
*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(fromrow==BOUNDARYROW){
if(tocol<ncol-2 && nodes[torow][tocol+1].group==BOUNDARYPTR){
*arcrow=torow;
*arccol=tocol+1;
*arcdir=-1;
}else if(tocol>0 && nodes[torow][tocol-1].group==BOUNDARYPTR){
*arcrow=torow;
*arccol=tocol;
*arcdir=1;
}else if(torow<nrow-2 && nodes[torow+1][tocol].group==BOUNDARYPTR){
*arcrow=torow+1+nrow-1;
*arccol=tocol;
*arcdir=-1;
}else{
*arcrow=torow+nrow-1;
*arccol=tocol;
*arcdir=1;
}
}else if(torow==BOUNDARYROW){
if(fromcol<ncol-2 && nodes[fromrow][fromcol+1].group==BOUNDARYPTR){
*arcrow=fromrow;
*arccol=fromcol+1;
*arcdir=1;
}else if(fromcol>0 && nodes[fromrow][fromcol-1].group==BOUNDARYPTR){
*arcrow=fromrow;
*arccol=fromcol;
*arcdir=-1;
}else if(fromrow<nrow-2 && nodes[fromrow+1][fromcol].group==BOUNDARYPTR){
*arcrow=fromrow+1+nrow-1;
*arccol=fromcol;
*arcdir=1;
}else{
*arcrow=fromrow+nrow-1;
*arccol=fromcol;
*arcdir=-1;
}
}else if(fromcol==0){
*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){
*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;
}
return;
}
static
void GetArcNonGrid(nodeT *from, nodeT *to, long *arcrow, long *arccol,
long *arcdir, long nrow, long ncol,
nodeT **nodes, nodesuppT **nodesupp){
long tilenum, nodenum, arcnum;
scndryarcT *outarc;
tilenum=from->row;
nodenum=from->col;
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;
}
}
return;
}
static
void NonDegenUpdateChildren(nodeT *startnode, nodeT *lastnode,
nodeT *nextonpath, long dgroup,
long ngroundarcs, long nflow, nodeT **nodes,
nodesuppT **nodesupp, nodeT *ground,
boundaryT *boundary,
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;
node1=startnode;
pathgroup=lastnode->group;
while(node1!=lastnode){
node2=nextonpath;
GetArc(node2->pred,node2,&arcrow,&arccol,&arcdir,nrow,ncol,
nodes,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;
node1=node2;
arcnum=GetArcNumLims(node1->row,&upperarcnum,ngroundarcs,boundary);
while(arcnum<upperarcnum){
node2=NeighborNode(node1,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,boundary,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;
}
}
}
}
}
}
return;
}
static
long PruneTree(nodeT *source, nodeT **nodes, nodeT *ground, boundaryT *boundary,
nodesuppT **nodesupp, incrcostT **incrcosts,
short **flows, long ngroundarcs, long prunecostthresh,
long nrow, long ncol){
long npruned;
nodeT *node1;
npruned=0;
node1=source->next;
while(node1!=source){
if(CheckLeaf(node1,nodes,ground,boundary,nodesupp,incrcosts,flows,
ngroundarcs,nrow,ncol,prunecostthresh)){
node1->prev->next=node1->next;
node1->next->prev=node1->prev;
node1->group=PRUNED;
npruned++;
if(node1->prev->level < node1->level){
node1=node1->prev;
}else{
node1=node1->next;
}
}else{
node1=node1->next;
}
}
fprintf(sp3,"\n Pruned %ld nodes\n",npruned);
return(npruned);
}
static
int CheckLeaf(nodeT *node1, nodeT **nodes, nodeT *ground, boundaryT *boundary,
nodesuppT **nodesupp, incrcostT **incrcosts,
short **flows, long ngroundarcs, long nrow, long ncol,
long prunecostthresh){
long arcnum, upperarcnum, arcrow, arccol, arcdir;
nodeT *node2;
if(node1->next->level > node1->level){
return(FALSE);
}
arcnum=GetArcNumLims(node1->row,&upperarcnum,ngroundarcs,boundary);
while(arcnum<upperarcnum){
node2=NeighborNode(node1,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,boundary,nodesupp);
if(node2->group==0 || node2->group==INBUCKET
|| incrcosts[arcrow][arccol].poscost<prunecostthresh
|| incrcosts[arcrow][arccol].negcost<prunecostthresh
|| flows[arcrow][arccol]!=0){
return(FALSE);
}
}
return(TRUE);
}
int 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, int **nnodesperrowptr, long *narcrowptr,
int **narcsperrowptr, long nrow, long ncol,
signed char *notfirstloopptr, totalcostT *totalcostptr,
paramT *params){
long i;
if(ground!=NULL && *nodesptr==NULL){
*nodesptr=(nodeT **)Get2DMem(nrow-1,ncol-1,sizeof(nodeT *),sizeof(nodeT));
InitNodeNums(nrow-1,ncol-1,*nodesptr,ground);
}
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;
}
*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);
fflush(NULL);
fprintf(sp0,"((Maximum flow) * NSHORTCYCLE) too large\nAbort\n");
exit(ABNORMAL_EXIT);
}
if(ncol>2){
*ngroundarcsptr=2*(nrow+ncol-2)-4;
}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 *));
}
*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;
}
*iincrcostfileptr=0;
if(ground!=NULL){
(*incrcostsptr)=(incrcostT **)Get2DRowColMem(nrow,ncol,sizeof(incrcostT *),
sizeof(incrcostT));
}
if(ground!=NULL){
(*nnoderowptr)=nrow-1;
(*nnodesperrowptr)=(int *)MAlloc((nrow-1)*sizeof(int));
for(i=0;i<nrow-1;i++){
(*nnodesperrowptr)[i]=ncol-1;
}
(*narcrowptr)=2*nrow-1;
(*narcsperrowptr)=(int *)MAlloc((2*nrow-1)*sizeof(int));
for(i=0;i<nrow-1;i++){
(*narcsperrowptr)[i]=ncol;
}
for(i=nrow-1;i<2*nrow-1;i++){
(*narcsperrowptr)[i]=ncol-1;
}
}
(*notfirstloopptr)=FALSE;
(*totalcostptr)=INITTOTALCOST;
return(0);
}
long SetupTreeSolveNetwork(nodeT **nodes, nodeT *ground, nodeT ***apexes,
signed char **iscandidate, long nnoderow,
int *nnodesperrow, long narcrow, int *narcsperrow,
long nrow, long ncol){
long row, col, nnodes;
nnodes=0;
for(row=0;row<nnoderow;row++){
for(col=0;col<nnodesperrow[row];col++){
if(nodes[row][col].group!=MASKED){
nodes[row][col].group=0;
nnodes++;
}
nodes[row][col].incost=VERYFAR;
nodes[row][col].outcost=VERYFAR;
nodes[row][col].pred=NULL;
}
}
if(ground!=NULL){
if(ground->group!=MASKED){
ground->group=0;
nnodes++;
}
ground->incost=VERYFAR;
ground->outcost=VERYFAR;
ground->pred=NULL;
}
for(row=0;row<narcrow;row++){
for(col=0;col<narcsperrow[row];col++){
apexes[row][col]=NONTREEARC;
iscandidate[row][col]=FALSE;
}
}
if(ground!=NULL){
iscandidate[nrow-1][0]=TRUE;
iscandidate[2*nrow-2][0]=TRUE;
iscandidate[nrow-1][ncol-2]=TRUE;
iscandidate[2*nrow-2][ncol-2]=TRUE;
}
return(nnodes);
}
signed char CheckMagMasking(float **mag, long nrow, long ncol){
long row, col;
for(row=0;row<nrow;row++){
for(col=0;col<ncol;col++){
if(mag[row][col]>0){
return(0);
}
}
}
return(1);
}
int MaskNodes(long nrow, long ncol, nodeT **nodes, nodeT *ground,
float **mag){
long row, col;
for(row=0;row<nrow-1;row++){
for(col=0;col<ncol-1;col++){
nodes[row][col].group=GridNodeMaskStatus(row,col,mag);
}
}
ground->group=GroundMaskStatus(nrow,ncol,mag);
return(0);
}
static
int GridNodeMaskStatus(long row, long col, float **mag){
if(mag[row][col] || mag[row][col+1]
|| mag[row+1][col] || mag[row+1][col+1]){
return(0);
}
return(MASKED);
}
static
int GroundMaskStatus(long nrow, long ncol, float **mag){
long row, col;
for(row=0;row<nrow;row++){
if(mag[row][0] || mag[row][ncol-1]){
return(0);
}
}
for(col=0;col<ncol;col++){
if(mag[0][col] || mag[nrow-1][col]){
return(0);
}
}
return(MASKED);
}
long MaxNonMaskFlow(short **flows, float **mag, long nrow, long ncol){
long row, col;
long mostflow, flowvalue;
mostflow=0;
for(row=0;row<nrow-1;row++){
for(col=0;col<ncol;col++){
flowvalue=labs((long )flows[row][col]);
if(flowvalue>mostflow && mag[row][col]>0 && mag[row+1][col]>0){
mostflow=flowvalue;
}
}
}
for(row=nrow-1;row<2*nrow-1;row++){
for(col=0;col<ncol-1;col++){
flowvalue=labs((long )flows[row][col]);
if(flowvalue>mostflow
&& mag[row-nrow+1][col]>0 && mag[row-nrow+1][col+1]>0){
mostflow=flowvalue;
}
}
}
return(mostflow);
}
int InitNodeNums(long nrow, long ncol, nodeT **nodes, nodeT *ground){
long row, col;
for(row=0;row<nrow;row++){
for(col=0;col<ncol;col++){
nodes[row][col].row=row;
nodes[row][col].col=col;
}
}
if(ground!=NULL){
ground->row=GROUNDROW;
ground->col=GROUNDCOL;
}
return(0);
}
static
int InitBuckets(bucketT *bkts, nodeT *source, long nbuckets){
long i;
bkts->curr=0;
bkts->wrapped=FALSE;
for(i=0;i<nbuckets;i++){
bkts->bucketbase[i]=NULL;
}
bkts->bucket[0]=source;
source->next=NULL;
source->prev=NULL;
source->group=INBUCKET;
source->outcost=0;
return(0);
}
int InitNodes(long nnrow, long nncol, nodeT **nodes, nodeT *ground){
long row, col;
for(row=0;row<nnrow;row++){
for(col=0;col<nncol;col++){
nodes[row][col].group=NOTINBUCKET;
nodes[row][col].incost=VERYFAR;
nodes[row][col].outcost=VERYFAR;
nodes[row][col].pred=NULL;
}
}
if(ground!=NULL){
ground->group=NOTINBUCKET;
ground->incost=VERYFAR;
ground->outcost=VERYFAR;
ground->pred=NULL;
}
return(0);
}
void BucketInsert(nodeT *node, long ind, bucketT *bkts){
node->next=bkts->bucket[ind];
if((bkts->bucket[ind])!=NULL){
bkts->bucket[ind]->prev=node;
}
bkts->bucket[ind]=node;
node->prev=NULL;
node->group=INBUCKET;
return;
}
void BucketRemove(nodeT *node, long ind, bucketT *bkts){
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;
}
return;
}
nodeT *ClosestNode(bucketT *bkts){
nodeT *node;
while(TRUE){
if((bkts->curr)>(bkts->maxind)){
return(NULL);
}
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);
}
bkts->curr++;
}
}
#if 0#endif
static
nodeT *MinOutCostNode(bucketT *bkts){
long minoutcost;
nodeT *node1, *node2;
while(bkts->curr<bkts->maxind && bkts->bucket[bkts->curr]==NULL){
bkts->curr++;
}
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);
}
long SelectSources(nodeT **nodes, float **mag, nodeT *ground, long nflow,
short **flows, long ngroundarcs,
long nrow, long ncol, paramT *params,
nodeT ***sourcelistptr, long **nconnectedarrptr){
long row, col, nsource, nsourcelistmem, nconnected;
long *nconnectedarr;
nodeT *source;
nodeT **sourcelist;
nsource=0;
nsourcelistmem=0;
sourcelist=NULL;
nconnectedarr=NULL;
if(ground->group!=MASKED && ground->group!=BOUNDARYPTR){
ground->group=0;
}
ground->next=NULL;
for(row=0;row<nrow-1;row++){
for(col=0;col<ncol-1;col++){
if(nodes[row][col].group!=MASKED && nodes[row][col].group!=BOUNDARYPTR){
nodes[row][col].group=0;
}
nodes[row][col].next=NULL;
}
}
source=SelectConnNodeSource(nodes,mag,
ground,ngroundarcs,nrow,ncol,params,
ground,&nconnected);
if(source!=NULL){
if(++nsource>nsourcelistmem){
nsourcelistmem+=NSOURCELISTMEMINCR;
sourcelist=ReAlloc(sourcelist,nsourcelistmem*sizeof(nodeT *));
nconnectedarr=ReAlloc(nconnectedarr,nsourcelistmem*sizeof(long));
}
sourcelist[nsource-1]=source;
nconnectedarr[nsource-1]=nconnected;
}
for(row=0;row<nrow-1;row++){
for(col=0;col<ncol-1;col++){
source=SelectConnNodeSource(nodes,mag,
ground,ngroundarcs,nrow,ncol,params,
&nodes[row][col],&nconnected);
if(source!=NULL){
if(++nsource>nsourcelistmem){
nsourcelistmem+=NSOURCELISTMEMINCR;
sourcelist=ReAlloc(sourcelist,nsourcelistmem*sizeof(nodeT *));
nconnectedarr=ReAlloc(nconnectedarr,nsourcelistmem*sizeof(long));
}
sourcelist[nsource-1]=source;
nconnectedarr[nsource-1]=nconnected;
}
}
}
fprintf(sp1,"Found %ld valid set(s) of connected nodes\n",nsource);
if(ground->group!=MASKED && ground->group!=BOUNDARYPTR){
ground->group=0;
}
ground->next=NULL;
for(row=0;row<nrow-1;row++){
for(col=0;col<ncol-1;col++){
if(nodes[row][col].group==INBUCKET
|| nodes[row][col].group==NOTINBUCKET
|| nodes[row][col].group==BOUNDARYCANDIDATE
|| nodes[row][col].group==PRUNED){
fflush(NULL);
fprintf(stderr,
"WARNING: weird nodes[%ld][%ld].group=%d in SelectSources()\n",
row,col,nodes[row][col].group);
}
if(nodes[row][col].group!=MASKED && nodes[row][col].group!=BOUNDARYPTR){
nodes[row][col].group=0;
}
nodes[row][col].next=NULL;
}
}
if(sourcelistptr!=NULL){
(*sourcelistptr)=sourcelist;
}else{
fflush(NULL);
fprintf(sp0,"ERROR: NULL sourcelistptr in SelectSources()\nAbort\n");
exit(ABNORMAL_EXIT);
}
if(nconnectedarrptr!=NULL){
(*nconnectedarrptr)=nconnectedarr;
}else{
fflush(NULL);
fprintf(sp0,"ERROR: NULL nconnectedarrptr SelectSources()\nAbort\n");
exit(ABNORMAL_EXIT);
}
return(nsource);
}
static
nodeT *SelectConnNodeSource(nodeT **nodes, float **mag,
nodeT *ground, long ngroundarcs,
long nrow, long ncol,
paramT *params, nodeT *start, long *nconnectedptr){
long nconnected;
nodeT *source;
if(start->group==MASKED || start->group==ONTREE){
return(NULL);
}
nconnected=ScanRegion(start,nodes,mag,ground,ngroundarcs,nrow,ncol,ONTREE);
if(nconnected>params->nconnnodemin){
source = start;
}else{
source=NULL;
}
if(nconnectedptr!=NULL){
(*nconnectedptr)=nconnected;
}
return(source);
}
static
long ScanRegion(nodeT *start, nodeT **nodes, float **mag,
nodeT *ground, long ngroundarcs,
long nrow, long ncol, int groupsetting){
nodeT *node1, *node2, *end;
long arcrow, arccol, arcdir, arcnum, upperarcnum, nconnected;
nodesuppT **nodesupp;
boundaryT *boundary;
nconnected=0;
end=start;
nodesupp=NULL;
boundary=NULL;
node1=start;
node1->group=INBUCKET;
while(node1!=NULL){
arcnum=GetArcNumLims(node1->row,&upperarcnum,ngroundarcs,boundary);
while(arcnum<upperarcnum){
node2=NeighborNode(node1,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,boundary,nodesupp);
if(node2->group==BOUNDARYPTR){
node2->group=0;
}
if(IsRegionArc(mag,arcrow,arccol,nrow,ncol)){
if(node2->group!=ONTREE && node2->group!=INBUCKET){
node2->group=INBUCKET;
end->next=node2;
node2->next=NULL;
end=node2;
}
}
}
node1->group=ONTREE;
if(groupsetting==ONTREE){
node1->level=0;
}
nconnected++;
node1=node1->next;
}
if(groupsetting!=ONTREE){
node1=start;
while(node1!=NULL){
arcnum=GetArcNumLims(node1->row,&upperarcnum,ngroundarcs,boundary);
while(arcnum<upperarcnum){
node2=NeighborNode(node1,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,boundary,nodesupp);
if(node2->group!=ONTREE){
if(groupsetting==MASKED){
node2->group=MASKED;
}else if(groupsetting==0){
if(node2->row==GROUNDROW){
node2->group=GroundMaskStatus(nrow,ncol,mag);
}else{
node2->group=GridNodeMaskStatus(node2->row,node2->col,mag);
}
}
}
}
node1=node1->next;
}
node1=start;
while(node1!=NULL){
node1->group=0;
node1=node1->next;
}
}
return(nconnected);
}
static
short GetCost(incrcostT **incrcosts, long arcrow, long arccol,
long arcdir){
if(arcdir>0){
return(incrcosts[arcrow][arccol].poscost);
}else{
return(incrcosts[arcrow][arccol].negcost);
}
}
long ReCalcCost(void **costs, incrcostT **incrcosts, long flow,
long arcrow, long arccol, long nflow, long nrow,
paramT *params){
long poscost, negcost, iclipped;
CalcCost(costs,flow,arcrow,arccol,nflow,nrow,params,
&poscost,&negcost);
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(iclipped);
}
int SetupIncrFlowCosts(void **costs, incrcostT **incrcosts, short **flows,
long nflow, long nrow, long narcrow,
int *narcsperrow, paramT *params){
long arcrow, arccol, iclipped, narcs;
char pl[2];
narcs=0;
iclipped=0;
for(arcrow=0;arcrow<narcrow;arcrow++){
narcs+=narcsperrow[arcrow];
for(arccol=0;arccol<narcsperrow[arcrow];arccol++){
iclipped+=ReCalcCost(costs,incrcosts,flows[arcrow][arccol],
arcrow,arccol,nflow,nrow,params);
}
}
if(iclipped){
if(iclipped>1){
strcpy(pl,"s");
}else{
strcpy(pl,"");
}
fflush(NULL);
fprintf(sp0,"%ld incremental cost%s clipped to avoid overflow (%.3f%%)\n",
iclipped,pl,((double )iclipped)/(2*narcs));
}
return(0);
}
totalcostT EvaluateTotalCost(void **costs, short **flows, long nrow, long ncol,
int *narcsperrow,paramT *params){
totalcostT rowcost, totalcost;
long row, col, maxrow, maxcol;
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);
}
int 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];
memset(bkts,0,sizeof(bucketT));
*nodesptr=(nodeT **)Get2DMem(nrow-1,ncol-1,sizeof(nodeT *),sizeof(nodeT));
InitNodeNums(nrow-1,ncol-1,*nodesptr,ground);
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];
}
}
}
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));
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);
(*flowsptr)=(short **)Get2DRowColZeroMem(nrow,ncol,
sizeof(short *),sizeof(short));
flows=*flowsptr;
fprintf(sp2,"Running approximate minimum spanning tree solver\n");
while(TRUE){
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;
}
InitNodes(nrow-1,ncol-1,*nodesptr,ground);
InitBuckets(bkts,source,bkts->size);
SolveMST(*nodesptr,source,ground,bkts,mstcosts,residue,arcstatus,
nrow,ncol);
DischargeTree(source,mstcosts,flows,residue,arcstatus,
*nodesptr,ground,nrow,ncol);
if(ClipFlow(residue,flows,mstcosts,nrow,ncol,maxflow)){
break;
}
}
Free2DArray((void **)residue,nrow-1);
Free2DArray((void **)arcstatus,2*nrow-1);
Free2DArray((void **)mstcosts,2*nrow-1);
free(bkts->bucketbase);
return(0);
}
static
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;
nodesupp=NULL;
ngroundarcs=2*(nrow+ncol-2)-4;
groundcharge=0;
for(row=0;row<nrow-1;row++){
for(col=0;col<ncol-1;col++){
groundcharge-=residue[row][col];
}
}
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;
}
}
while((from=ClosestNode(bkts))!=NULL){
fromrow=from->row;
fromcol=from->col;
if(((fromrow!=GROUNDROW && residue[fromrow][fromcol]) ||
(fromrow==GROUNDROW && groundcharge)) && from!=source){
pathto=from;
pathfrom=from->pred;
while(TRUE){
pathto->outcost=0;
GetArc(pathfrom,pathto,&arcrow,&arccol,&arcdir,nrow,ncol,
nodes,nodesupp);
arcstatus[arcrow][arccol]=-1;
pathfromrow=pathfrom->row;
pathfromcol=pathfrom->col;
if((pathfromrow!=GROUNDROW && residue[pathfromrow][pathfromcol])
|| (pathfromrow==GROUNDROW && groundcharge)){
break;
}
pathto=pathfrom;
pathfrom=pathfrom->pred;
}
}
fromdist=from->outcost;
arcnum=GetArcNumLims(fromrow,&upperarcnum,ngroundarcs,NULL);
while(arcnum<upperarcnum){
to=NeighborNode(from,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,NULL,nodesupp);
row=to->row;
col=to->col;
if(arcstatus[arcrow][arccol]<0){
arcdist=0;
}else if((arcdist=mstcosts[arcrow][arccol])==LARGESHORT){
arcdist=VERYFAR;
}
if((newdist=fromdist+arcdist)<(to->outcost)){
if(to->group==INBUCKET){
if(to->outcost<bkts->maxind){
BucketRemove(to,to->outcost,bkts);
}else{
BucketRemove(to,bkts->maxind,bkts);
}
}
to->outcost=newdist;
to->pred=from;
if(newdist<bkts->maxind){
BucketInsert(to,newdist,bkts);
if(newdist<bkts->curr){
bkts->curr=newdist;
}
}else{
BucketInsert(to,bkts->maxind,bkts);
}
}
}
}
}
static
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;
nextnode=source;
ground->outcost=0;
for(row=0;row<nrow-1;row++){
for(col=0;col<ncol-1;col++){
nodes[row][col].outcost=residue[row][col];
ground->outcost-=residue[row][col];
}
}
ngroundarcs=2*(nrow+ncol-2)-4;
nodesupp=NULL;
todir=0;
while(TRUE){
from=nextnode;
nextnode=NULL;
arcnum=GetArcNumLims(from->row,&upperarcnum,ngroundarcs,NULL);
while(arcnum<upperarcnum){
to=NeighborNode(from,++arcnum,&upperarcnum,nodes,ground,
&arcrow,&arccol,&arcdir,nrow,ncol,NULL,nodesupp);
if(arcstatus[arcrow][arccol]==-1){
nextnode=to;
row=arcrow;
col=arccol;
break;
}else if(arcstatus[arcrow][arccol]==-2){
nextnode=to;
row=arcrow;
col=arccol;
todir=arcdir;
}
}
if(nextnode==NULL){
break;
}
if((--arcstatus[row][col])==-3){
flows[row][col]+=todir*from->outcost;
nextnode->outcost+=from->outcost;
from->outcost=0;
}
}
return(from->outcost);
}
static
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;
mostflow=Short2DRowColAbsMax(flows,nrow,ncol);
if(mostflow<=maxflow){
return(TRUE);
}
fprintf(sp2,"Maximum flow on network: %ld\n",mostflow);
cliplimit=(long )ceil(mostflow*CLIPFACTOR)+1;
if(maxflow>cliplimit){
cliplimit=maxflow;
}
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];
}
}
}
maxcost+=INITMAXCOSTINCR;
if(maxcost>=LARGESHORT){
fflush(NULL);
fprintf(sp0,"WARNING: escaping ClipFlow loop to prevent cost overflow\n");
return(TRUE);
}
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){
fflush(NULL);
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){
fflush(NULL);
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){
fflush(NULL);
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){
fflush(NULL);
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;
}
}
}
fprintf(sp2,"Flows clipped to %ld. Rerunning MST solver.\n",cliplimit);
return(FALSE);
}
int MCFInitFlows(float **wrappedphase, short ***flowsptr, short **mstcosts,
long nrow, long ncol, long cs2scalefactor){
#ifndef NO_CS2
signed char **residue;
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);
SolveCS2(residue,mstcosts,nrow,ncol,cs2scalefactor,flowsptr);
#endif
return(0);
}