karger.c

Go to the documentation of this file.
00001 #include <math.h>
00002 #include <stdio.h>
00003 #include <stdlib.h>
00004 #include <malloc.h>
00005 #include <time.h>
00006 #include "karger.h"
00007 #include "bc_zeit.h"
00008 #include "eg_macros.h"
00009 
00010 int max_numiter = 0;
00011 
00012 #define MAXCKEYS 32768
00013 #define MAXALPHA 4
00014 #define MAXPSNODES 64
00015 #define RFACTOR 1000
00016 
00017 static int
00018    get_numiter(int nnode, int nedges, int alpha, double bound),
00019    create_cutset(int nnodes, int nps, int *psnodes, int *pssubset,
00020                  int nremain, int *edge, double *length, int *treeinf,
00021                  unsigned int *nkey, char *ckeys, int *cutset,
00022                  int *cutsize, double *cutweight, int *foundset),
00023   get_alphacut(int nnodes, int nedges, int *edge, double *length,
00024              int *treeinf, unsigned int *nkey, char *ckeys, int alpha,
00025              double bound, setlist **sets,
00026              int (*choose_edge)(int, int*, double*, double, void*, int*),
00027              void *process_info,
00028              int (*process_set)(int*, int, double, void*, setlist **)
00029              );
00030 
00031 static void
00032     merge_components(int comp1, int comp2, int *treeinf, int *newnode);
00033 
00034 
00035 /* nnodes, nedges, elist - graph with nnodes and nedges given in elist
00036    elen          - weight of edges
00037    alpha, bound  - want cuts with weight <= alpha * min-cut && <= bound
00038    maxtime, seed - maximum time, random seed (if 0, seed chosen from time)
00039    sets          - list of sets passed back
00040    choose_edge   - function to choose edge to be contracted, see choose_edge1
00041    process_info  - arbitrary info to be used in process_set
00042    process_set   - function to process and/or generated sets
00043 */
00044 int karger(int nnodes, int nedges, int *elist, double *elen, int alpha,
00045            double bound, double maxtime, int seed, setlist **sets,
00046            int (*choose_edge)(int, int*, double*, double, void*, int*),
00047            void *process_info,
00048            int (*process_set)(int*, int, double, void*, setlist **)
00049            )
00050 {
00051    int rval = PROCESS_OVER;
00052    int r = 0, i = 0;
00053    int *edge = NULL;
00054    double *length = NULL;
00055    int *treeinf = NULL;
00056    unsigned int *nkey = NULL, *nkeyp = NULL;
00057    char ckeys[MAXCKEYS];
00058    int numiter;
00059    double szeit = CCutil_zeit();
00060 
00061    if (nnodes <= 0 || nedges <= 0){
00062       fprintf(stderr,"Invalid # of nodes or # of edges\n");
00063       return PROCESS_ERROR;
00064    }
00065    if (elist == NULL || elen == NULL){
00066       fprintf(stderr,"Invalid edge or weight lists\n");
00067       return PROCESS_ERROR;
00068    }
00069    if (alpha < 0){
00070       fprintf(stderr,"Invalid alpha\n");
00071       return PROCESS_ERROR;
00072    }
00073    if (alpha > MAXALPHA){
00074       fprintf(stderr,"give alpha <= %d\n", MAXALPHA);
00075       return PROCESS_ERROR;
00076    }      
00077    if (bound <= 0){
00078       fprintf(stderr,"Invalid bound %f on cuts\n", bound);
00079       return PROCESS_ERROR;
00080    }
00081    if (sets == NULL){
00082       fprintf(stderr,"Null set list pointer\n");
00083       return PROCESS_ERROR;
00084    }
00085   if(seed == 0 ) seed = CCutil_zeit();
00086   srandom((unsigned int)seed);
00087 
00088    edge = MALLOC(2*nedges, int);
00089    length = MALLOC(nedges, double);
00090    treeinf = MALLOC(3*nnodes, int);
00091    nkey = MALLOC(nnodes, unsigned int);
00092    nkeyp = MALLOC(nnodes, unsigned int);
00093    if (edge == NULL || length == NULL || treeinf == NULL || nkey == NULL){
00094       fprintf(stderr,"Not enough mem for local arrays\n");
00095       rval = PROCESS_ERROR;
00096       goto CLEANUP;
00097    }
00098 
00099    /* copy the edges and lengths into local arrays */
00100    for (i=0; i<nedges; i++){
00101       edge[2*i] = elist[2*i];
00102       edge[2*i+1] = elist[2*i+1];
00103       length[i] = elen[i];
00104    }
00105 
00106    for (i=0; i<MAXCKEYS; i++)
00107       ckeys[i] = 0;
00108    for (i=0; i<nnodes; i++)
00109       nkeyp[i] = random();
00110 
00111    /*
00112    *sets = NULL;
00113    */
00114    numiter = get_numiter(nnodes, nedges, alpha, bound);
00115    for (r=0; r<numiter; r++){
00116       /* Initialize component info */
00117       for (i=0; i<nnodes; i++){
00118          treeinf[3*i] = i;
00119          treeinf[3*i+1] = 1;
00120          treeinf[3*i+2] = 0;
00121 
00122          /* assign random key to each node */
00123          nkey[i] = nkeyp[i];
00124       }
00125 
00126       if (maxtime < CCutil_zeit()-szeit){
00127          rval = PROCESS_OVER;
00128          goto CLEANUP;
00129       }
00130 
00131       rval = get_alphacut(nnodes, nedges, edge, length, treeinf, nkey, ckeys,
00132                           alpha, bound, sets, choose_edge, process_info,
00133                           process_set); 
00134       if (rval == PROCESS_OVER || rval == PROCESS_ERROR) 
00135       {
00136          goto CLEANUP;
00137       }
00138    }
00139    if(r == numiter) rval = 0;
00140 
00141 CLEANUP:
00142 
00143    fprintf(stdout, "\nKarger: number of iterations: %d, time %lf\n", r, 
00144             CCutil_zeit()-szeit);
00145 
00146    IFFREE(edge, int);
00147    IFFREE(length, double);
00148    IFFREE(treeinf, int);
00149    IFFREE(nkey, unsigned int);
00150    IFFREE(nkeyp, unsigned int);
00151 
00152    return rval;
00153 
00154 } /* end kargers */
00155 
00156 
00157 int choose_edge1(int nremain, int *edge, double *length, double tweight,
00158                  void *process_info, int *e)
00159 {
00160    int i, rval = 0;
00161    long maxwt;
00162    double twt, drandn;
00163 
00164    /* locate edge to be contracted */
00165    maxwt = (long)((tweight * (double)RFACTOR) + 0.5);
00166    drandn = (random() % maxwt) / RFACTOR;
00167 
00168    for (i=0, twt=0.0; i<nremain; i++){
00169       twt += length[i];
00170       if (drandn <= twt){
00171          *e = i;
00172          return rval;
00173       }
00174    }
00175    rval = 1;
00176    return rval;
00177 }
00178 
00179 int add_cut(int *cutset, int cutsize, double cutweight, void *process_info,
00180             setlist **sets)
00181 {
00182    int i = 0;
00183    setlist *tset = NULL;
00184    int rval = PROCESS_INCOMPLETE;
00185 
00186    tset = (setlist *) calloc(1, sizeof(setlist));
00187    if (tset == NULL){
00188       fprintf(stderr, "No memory in add_cut\n");
00189       return PROCESS_ERROR;
00190    }
00191    tset->setv = (int *) calloc((size_t)cutsize, sizeof(int));
00192    if (tset->setv == NULL){
00193       fprintf(stderr, "No memory in process_tsp\n");
00194       IFFREE(tset, setlist);
00195       return PROCESS_ERROR;
00196    }
00197    tset->setn = cutsize;
00198    tset->cutval = cutweight;
00199    tset->next = *sets;
00200    for (i=0; i<cutsize; i++)
00201       tset->setv[i] = cutset[i];
00202    *sets = tset;
00203 
00204    return rval;
00205 }
00206 
00207 int karg_getprob (char *fname, int *nnodes, int *nedges, int **elist, 
00208                   double **elen)
00209 {
00210     FILE *f = NULL;
00211     int i = 0;
00212     int n1 = 0, n2 = 0;
00213     double weight = 0;
00214 
00215     *elist = (int *) NULL;
00216     *elen  = (double *) NULL;
00217 
00218     if ((f = fopen (fname, "r")) == NULL) {
00219        fprintf (stderr, "Unable to open %s for input\n",fname);
00220        goto CLEANUP;
00221     }
00222 
00223     if (fscanf (f, "%d %d", nnodes, nedges) != 2) {
00224        fprintf (stderr, "File %s has invalid format\n",fname);
00225        goto CLEANUP;
00226     }
00227     printf ("Nodes: %d  Edges: %d\n", *nnodes, *nedges);
00228     fflush (stdout);
00229 
00230     *elist = MALLOC (2 * (*nedges), int);
00231     *elen  = MALLOC (*nedges, double);
00232     if (*elist == NULL || *elen == NULL) {
00233         fprintf (stderr, "out of memory in karg_getprob\n");
00234         goto CLEANUP;
00235     } 
00236 
00237     for (i = 0; i < *nedges; i++) {
00238        if (fscanf(f,"%d %d %lf", &n1, &n2, &weight) != 3) {
00239           fprintf (stderr, "%s has invalid input format\n",fname);
00240           goto CLEANUP;
00241        }
00242        if ((weight < 0) || (n1 == n2) || (n1 < 0) || (n2 < 0) ||
00243            (n1 >= *nnodes) || (n2 >= *nnodes)){
00244           fprintf (stderr, "%s has invalid input numbers\n",fname);
00245           goto CLEANUP;
00246        }
00247        (*elist)[2*i] = n1;
00248        (*elist)[2*i+1] = n2;
00249        (*elen)[i] = weight;
00250     }
00251     fclose (f);
00252     return 0;
00253 
00254 CLEANUP:
00255     
00256     *nnodes = 0;
00257     *nedges = 0;
00258     IFFREE(*elist, int);
00259     IFFREE(*elen, double);
00260     if (f) fclose (f);
00261     return 1;
00262 }
00263 
00264 int process_cut(int *cutset, int cutsize, double cutweight, void *process_info,
00265                 setlist **sets)
00266 {
00267    int i = 0;
00268    setlist *tset = NULL;
00269    int rval = PROCESS_INCOMPLETE;
00270    cuts_info *cinf = (cuts_info *)process_info;
00271 
00272    /* If cinf.val or 0 is in set, then ignore */
00273    for (i=0; i<cutsize; i++)
00274       if (cutset[i] == 0 || cutset[i] == cinf->val)
00275          return rval;
00276 
00277    /* if cut has node 2 stop
00278    for (i=0; i<cutsize; i++)
00279       if (cutset[i] == 2)
00280          return PROCESS_OVER;
00281    */
00282    tset = (setlist *) calloc(1, sizeof(setlist));
00283    if (tset == NULL){
00284       fprintf(stderr, "No memory in add_cut\n");
00285       return PROCESS_ERROR;
00286    }
00287    tset->setv = (int *) calloc((size_t)cutsize, sizeof(int));
00288    if (tset->setv == NULL){
00289       fprintf(stderr, "No memory in process_tsp\n");
00290       IFFREE(tset, setlist);
00291       return PROCESS_ERROR;
00292    }
00293    tset->setn = cutsize;
00294    tset->cutval = cutweight;
00295    tset->next = *sets;
00296    for (i=0; i<cutsize; i++)
00297       tset->setv[i] = cutset[i];
00298    *sets = tset;
00299 
00300    return rval;
00301 }
00302 
00303 /***************************************/
00304 /* From now on internal functions only */
00305 
00306 
00307 /* modify this function to return whatever you want */
00308 static int
00309 get_numiter(int nnode, int nedges, int alpha, double bound)
00310 {
00311    if (max_numiter == 0)
00312       return (alpha * nnode * (nnode - 1)) / 2;
00313    else
00314       return max_numiter;
00315 }
00316 
00317 static int
00318 get_alphacut(int nnodes, int nedges, int *edge, double *length,
00319              int *treeinf, unsigned int *nkey, char *ckeys, int alpha,
00320              double bound, setlist **sets,
00321              int (*choose_edge)(int, int*, double*, double, void*, int*),
00322              void *process_info,
00323              int (*process_set)(int*, int, double, void*, setlist **)
00324              )
00325 {
00326    int rval = PROCESS_INCOMPLETE;
00327    int ncontract = 0, nremain = 0, foundset = 0;
00328    int i = 0, j = 0, k = 0, e = 0;
00329    int newnode = 0, temp = 0;
00330    int comp1 = 0, comp2 = 0;
00331    int maxsets = 0, twoalpha = 0;
00332    int psnodes[MAXPSNODES],pssubset[MAXPSNODES], nps = 0;
00333    int *cutset = NULL, *setind = NULL, cutsize = 0;
00334    double temp1 = 0, tweight = 0;
00335    double cutweight = 0;
00336 
00337    if ((cutset = CALLOC(nnodes, int)) == NULL){
00338       fprintf(stderr, "No memory in get_alphacut()\n");
00339       return PROCESS_ERROR;
00340    }
00341    
00342    /* add up all edges */
00343    for (i=0, tweight=0.0; i<nedges; i++){
00344       tweight += length[i];
00345    }
00346    
00347    /* all edges remain, contracted 0 */
00348    nremain = nedges;
00349    ncontract = 0;
00350 
00351    /* need two X alpha nodes */
00352    twoalpha = alpha *2;
00353    
00354    /* contract till you have #nodes  = twoalpha left */
00355    for (ncontract = 0; ncontract < nnodes - twoalpha; ncontract++){
00356       if (nremain == 0)
00357          break;
00358 
00359       /* locate edge to be contracted */
00360       rval = choose_edge(nremain, edge, length, tweight, process_info, &e);
00361       if (rval) goto CLEANUP;
00362 
00363       if (e < 0 || e >= nremain){
00364          rval = PROCESS_ERROR;
00365          goto CLEANUP;
00366       }
00367 
00368       /* merge the two pseudo-nodes which form ends of the edges */
00369       comp1 = treeinf[ 3*edge[2*e] ];
00370       comp2 = treeinf[ 3*edge[2*e+1] ];
00371       merge_components(comp1, comp2, treeinf, &newnode);
00372 
00373       /* merge key */
00374       if (newnode == comp2)
00375          nkey[comp2] ^= nkey[comp1];
00376       else
00377          nkey[comp1] ^= nkey[comp2];
00378 
00379       /* move all edges lying within the pseudonode to the end */
00380       for (i=nremain-1; i>=0; i--){
00381          if (treeinf[ 3*edge[2*i] ] == treeinf[ 3*edge[2*i+1] ]){
00382             if (i != nremain-1){
00383                SWAP(edge[2*i], edge[2*(nremain-1)], temp);
00384                SWAP(edge[2*i+1], edge[2*(nremain-1)+1], temp);
00385                SWAP(length[i], length[nremain-1], temp1);
00386             }
00387             tweight -= length[nremain-1];
00388             nremain--;
00389          }
00390       }
00391 
00392    } /* end edges */
00393 
00394    if (nnodes - ncontract > MAXPSNODES){
00395       rval = PROCESS_ERROR;
00396       goto CLEANUP;
00397    }
00398 
00399    for (i=0, nps=0; i<nnodes; i++)
00400       if (treeinf[3*i+1] > 0) psnodes[nps++] = i;
00401 
00402    /* create indicator array */
00403    if ((setind = CALLOC(nnodes, int)) == NULL){
00404       fprintf(stderr, "No memory in get_alphacut()\n");
00405       rval = PROCESS_ERROR; goto CLEANUP;
00406    }
00407 
00408    /* If no edges remain, every node represents a cut */
00409    if (nremain == 0){
00410       for (i=0; i< nps; i++){
00411          pssubset[i] = 1;
00412 
00413          /* create cut-set */
00414          rval = create_cutset(nnodes, 1, &(psnodes[i]),&(pssubset[i]), nremain,
00415                               edge, length, treeinf, nkey, ckeys, cutset,
00416                               &cutsize, &cutweight, &foundset);
00417          if (rval) {rval = PROCESS_ERROR; goto CLEANUP; }
00418          if (foundset) continue;
00419          if (cutweight >= bound - TOLER) continue;
00420 
00421          /* process set */
00422          rval = process_set(cutset, cutsize, cutweight, process_info, sets);
00423 
00424          if (rval == PROCESS_ERROR || rval == PROCESS_OVER)
00425             goto CLEANUP;
00426 
00427          /* create negation */
00428          {
00429             //int k;
00430 
00431             for (k=0; k<nnodes; k++) setind[k] = 0;
00432             setind[psnodes[i]] = 1;
00433             for (k=0, cutsize = 0; k<nnodes; k++)
00434                if (!setind[treeinf[3*k]])
00435                   cutset[cutsize++] = k;
00436          }
00437 
00438          /* process negation */
00439          rval = process_set(cutset, cutsize, cutweight, process_info, sets);
00440 
00441          if (rval == PROCESS_ERROR || rval == PROCESS_OVER)
00442             goto CLEANUP;
00443       }
00444    }
00445    else{ /* nremain != 0 */
00446       /* generate sets using simple gray code */
00447       for (i=0; i<nps; i++)
00448          pssubset[i] = 0;
00449 
00450       maxsets = (1 << (nps-1)) - 1;
00451       for (i=0; i<maxsets; i++){
00452          for (j=0, k=1; j < nps; j++, k <<= 1){
00453             if ((k & i) == 0){
00454                pssubset[j] ^= 1;
00455                break;
00456             }
00457          }
00458          /* create cut-set */
00459          rval = create_cutset(nnodes, nps, psnodes, pssubset, nremain, edge,
00460                               length, treeinf, nkey, ckeys, cutset, &cutsize,
00461                               &cutweight, &foundset);
00462          if (rval) {rval = PROCESS_ERROR; goto CLEANUP; }
00463          if (foundset) continue;
00464          if (cutweight >= bound - TOLER) continue;
00465 
00466          /* process set */
00467          rval = process_set(cutset, cutsize, cutweight, process_info, sets);
00468 
00469          if (rval == PROCESS_ERROR || rval == PROCESS_OVER)
00470             goto CLEANUP;
00471 
00472          /* create negation */
00473          {
00474             //int k;
00475 
00476             for (k=0; k<nnodes; k++) setind[k] = 0;
00477 
00478             for (k=0; k<nps; k++)
00479                if (pssubset[k])
00480                   setind[psnodes[k]] = 1;
00481             for (k=0, cutsize = 0; k<nnodes; k++)
00482                if (!setind[treeinf[3*k]])
00483                   cutset[cutsize++] = k;
00484          }
00485 
00486          /* process negation */
00487          rval = process_set(cutset, cutsize, cutweight, process_info, sets);
00488          
00489          if (rval == PROCESS_ERROR || rval == PROCESS_OVER)
00490             goto CLEANUP;
00491 
00492       } /* end for all subsets */
00493    } /* nremain > 0 */
00494 
00495    rval = PROCESS_INCOMPLETE;
00496 
00497  CLEANUP:
00498    IFFREE(cutset, int);
00499    IFFREE(setind, int);
00500    return rval;
00501 
00502 } /* End get cut */
00503 
00504 static void
00505 merge_components(int comp1, int comp2, int *treeinf, int *newnode)
00506 {
00507    int cur, i, prev;
00508    int siz1, siz2, c1, c2;
00509 
00510    /* merge smaller comp */
00511    siz1 = treeinf[3*comp1+1];
00512    siz2 = treeinf[3*comp2+1];
00513 
00514    if (siz1 <= siz2){
00515       c1 = comp1;
00516       c2 = comp2;
00517    }
00518    else{
00519       c2 = comp1;
00520       c1 = comp2;
00521       siz1 = siz2;
00522    }
00523 
00524    for (i=0,cur=c1; i<siz1; i++){
00525       treeinf[3*cur] = c2;
00526       prev = cur;
00527       cur = treeinf[3*cur+2];
00528    }
00529    treeinf[3*c2+1] += siz1;
00530    treeinf[3*c1+1] = 0;
00531    treeinf[3*prev+2] = treeinf[3*c2+2];
00532    treeinf[3*c2+2] = c1;
00533    *newnode = c2;
00534 }
00535 
00536 
00537 /* This assumes that the function will be called for only one side of a cut,
00538    not for it's negation.
00539 */
00540 static int
00541 create_cutset(int nnodes, int nps, int *psnodes, int *pssubset,
00542               int nremain, int *edge, double *length, int *treeinf,
00543               unsigned int *nkey, char *ckeys, int *cutset,
00544               int *cutsize, double *cutweight, int *foundset)
00545 {
00546    int i = 0,tsiz = 0;
00547    unsigned int rkey = 0;
00548    int *setind = NULL, csiz = 0, stsiz = 0;
00549    int rval = 0;
00550 
00551    setind = CALLOC(nnodes, int);
00552    if (setind == NULL){
00553       fprintf(stderr, "No memory in create_cutset()\n");
00554       rval = 1;
00555       goto CLEANUP;
00556    }
00557 
00558    for (i=0, stsiz=0, csiz = 0; i<nps; i++){
00559       if (pssubset[i]){
00560          csiz += treeinf[3*psnodes[i]+1];
00561          setind[psnodes[i]] = 1;
00562          stsiz++;
00563       }
00564    }
00565 
00566    if (nps < 1 || stsiz < 1 || csiz < 1){
00567       fprintf(stderr, "Invalid input to process_set()\n");
00568       rval = 1;
00569       goto CLEANUP;
00570    }
00571 
00572    /* form the key for the smaller side of the cut and store */
00573    if (nnodes - csiz > csiz){
00574       for (i=0, rkey=0; i<nps; i++)
00575          if (pssubset[i])
00576             rkey ^= nkey[psnodes[i]];
00577    }
00578    else{
00579       for (i=0, rkey=0; i<nps; i++)
00580          if (!pssubset[i])
00581             rkey ^= nkey[psnodes[i]];
00582    }
00583    if (ckeys[rkey % MAXCKEYS] == 0){
00584       *foundset = 0;
00585       ckeys[rkey % MAXCKEYS] = 1;
00586    }
00587    else{ /* set found with high prob */
00588       *foundset = 1;
00589       goto CLEANUP;
00590    }
00591 
00592    for (i=0, (*cutweight)=0.0; i<nremain; i++)
00593       if (setind[ treeinf[ 3*edge[2*i] ]] != setind[treeinf[ 3*edge[2*i+1]]])
00594          (*cutweight) += length[i];
00595 
00596    *cutsize = csiz;
00597    for (i=0, csiz=0; i<nnodes; i++)
00598       if (setind[treeinf[3*i]])
00599          cutset[csiz++] = i;
00600 
00601    if (csiz != *cutsize){
00602       fprintf(stderr, "Some mistake in input to create_cutset\n");
00603       rval = 1;
00604    }
00605 
00606  CLEANUP:
00607    IFFREE(setind, int);
00608    return rval;
00609 }

Generated on Thu Oct 20 14:58:41 2005 for DominoParitySeparator by  doxygen 1.4.5