static int serial_fm2 (ZZ *zz, HGraph *hg, int p, float *part_sizes, Partition part, PHGPartParams *hgp, float bal_tol) { int i, j, vertex, edge, *pins[2], *locked = 0, *locked_list = 0, round = 0; double total_weight, part_weight[2], max_weight[2]; double cutsize_beforepass, best_cutsize, *gain = 0; HEAP heap[2]; int steplimit; char *yo="serial_fm2"; int part_dim = (hg->VtxWeightDim ? hg->VtxWeightDim : 1); #ifdef HANDLE_ISOLATED_VERTICES int isocnt=0; #endif #ifdef _DEBUG double tw0, imbal, cutsize; #endif double error, best_error; int best_imbalance, imbalance; if (p != 2) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "p!=2 not allowed for local_fm2."); return ZOLTAN_FATAL; } if (hg->nEdge == 0) return ZOLTAN_OK; /* Calculate the weights in each partition and total, then maxima */ part_weight[0] = 0.0; part_weight[1] = 0.0; if (hg->vwgt) { for (i = 0; i < hg->nVtx; i++) part_weight[part[i]] += hg->vwgt[i*hg->VtxWeightDim]; total_weight = part_weight[0] + part_weight[1]; } else { total_weight = (double)(hg->nVtx); for (i = 0; i < hg->nVtx; i++) part_weight[part[i]] += 1.0; } max_weight[0] = total_weight * bal_tol * part_sizes[0]; max_weight[1] = total_weight * bal_tol * part_sizes[part_dim]; #ifdef _DEBUG tw0 = total_weight * part_sizes[0]; #endif if (!(pins[0] = (int*) ZOLTAN_CALLOC(2*hg->nEdge, sizeof(int))) || !(locked = (int*) ZOLTAN_CALLOC(hg->nVtx, sizeof(int))) || !(locked_list = (int*) ZOLTAN_CALLOC(hg->nVtx, sizeof(int))) || !(gain = (double*)ZOLTAN_CALLOC(hg->nVtx, sizeof(double))) ) { Zoltan_Multifree(__FILE__,__LINE__, 4, &pins[0], &locked, &locked_list, &gain); ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Insufficient memory."); return ZOLTAN_MEMERR; } pins[1] = &(pins[0][hg->nEdge]); /* Initial calculation of the pins distribution and gain values */ for (i = 0; i < hg->nEdge; i++) for (j = hg->hindex[i]; j < hg->hindex[i+1]; j++) (pins[part[hg->hvertex[j]]][i])++; for (i = 0; i < hg->nVtx; i++) for (j = hg->vindex[i]; j < hg->vindex[i+1]; j++) { edge = hg->vedge[j]; if (pins[part[i]][edge] == 1) gain[i] += (hg->ewgt ? hg->ewgt[edge] : 1.0); else if (pins[1-part[i]][edge] == 0) gain[i] -= (hg->ewgt ? hg->ewgt[edge] : 1.0); } /* Initialize the heaps and fill them with the gain values */ Zoltan_Heap_Init(zz, &heap[0], hg->nVtx); Zoltan_Heap_Init(zz, &heap[1], hg->nVtx); for (i = 0; i < hg->nVtx; i++) if (!hgp->UseFixedVtx || hg->fixed_part[i]<0) { #ifdef HANDLE_ISOLATED_VERTICES if (hg->vindex[i+1]==hg->vindex[i]) { /* isolated vertex */ part_weight[part[i]] -= (hg->vwgt ? hg->vwgt[i*hg->VtxWeightDim] : 1.0); part[i] = -(part[i]+1); /* remove those vertices from that part*/ ++isocnt; } else #endif Zoltan_Heap_Input(&heap[part[i]], i, gain[i]); } #ifdef _DEBUG else { int pp = (hg->fixed_part[i] < hg->bisec_split) ? 0 : 1; if (part[i]!=pp) errexit("%s: beginning of pass for hg->info=%d vertex %d is fixed at %d bisec_split is %d but its part is %d\n", uMe(hg->comm), hg->info, i, hg->fixed_part[i], hg->bisec_split, part[i]); } #endif Zoltan_Heap_Make(&heap[0]); Zoltan_Heap_Make(&heap[1]); /* Initialize given partition as best partition */ best_cutsize = cutsize_beforepass = Zoltan_PHG_Compute_NetCut(hg->comm, hg, part); best_error = MAX (part_weight[0]-max_weight[0], part_weight[1]-max_weight[1]); best_imbalance = (part_weight[0]>max_weight[0])||(part_weight[1]>max_weight[1]); do { int step = 0, no_better_steps = 0, number_locked = 0, best_locked = 0; int sour, dest; double cur_cutsize=best_cutsize; round++; cutsize_beforepass = best_cutsize; if (hgp->output_level > PHG_DEBUG_LIST) printf("ROUND %d:\nSTEP VERTEX PARTS MAX_WGT CHANGE CUTSIZE\n",round); steplimit = (hgp->fm_max_neg_move < 0) ? hg->nVtx : hgp->fm_max_neg_move; /* steplimit = hg->nVtx/4; Robsys previous choice */ while (step < hg->nVtx && no_better_steps < steplimit) { step++; no_better_steps++; if (Zoltan_Heap_Empty(&heap[0])) sour = 1; else if (Zoltan_Heap_Empty(&heap[1])) sour = 0; else if (part_weight[0] > max_weight[0]) sour = 0; else if (part_weight[1] > max_weight[1]) sour = 1; else if (Zoltan_Heap_Max_Value(&heap[0]) > Zoltan_Heap_Max_Value(&heap[1])) sour = 0; else sour = 1; dest = 1-sour; vertex = Zoltan_Heap_Extract_Max(&heap[sour]); if (vertex<0) break; locked[vertex] = part[vertex] + 1; locked_list[number_locked++] = vertex; cur_cutsize -= gain[vertex]; Zoltan_HG_move_vertex (hg, vertex, sour, dest, part, pins, gain, heap); #ifdef _DEBUG imbal = (tw0==0.0) ? 0.0 : (part_weight[0]-tw0)/tw0; uprintf(hg->comm, "%4d: SEQ moving %4d from %d to %d cut=%6.0lf bal=%.3lf\n", step, vertex, sour, dest, cur_cutsize, imbal); /* Just for debugging */ cutsize = Zoltan_PHG_Compute_NetCut(hg->comm, hg, part); if (cur_cutsize!=cutsize) { errexit("%s: SEQ after move cutsize=%.2lf Verify: total=%.2lf\n", uMe(hg->comm), cur_cutsize, cutsize); } #endif part_weight[sour] -= (hg->vwgt ? hg->vwgt[vertex*hg->VtxWeightDim] : 1.0); part_weight[dest] += (hg->vwgt ? hg->vwgt[vertex*hg->VtxWeightDim] : 1.0); error = MAX (part_weight[0]-max_weight[0],part_weight[1]-max_weight[1]); imbalance = (part_weight[0]>max_weight[0])||(part_weight[1]>max_weight[1]); if ( ( best_imbalance && (error < best_error)) || (!imbalance && (cur_cutsize < best_cutsize))) { best_error = error; best_imbalance = imbalance; best_locked = number_locked; best_cutsize = cur_cutsize; no_better_steps = 0; } if (hgp->output_level > PHG_DEBUG_LIST+1) printf ("%4d %6d %2d->%2d %7.2f %f %f\n", step, vertex, sour, dest, error, cur_cutsize - cutsize_beforepass, cur_cutsize); } #ifdef _DEBUG uprintf(hg->comm, "SEQ Best CUT=%6.0lf at move %d\n", best_cutsize, best_locked); #endif /* rollback */ while (number_locked != best_locked) { vertex = locked_list[--number_locked]; sour = part[vertex]; dest = locked[vertex] - 1; Zoltan_HG_move_vertex (hg, vertex, sour, dest, part, pins, gain, heap); part_weight[sour] -= (hg->vwgt ? hg->vwgt[vertex*hg->VtxWeightDim] : 1.0); part_weight[dest] += (hg->vwgt ? hg->vwgt[vertex*hg->VtxWeightDim] : 1.0); Zoltan_Heap_Input(&heap[dest], vertex, gain[vertex]); locked[vertex] = 0; } /* only update data structures if we're going to do another pass */ if ((best_cutsize < cutsize_beforepass) && (round < hgp->fm_loop_limit)) { while (number_locked) { vertex = locked_list[--number_locked]; locked[vertex] = 0; Zoltan_Heap_Input(&heap[part[vertex]], vertex, gain[vertex]); } Zoltan_Heap_Make(&(heap[0])); Zoltan_Heap_Make(&(heap[1])); } } while ((best_cutsize < cutsize_beforepass) && (round < hgp->fm_loop_limit)); #ifdef HANDLE_ISOLATED_VERTICES if (isocnt) { #ifdef _DEBUG double isoimbalbefore, isoimbal; #endif double targetw0; targetw0 = total_weight * part_sizes[0]; #ifdef _DEBUG isoimbalbefore = (targetw0==0) ? 0.0 : (part_weight[0] - targetw0)/ targetw0; #endif for (i=0; i < hg->nVtx; ++i) if (!hgp->UseFixedVtx || hg->fixed_part[i]<0) { if (hg->vindex[i+1]==hg->vindex[i]) { /* go over isolated vertices */ int npno = (part_weight[0] < targetw0) ? 0 : 1; part_weight[npno] += (hg->vwgt ? hg->vwgt[i*hg->VtxWeightDim] : 1.0); part[i] = npno; } } #ifdef _DEBUG isoimbal = (targetw0==0) ? 0.0 : (part_weight[0] - targetw0)/ targetw0; uprintf(hg->comm, "SEQ %d isolated vertices, balance before: %.3lf after: %.3lf\n", isocnt, isoimbalbefore, isoimbal); #endif } #endif /* gain_check (hg, gain, part, pins); */ Zoltan_Multifree(__FILE__,__LINE__, 4, &pins[0], &locked, &locked_list, &gain); Zoltan_Heap_Free(&heap[0]); Zoltan_Heap_Free(&heap[1]); return ZOLTAN_OK; }
static int greedy_grow_part ( ZZ *zz, HGraph *hg, /* Hypergraph. */ int start_vtx, /* Start the ordering from this vertex. */ int p, /* Number of partitions (must be 2). */ float *part_sizes, /* Array of length p containing the percentages of work to be assigned to each partition. */ Partition part, /* Output: Partition array. */ PHGPartParams *hgp /* Partitioning parameters. */ ) { int i, j, vtx, edge, edgesize; int *cut[2]; double *gain = NULL; int vwgtdim = hg->VtxWeightDim; int part_dim = (hg->VtxWeightDim ? hg->VtxWeightDim : 1); double weight_sum, part_sum; double cutoff; double psize_sum= 0.0; HEAP h[2]; static char *yo = "greedy_grow_part"; int err=ZOLTAN_OK; /* Allocate arrays. */ if (!(gain = (double*) ZOLTAN_CALLOC (hg->nVtx, sizeof (double)))){ ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Insufficient memory."); err = ZOLTAN_MEMERR; goto End; } /* Initially put all vertices in part 0, except fixed ones. */ for (i=0; i<hg->nVtx; i++) part[i] = 0; if (hgp->UsePrefPart){ for (i=0; i<hg->nVtx; i++) if ((hg->bisec_split >= 0) && (hg->pref_part[i] >= hg->bisec_split)) part[i] = 1; } cut[0] = (int*) ZOLTAN_CALLOC (2*hg->nEdge, sizeof (int)); if ((hg->nEdge > 0 && cut[0] == NULL) ) { ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Insufficient memory."); err = ZOLTAN_MEMERR; goto End; } cut[1] = &(cut[0][hg->nEdge]); /* Initialize cut values. */ for (i=0; i<hg->nEdge; i++) for (j=hg->hindex[i]; j<hg->hindex[i+1]; j++) (cut[part[hg->hvertex[j]]][i])++; /* Initialize gain values. */ for (i=0; i<hg->nVtx; i++){ /* compute gain only if vertex is free */ if (!hgp->UseFixedVtx || (hg->fixed_part[i] < 0)) for (j=hg->vindex[i]; j<hg->vindex[i+1]; j++) { edge = hg->vedge[j]; edgesize = cut[0][edge]+cut[1][edge]; /* if edge is not cut by fixed vertices, update gain value */ if (MIN(cut[0][edge],cut[1][edge])==0) gain[i] -= (hg->ewgt ? (hg->ewgt[edge]) : 1.0); if (edgesize>1 && cut[part[i]][edge]==1) gain[i] += (hg->ewgt ? (hg->ewgt[edge]) : 1.0); } } /* Sum total weights. (No multi-weights yet) */ weight_sum = 0.; part_sum = 0.0; /* Weight in the growing partition (1) */ for (i=0; i<hg->nVtx; i++){ weight_sum += hg->vwgt[i*vwgtdim]; if (part[i]>0) part_sum += hg->vwgt[i*vwgtdim]; } /* Set cutoff for growing partition (1) */ psize_sum = part_sizes[0] + part_sizes[part_dim]; cutoff = weight_sum*part_sizes[part_dim]/psize_sum; if (hgp->output_level >= PHG_DEBUG_ALL) printf("Debug: Starting new greedy growing at vertex %d, part=%2d\n", start_vtx, p); /* Initialize heap. */ if (!hgp->UseFixedVtx) gain[start_vtx] = 1e10; /* Make start_vtx max value in heap. */ /* All other values should be negative. */ Zoltan_Heap_Init(zz, &h[0], hg->nVtx); Zoltan_Heap_Init(zz, &h[1], 0); /* Dummy heap, not used. */ for (i=0; i<hg->nVtx; i++){ /* Insert all non-fixed vertices into heap. */ if (!hgp->UseFixedVtx || (hg->fixed_part[i] < 0)) Zoltan_Heap_Input(h, i, gain[i]); } Zoltan_Heap_Make(h); while (part_sum < cutoff) { /* Get next vertex from heap */ vtx = Zoltan_Heap_Extract_Max(h); if (vtx < 0) { /* Empty heap: This can only happen if all vertices are fixed. */ break; } part_sum += hg->vwgt[vtx*vwgtdim]; part[vtx] = 1; if (hgp->output_level >= PHG_DEBUG_PRINT) printf("COARSE_PART vtx=%2d, part[%2d]=%2d, part_sum=%f\n", vtx,vtx,part[vtx],part_sum); /* Move vertex from part=0 to part=1. */ /* Update gain values for nbors. */ /* We use Zoltan_HG_move_vertex from the refinement code. */ Zoltan_HG_move_vertex(hg, vtx, 0, 1, part, cut, gain, h); } End: ZOLTAN_FREE (&gain); if (cut[0]) ZOLTAN_FREE (&cut[0]); Zoltan_Heap_Free (&h[0]); Zoltan_Heap_Free( &h[1]); return err; }