/************************************************************************ * bdmatch.c * * Main function for bdmatch bp code. * * Copyright (C) 2008 Bert Huang * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "bdmatch.h" int THREADS = 4; int main(int argc, char *argv[]) { int i,j,k,N,*LB,*UB,*colsum,iter=1,converged, poscount,**inds, *rowcounts,**backinds,*colcounts,myCount[THREADS], **myRows, *updatethread, cbuffpos=0, oscillation = 10, row, col, nnz=0, iterchars, maxiter = MAX_ITER, verbose = 1, sparse = 1, flags = 0; float **W, **B, **oldB, change, *rowsums, *oldrowsums, val, rowf, colf, lbf, ubf, threshold, cbuff[CIRC_BUFF], Nf, nnzf; FILE *matrix=NULL, *bounds=NULL,*out=NULL; updateArgs *arg; pthread_t *beliefUpdates; /* load arguments from command line */ damping = 1; i = 1; while(ii+1) { matrix = fopen(argv[i+1],"r"); i+=2; flags++; } else { printf("Error, a filename must follow '-w'\n"); return 0; } } else if (strcmp(argv[i], "-o")==0) { if (argc>i+1) { out = fopen(argv[i+1],"w"); i+=2; flags++; } else { printf("Error, a filename must follow '-o'\n"); return 0; } } else if (strcmp(argv[i], "-d")==0) { if (argc>i+1) { bounds = fopen(argv[i+1],"r"); i+=2; flags++; } else { printf("Error, a filename must follow '-d'\n"); return 0; } } else if (strcmp(argv[i], "-i")==0) { if (argc>i+1) { maxiter = atoi(argv[i+1]); i+=2; } else { printf("Error, a number must follow '-i'\n"); return 0; } } else if (strcmp(argv[i], "-damp")==0) { if (argc>i+1) { damping = atof(argv[i+1]); i+=2; } else { printf("Error, a number must follow '-damp'\n"); } } else if (strcmp(argv[i], "-v")==0) { if (argc>i+1) { verbose = atoi(argv[i+1]); i+=2; } else { printf("Error, a number must follow '-v'\n"); } } else if (strcmp(argv[i], "-s")==0) { if (argc>i+1) { sparse = atoi(argv[i+1]); i+=2; } else { printf("Error, a number must follow '-s'\n"); } } else if (strcmp(argv[i], "-t")==0) { if (argc>i+1) { THREADS = atoi(argv[i+1]); i+=2; } else { printf("Error, a number must follow '-t'\n"); } } else if (strcmp(argv[i], "-h")==0) { printf("bdmatch version 0.1b\n"); printf("USAGE: bdmatch [-arg1 val] [-arg2 val] [..]\n\n"); printf("Flags:\n\n"); printf("\t-w [filename]\tWeight file\n"); printf("\t-d [filename]\tDegree file\n"); printf("\t-o [filename]\tOutput file\n"); printf("\t-i [integer]\tMaximum iterations (default 1000)\n"); printf("\t-damp [float]\tDamping proportion (default 1)\n"); printf("\t-h\t\tHelp\n"); printf("\t-s [0 1]\tSparse input (default 1)\n"); printf("\t-t [integer]\tNumber of threads (default 4)\n"); printf("\t-v [0 1 2]\tVerbose (default 1)\n"); printf("\n\nSparse format should have 'N nnz' as first line\n"); printf("bdmatch Copyright (C) 2008 Bert Huang\n"); printf("This program comes with ABSOLUTELY NO WARRANTY. "); printf("This is free software, and you are welcome to"); printf(" redistribute it under certain conditions. "); printf("See LICENSE for details.\n"); i++; } else { printf("Error, unrecognized command line argument\n"); return 0; } } if (flags<3) { printf("Error, need at least weights, degrees and output filenames\n"); return 0; } if (verbose>=1) { printf("Verbose level is %d. ", verbose); printf("Damping factor is %f. ", damping); printf("Running with %d threads.\n", THREADS); } fscanf(matrix, "%f %f\n", &Nf,&nnzf); nnz = (int)nnzf; N = (int)Nf; if (verbose>=1) printf("%d nodes, %d edges\n", N,nnz); /* allocate memory */ rowcounts = (int*)malloc(N*sizeof(int)); rowsums = (float*)malloc(N*sizeof(float)); oldrowsums = (float*)malloc(N*sizeof(float)); colcounts = (int*)malloc(N*sizeof(int)); backinds = (int**)malloc(N*sizeof(int*)); W = (float**)malloc(N*sizeof(float*)); B = (float**)malloc(N*sizeof(float*)); oldB = (float**)malloc(N*sizeof(float*)); inds = (int**)malloc(N*sizeof(int*)); /* first count nonzeros */ for (i=0; i=2) printf("Connecting node %d to %d with weight %f\n", row, col, val); W[row][rowcounts[row]] = val; B[row][rowcounts[row]] = val; oldB[row][rowcounts[row]] = val; inds[row][rowcounts[row]] = col; backinds[row][rowcounts[row]] = colcounts[col]++; rowcounts[row]++; } fclose(matrix); /* allocate and read in LB */ LB = (int*)malloc(N*sizeof(int)); UB = (int*)malloc(N*sizeof(int)); for (i=0; i=3) printf("bounds for %d, lb %d, ub %d\n", i, LB[i], UB[i]); } fclose(bounds); /*validate inputs */ for (i=0; iUB[i]) { printf("Lower bound cannot be greater than upper\n"); return 0; } } if (verbose>=1) printf("Data loaded. Starting BP\n"); colsum = (int*)malloc(N*sizeof(int)); /*split up threads */ for (i=0; i=1) printf("Iteration "); iterchars = 0; while(convergedCONVERG_THR && oscillation>0) { /* copy B */ for (i=0; ioldB = oldB; arg->B = B; arg->W = W; arg->LB = LB; arg->UB = UB; arg->rowcounts = rowcounts; arg->inds = inds; arg->backinds = backinds; arg->N = N; arg->myCount = myCount[i]; arg->myRows = myRows[i]; pthread_create(&beliefUpdates[i],NULL,updateB,arg); } for (i=0; i=1) { while(iterchars>0) { printf("\b"); iterchars--; } printf("%d",iter); iterchars = 1+log10(iter); fflush(stdout); } /* check for convergence */ if (iter%INTERVAL==0) { /* track changes */ cbuff[cbuffpos] = 0; for (i=0; i0) { cbuff[cbuffpos] += fabs(B[i][0]); } } for (i=0; i=CIRC_BUFF) cbuffpos = 0; for (i=0; imaxiter) { if (verbose>=1) printf("\nReached Maximum iterations.\n"); converged = 9999999; } iter++; } if (verbose>=1) { printf("\n"); if (change<=CONVERG_THR) { printf("Converged to stable beliefs in %d iterations\n",iter); } else if (oscillation<1) { printf("Stopped after reaching oscillation. \n"); printf("No feasible solution found or there are multiple maxima. "); printf("Outputting best approximate solution. Try damping.\n"); } } /* output P */ /*output P and B as sparse matrices */ for (i=0; i0) poscount++; if (LB[i]>=rowcounts[i]) { threshold = -INF; } else if (UB[i]<1) { threshold = INF; } else if (poscount>=UB[i]) { threshold = B[i][quickselect(B[i],rowcounts[i],UB[i]-1)]; } else if (poscount<=LB[i]) { if (LB[i]==0) threshold = INF; else threshold = B[i][quickselect(B[i],rowcounts[i],LB[i]-1)]; } else { threshold = B[i][quickselect(B[i],rowcounts[i],poscount-1)]; } colcounts[i] = 0; for (j=0; j=threshold),B[i][j]); if (verbose>=2) printf("%d %d %d %f\n", inds[i][j],i,(B[i][j]>=threshold),B[i][j]); } } fclose(out); /* clean up */ for (i=0; i