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
00036
00037
00038
00039
00040
00041
00042
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
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
00113
00114 numiter = get_numiter(nnodes, nedges, alpha, bound);
00115 for (r=0; r<numiter; r++){
00116
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
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 }
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
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
00273 for (i=0; i<cutsize; i++)
00274 if (cutset[i] == 0 || cutset[i] == cinf->val)
00275 return rval;
00276
00277
00278
00279
00280
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
00305
00306
00307
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
00343 for (i=0, tweight=0.0; i<nedges; i++){
00344 tweight += length[i];
00345 }
00346
00347
00348 nremain = nedges;
00349 ncontract = 0;
00350
00351
00352 twoalpha = alpha *2;
00353
00354
00355 for (ncontract = 0; ncontract < nnodes - twoalpha; ncontract++){
00356 if (nremain == 0)
00357 break;
00358
00359
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
00369 comp1 = treeinf[ 3*edge[2*e] ];
00370 comp2 = treeinf[ 3*edge[2*e+1] ];
00371 merge_components(comp1, comp2, treeinf, &newnode);
00372
00373
00374 if (newnode == comp2)
00375 nkey[comp2] ^= nkey[comp1];
00376 else
00377 nkey[comp1] ^= nkey[comp2];
00378
00379
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 }
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
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
00409 if (nremain == 0){
00410 for (i=0; i< nps; i++){
00411 pssubset[i] = 1;
00412
00413
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
00422 rval = process_set(cutset, cutsize, cutweight, process_info, sets);
00423
00424 if (rval == PROCESS_ERROR || rval == PROCESS_OVER)
00425 goto CLEANUP;
00426
00427
00428 {
00429
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
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{
00446
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
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
00467 rval = process_set(cutset, cutsize, cutweight, process_info, sets);
00468
00469 if (rval == PROCESS_ERROR || rval == PROCESS_OVER)
00470 goto CLEANUP;
00471
00472
00473 {
00474
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
00487 rval = process_set(cutset, cutsize, cutweight, process_info, sets);
00488
00489 if (rval == PROCESS_ERROR || rval == PROCESS_OVER)
00490 goto CLEANUP;
00491
00492 }
00493 }
00494
00495 rval = PROCESS_INCOMPLETE;
00496
00497 CLEANUP:
00498 IFFREE(cutset, int);
00499 IFFREE(setind, int);
00500 return rval;
00501
00502 }
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
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
00538
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
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{
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 }