void coarsen_klv ( /* Coarsen until nvtxs < vmax, compute and uncoarsen. */ struct vtx_data **graph, /* array of vtx data for graph */ int nvtxs, /* number of vertices in graph */ int nedges, /* number of edges in graph */ int using_vwgts, /* are vertices weights being used? */ int using_ewgts, /* are edge weights being used? */ float *term_wgts[], /* weights for terminal propogation */ int igeom, /* dimension for geometric information */ float **coords, /* coordinates for vertices */ int vwgt_max, /* largest vertex weight */ int *assignment, /* processor each vertex gets assigned to */ double *goal, /* desired set sizes */ int architecture, /* 0 => hypercube, d => d-dimensional mesh */ int (*hops)[MAXSETS], /* cost of edge between sets */ int solver_flag, /* which eigensolver to use */ int ndims, /* number of eigenvectors to calculate */ int nsets, /* number of sets being divided into */ int vmax, /* largest subgraph to stop coarsening */ int mediantype, /* flag for different assignment strategies */ int mkconnected, /* enforce connectivity before eigensolve? */ double eigtol, /* tolerence in eigen calculation */ int nstep, /* number of coarsenings between RQI steps */ int step, /* current step number */ int **pbndy_list, /* pointer to returned boundary list */ double *weights, /* weights of vertices in each set */ int give_up /* has coarsening bogged down? */ ) { extern FILE *Output_File; /* output file or null */ extern int DEBUG_TRACE; /* trace the execution of the code */ extern int DEBUG_COARSEN; /* debug flag for coarsening */ extern double COARSEN_RATIO_MIN; /* vtx reduction demanded */ extern int COARSEN_VWGTS; /* use vertex weights while coarsening? */ extern int COARSEN_EWGTS; /* use edge weights while coarsening? */ extern int LIMIT_KL_EWGTS; /* limit edges weights in KL? */ extern int COARSE_KLV; /* apply klv as a smoother? */ extern int COARSE_BPM; /* apply bipartite matching/flow as a smoother? */ extern double KL_IMBALANCE; /* fractional imbalance allowed in KL */ struct vtx_data **cgraph; /* array of vtx data for coarsened graph */ double new_goal[MAXSETS];/* new goal if not using vertex weights */ double *real_goal; /* chooses between goal and new_goal */ double total_weight; /* total weight of vertices */ double goal_weight; /* total weight of vertices in goal */ float *cterm_wgts[MAXSETS]; /* terminal weights for coarse graph */ float *new_term_wgts[MAXSETS]; /* modified for Bui's method */ float **real_term_wgts; /* which of previous two to use */ float ewgt_max; /* largest edge weight in graph */ float *twptr = NULL; /* loops through term_wgts */ float *twptr_save = NULL;/* copy of twptr */ float *ctwptr; /* loops through cterm_wgts */ float **ccoords; /* coarse graph coordinates */ int *v2cv; /* mapping from vtxs to coarse vtxs */ int *flag; /* scatter array for coarse bndy vtxs */ int *bndy_list; /* list of vertices on boundary */ int *cbndy_list; /* list of vertices of coarse graph on boundary */ int *cassignment; /* set assignments for coarsened vertices */ int flattened; /* was this graph flattened? */ int list_length; /* length of boundary vtx list */ int cnvtxs; /* number of vertices in coarsened graph */ int cnedges; /* number of edges in coarsened graph */ int cvwgt_max; /* largest vertex weight in coarsened graph */ int nextstep; /* next step in RQI test */ int max_dev; /* largest allowed deviation from balance */ int i, j; /* loop counters */ int find_bndy(), flatten(); double find_maxdeg(); void makevwsqrt(), make_connected(), print_connected(), eigensolve(); void make_unconnected(), assign(), klvspiff(), coarsen1(), free_graph(); void compress_ewgts(), restore_ewgts(), count_weights(), bpm_improve(); void simple_part(); if (DEBUG_COARSEN > 0 || DEBUG_TRACE > 0) { printf("<Entering coarsen_kl, step=%d, nvtxs=%d, nedges=%d, vmax=%d>\n", step, nvtxs, nedges, vmax); } /* Is problem small enough to solve? */ if (nvtxs <= vmax || give_up) { real_goal = goal; simple_part(graph, nvtxs, assignment, nsets, 1, real_goal); list_length = find_bndy(graph, nvtxs, assignment, 2, &bndy_list); count_weights(graph, nvtxs, assignment, nsets + 1, weights, 1); max_dev = (step == 0) ? vwgt_max : 5 * vwgt_max; total_weight = 0; for (i = 0; i < nsets; i++) total_weight += real_goal[i]; if (max_dev > total_weight) max_dev = vwgt_max; goal_weight = total_weight * KL_IMBALANCE / nsets; if (goal_weight > max_dev) max_dev = goal_weight; if (COARSE_KLV) { klvspiff(graph, nvtxs, assignment, real_goal, max_dev, &bndy_list, weights); } if (COARSE_BPM) { bpm_improve(graph, assignment, real_goal, max_dev, &bndy_list, weights, using_vwgts); } *pbndy_list = bndy_list; return; } /* Otherwise I have to coarsen. */ flattened = FALSE; if (coords != NULL) { ccoords = smalloc(igeom * sizeof(float *)); } else { ccoords = NULL; } if (FLATTEN && step == 0) { flattened = flatten(graph, nvtxs, nedges, &cgraph, &cnvtxs, &cnedges, &v2cv, using_ewgts && COARSEN_EWGTS, igeom, coords, ccoords); } if (!flattened) { coarsen1(graph, nvtxs, nedges, &cgraph, &cnvtxs, &cnedges, &v2cv, igeom, coords, ccoords, using_ewgts && COARSEN_EWGTS); } if (term_wgts[1] != NULL) { twptr = smalloc((cnvtxs + 1) * (nsets - 1) * sizeof(float)); twptr_save = twptr; for (i = (cnvtxs + 1) * (nsets - 1); i; i--) { *twptr++ = 0; } twptr = twptr_save; for (j = 1; j < nsets; j++) { cterm_wgts[j] = twptr; twptr += cnvtxs + 1; } for (j = 1; j < nsets; j++) { ctwptr = cterm_wgts[j]; twptr = term_wgts[j]; for (i = 1; i < nvtxs; i++) { ctwptr[v2cv[i]] += twptr[i]; } } } else { cterm_wgts[1] = NULL; } /* If coarsening isn't working very well, give up and partition. */ give_up = FALSE; if (nvtxs * COARSEN_RATIO_MIN < cnvtxs && cnvtxs > vmax && !flattened) { printf("WARNING: Coarsening not making enough progress, nvtxs = %d, cnvtxs = %d.\n", nvtxs, cnvtxs); printf(" Recursive coarsening being stopped prematurely.\n"); if (Output_File != NULL) { fprintf(Output_File, "WARNING: Coarsening not making enough progress, nvtxs = %d, cnvtxs = %d.\n", nvtxs, cnvtxs); fprintf(Output_File, " Recursive coarsening being stopped prematurely.\n"); } give_up = TRUE; } /* Now recurse on coarse subgraph. */ if (COARSEN_VWGTS) { cvwgt_max = 0; for (i = 1; i <= cnvtxs; i++) { if (cgraph[i]->vwgt > cvwgt_max) cvwgt_max = cgraph[i]->vwgt; } } else cvwgt_max = 1; cassignment = smalloc((cnvtxs + 1) * sizeof(int)); if (flattened) nextstep = step; else nextstep = step + 1; coarsen_klv(cgraph, cnvtxs, cnedges, COARSEN_VWGTS, COARSEN_EWGTS, cterm_wgts, igeom, ccoords, cvwgt_max, cassignment, goal, architecture, hops, solver_flag, ndims, nsets, vmax, mediantype, mkconnected, eigtol, nstep, nextstep, &cbndy_list, weights, give_up); /* Interpolate assignment back to fine graph. */ for (i = 1; i <= nvtxs; i++) { assignment[i] = cassignment[v2cv[i]]; } /* Construct boundary list from coarse boundary list. */ flag = smalloc((cnvtxs + 1) * sizeof(int)); for (i = 1; i <= cnvtxs; i++) { flag[i] = FALSE; } for (i = 0; cbndy_list[i]; i++) { flag[cbndy_list[i]] = TRUE; } list_length = 0; for (i = 1; i <= nvtxs; i++) { if (flag[v2cv[i]]) ++list_length; } bndy_list = smalloc((list_length + 1) * sizeof(int)); list_length = 0; for (i = 1; i <= nvtxs; i++) { if (flag[v2cv[i]]) bndy_list[list_length++] = i; } bndy_list[list_length] = 0; sfree(flag); sfree(cbndy_list); /* Free the space that was allocated. */ sfree(cassignment); if (twptr_save != NULL) { sfree(twptr_save); twptr_save = NULL; } free_graph(cgraph); sfree(v2cv); /* Smooth using KL or BPM every nstep steps. */ if (!(step % nstep) && !flattened) { if (!COARSEN_VWGTS && step != 0) { /* Construct new goal */ goal_weight = 0; for (i = 0; i < nsets; i++) goal_weight += goal[i]; for (i = 0; i < nsets; i++) new_goal[i] = goal[i] * (nvtxs / goal_weight); real_goal = new_goal; } else real_goal = goal; if (LIMIT_KL_EWGTS) { find_maxdeg(graph, nvtxs, using_ewgts, &ewgt_max); compress_ewgts(graph, nvtxs, nedges, ewgt_max, using_ewgts); } /* If not coarsening ewgts, then need care with term_wgts. */ if (!using_ewgts && term_wgts[1] != NULL && step != 0) { twptr = smalloc((nvtxs + 1) * (nsets - 1) * sizeof(float)); twptr_save = twptr; for (j = 1; j < nsets; j++) { new_term_wgts[j] = twptr; twptr += nvtxs + 1; } for (j = 1; j < nsets; j++) { twptr = term_wgts[j]; ctwptr = new_term_wgts[j]; for (i = 1; i <= nvtxs; i++) { if (twptr[i] > .5) ctwptr[i] = 1; else if (twptr[i] < -.5) ctwptr[i] = -1; else ctwptr[i] = 0; } } real_term_wgts = new_term_wgts; } else { real_term_wgts = term_wgts; new_term_wgts[1] = NULL; } max_dev = (step == 0) ? vwgt_max : 5 * vwgt_max; total_weight = 0; for (i = 0; i < nsets; i++) { total_weight += real_goal[i]; } if (max_dev > total_weight) max_dev = vwgt_max; goal_weight = total_weight * KL_IMBALANCE / nsets; if (goal_weight > max_dev) { max_dev = goal_weight; } if (!COARSEN_VWGTS) { count_weights(graph, nvtxs, assignment, nsets + 1, weights, (vwgt_max != 1)); } if (COARSE_KLV) { klvspiff(graph, nvtxs, assignment, real_goal, max_dev, &bndy_list, weights); } if (COARSE_BPM) { bpm_improve(graph, assignment, real_goal, max_dev, &bndy_list, weights, using_vwgts); } if (real_term_wgts != term_wgts && new_term_wgts[1] != NULL) { sfree(real_term_wgts[1]); } if (LIMIT_KL_EWGTS) restore_ewgts(graph, nvtxs); } *pbndy_list = bndy_list; if (twptr_save != NULL) { sfree(twptr_save); twptr_save = NULL; } /* Free the space that was allocated. */ if (ccoords != NULL) { for (i = 0; i < igeom; i++) sfree(ccoords[i]); sfree(ccoords); } if (DEBUG_COARSEN > 0) { printf(" Leaving coarsen_klv, step=%d\n", step); } }
/* Perform KL between two sets. */ int kl_refine ( struct vtx_data **graph, /* graph data structure */ struct vtx_data **subgraph, /* space for subgraph to refine */ struct bilist *set_list, /* lists of vtxs in each set */ struct bilist *vtx_elems, /* start of storage for lists */ int *new_assign, /* set assignments for all vertices */ int set1, int set2, /* two sets being refined */ int *glob2loc, /* maps vertices to subgraph vertices */ int *loc2glob, /* maps subgraph vertices to vertices */ int *sub_assign, /* new assignment for subgraphs */ int *old_sub_assign, /* current assignment for subgraphs */ int *degrees, /* space for forming subgraphs */ int using_ewgts, /* are edge weights being used? */ int (*hops)[MAXSETS], /* KL set preferences */ double *goal, /* desired set sizes */ int *sizes, /* number of vertices in different sets */ float *term_wgts[], /* space for terminal propagation weights */ int architecture, /* 0 => hypercube, d => d-dimensional mesh */ int mesh_dims[3] /* if mesh, how big is it? */ ) { extern int TERM_PROP; /* perform terminal propagation? */ extern double KL_IMBALANCE; /* fractional imbalance allowed in KL */ struct bilist *ptr; /* element in set_list */ double subgoal[2]; /* goal within two subgraphs */ double weights[2]; /* weights for each set */ double maxdeg; /* largest degree of a vertex */ double ratio; /* set sizes / goals */ int *null_ptr; /* argument to klspiff */ int vwgt_max; /* largest vertex weight */ int max_dev; /* largest set deviation allowed in KL */ int subnvtxs; /* number of vtxs in subgraph */ int vwgt_sum1; /* sum of vertex wgts in first set */ int vwgt_sum2; /* sum of vertex wgts in second set */ int subnedges; /* number of edges in subgraph */ int setA, setB; /* two sets being refined */ int nsame; /* number of vertices not moved */ int vtx; /* vertex in subgraph */ int i; /* loop counter */ double find_maxdeg(); void make_maps_ref(), make_subgraph(), remake_graph(); void klspiff(), make_terms_ref(), count_weights(); /* Compute all the quantities I'll need. */ null_ptr = NULL; make_maps_ref(graph, set_list, vtx_elems, new_assign, sub_assign, set1, set2, glob2loc, loc2glob, &subnvtxs, &vwgt_max, &vwgt_sum1, &vwgt_sum2); for (i = 1; i <= subnvtxs; i++) old_sub_assign[i] = sub_assign[i]; /* Set up goals for this KL invocation. */ ratio = (vwgt_sum1 + vwgt_sum2) / (goal[set1] + goal[set2]); subgoal[0] = ratio * goal[set1]; subgoal[1] = ratio * goal[set2]; if (TERM_PROP) { make_terms_ref(graph, using_ewgts, subnvtxs, loc2glob, set1, set2, new_assign, architecture, mesh_dims, term_wgts); } /* New_assign has overwritten set2 with set1. */ make_subgraph(graph, subgraph, subnvtxs, &subnedges, new_assign, set1, glob2loc, loc2glob, degrees, using_ewgts); maxdeg = find_maxdeg(subgraph, subnvtxs, using_ewgts, (float *) NULL); count_weights(subgraph, subnvtxs, sub_assign, 2, weights, (vwgt_max != 1)); max_dev = vwgt_max; ratio = (subgoal[0] + subgoal[1]) * KL_IMBALANCE / 2; if (ratio > max_dev) { max_dev = ratio; } klspiff(subgraph, subnvtxs, sub_assign, 2, hops, subgoal, term_wgts, max_dev, maxdeg, using_ewgts, &null_ptr, weights); /* Figure out which modification leaves most vertices intact. */ nsame = 0; for (i = 1; i <= subnvtxs; i++) { if (old_sub_assign[i] == sub_assign[i]) nsame++; } if (2 * nsame > subnvtxs) { setA = set1; setB = set2; } else { setA = set2; setB = set1; } /* Now update the assignments. */ sizes[setA] = sizes[setB] = 0; for (i = 1; i <= subnvtxs; i++) { vtx = loc2glob[i]; /* Update the set_lists. */ ptr = &(vtx_elems[vtx]); if (ptr->next != NULL) { ptr->next->prev = ptr->prev; } if (ptr->prev != NULL) { ptr->prev->next = ptr->next; } if (sub_assign[i] == 0) { new_assign[vtx] = (int) setA; ++sizes[setA]; ptr->next = set_list[setA].next; if (ptr->next != NULL) ptr->next->prev = ptr; ptr->prev = &(set_list[setA]); set_list[setA].next = ptr; } else { new_assign[vtx] = (int) setB; ++sizes[setB]; ptr->next = set_list[setB].next; if (ptr->next != NULL) ptr->next->prev = ptr; ptr->prev = &(set_list[setB]); set_list[setB].next = ptr; } } remake_graph(subgraph, subnvtxs, loc2glob, degrees, using_ewgts); return(nsame != subnvtxs); }
int main(int argc, char *argv[]) { struct Cell_head cellhd; struct Range range; char *name; /* input raster name */ char *result; /* output raster name */ char *mapset; /* mapset name */ DCELL *inrast; /* input buffer */ DCELL *outrast; /* output buffer */ int row,col; int infd, outfd; /* file descriptor */ int verbose; double *weights; /* array of weights */ DCELL **D_rows; DCELL *tmp; int nrows; int ncols; double min, max; /* raster map range */ RASTER_MAP_TYPE data_type; /* type of the map */ void *values; /* neighborhood values */ int n,i; /* number of neighborhood cells */ int size; /* matrix size */ double ssigma; /* sigma of the spatial part */ double csigma; /* sigma of the color part */ char title[1024]; /* map title */ struct GModule *module; /* GRASS module for parsing arguments */ struct { struct Option *input, *output; struct Option *sigma_s, *sigma_c, *size; struct Option *title; } parm; struct { struct Flag *quiet; struct Flag *print_sigmas; } flag; /* initialize GIS environment */ G_gisinit(argv[0]); /* reads grass env, stores program name to G_program_name */ /* initialize module */ module = G_define_module(); module->description = ("Gaussian filter for raster maps."); /* Define the different options */ parm.input = G_define_option() ; parm.input->key = "input"; parm.input->type = TYPE_STRING; parm.input->required = YES; parm.input->description= ("Name of an input layer" ); parm.output = G_define_option() ; parm.output->key = "output"; parm.output->type = TYPE_STRING; parm.output->required = YES; parm.output->description= ("Name of an output layer"); parm.sigma_s = G_define_option() ; parm.sigma_s->key = "ssigma"; parm.sigma_s->type = TYPE_DOUBLE; parm.sigma_s->required = NO; parm.sigma_s->description= ("Sigma for space part of the filter\n\t(default: 0.465*((size-1)/2)"); parm.sigma_c = G_define_option() ; parm.sigma_c->key = "csigma"; parm.sigma_c->type = TYPE_DOUBLE; parm.sigma_c->required = NO; parm.sigma_c->description= ("Sigma for color part of the filter\n(default: 0.465*((color_range)/2)"); parm.size = G_define_option() ; parm.size->key = "size"; parm.size->type = TYPE_INTEGER; parm.size->required = YES; parm.size->description= ("Size of the matrix (odd number)"); flag.print_sigmas = G_define_flag() ; flag.print_sigmas->key = 's' ; flag.print_sigmas->description = "Print calculated values for sigmas" ; flag.quiet = G_define_flag() ; flag.quiet->key = 'q' ; flag.quiet->description = "Quiet" ; /* options and flags pareser */ if (G_parser(argc, argv)) exit (-1); /* stores options and flags to variables */ name = parm.input->answer; result = parm.output->answer; verbose = (! flag.quiet->answer); sscanf(parm.size->answer, "%d", &size); if (!parm.sigma_s->answer) ssigma = 0.465*((size-1)/2); else sscanf(parm.sigma_s->answer, "%lf", &ssigma); /* controlling the input values */ if (size%2 == 0) G_fatal_error("Size <%d> is not odd number", size); /* returs NULL if the map was not found in any mapset, * mapset name otherwise*/ mapset = G_find_cell2 (name, ""); if (mapset == NULL) G_fatal_error ("cell file [%s] not found", name); /* color sigma next */ if (!parm.sigma_c->answer) { if (G_read_range(name, mapset, &range) < 0) G_fatal_error("Could not read the raster map range"); /* for raster maps with range from 0-255 the result * should be around 60 */ min = (double)range.min; max = (double)range.max; csigma = 0.456*(max - min)/2; } else sscanf(parm.sigma_c->answer, "%lf", &csigma); /* print if appropriate */ if (flag.print_sigmas->answer) printf("Space sigma: %f\nColor sigma: %f\n", ssigma, csigma); if (G_legal_filename (result) < 0) G_fatal_error ("[%s] is an illegal name", result); /* count weights */ weights = (double *)malloc(size * size * sizeof(double)); /* stores values of gauss. bell into 'weigts'*/ count_weights(weights, size, ssigma); /* determine the inputmap type (CELL/FCELL/DCELL) */ data_type = G_raster_map_type(name, mapset); /* G_open_cell_old - returns file destriptor (>0) */ if ( (infd = G_open_cell_old (name, mapset)) < 0) G_fatal_error ("Cannot open cell file [%s]", name); /* controlling, if we can open input raster */ if (G_get_cellhd (name, mapset, &cellhd) < 0) G_fatal_error ("Cannot read file header of [%s]", name); /* Allocate input buffer */ inrast = G_allocate_raster_buf(data_type); /* Allocate output buffer, use input map data_type */ nrows = G_window_rows(); ncols = G_window_cols(); outrast = G_allocate_d_raster_buf(); /* Allocate values buffers */ values = (DCELL *) malloc(size * size * sizeof(DCELL)); /* allocating memory for rows */ D_rows = (DCELL **)malloc(size * sizeof(DCELL)); for (i = 0; i < size; i++) { D_rows[i] = G_allocate_raster_buf(DCELL_TYPE); } if (values == NULL) G_fatal_error("Cannot allocate memory"); /* controlling, if we can write the raster */ if ( (outfd = G_open_raster_new (result, data_type)) < 0) G_fatal_error ("Could not open <%s>",result); /* write first rows as NULL values */ for (row = 0; row < size/2; row++) { G_set_d_null_value(outrast, ncols); if (G_put_d_raster_row (outfd, outrast) < 0) G_fatal_error ("Cannot write to <%s>",result); } /* allocate first size/2 rows */ for (row = 0; row < size; row++) if (G_get_d_raster_row(infd, D_rows[row], row) < 0) G_fatal_error ("Could not open <%s>",result); /****************************************************************/ /* for each row inside the region */ for ( row = size/2; row < nrows - size/2; row++) { if (verbose) G_percent (row, nrows, 2); /* allocate new last row */ G_get_d_raster_row(infd, D_rows[size-1], row+(size/2)); /*process the data */ for (col=0; col < ncols; col++){ /* skip the outside columns */ if ( (col - size/2) < 0 || ncols <= (col + size/2)) { G_set_d_null_value(outrast, 1); } /* work only with columns, which are inside */ else { /* store values of the matrix into arry 'values', 'n' is * number of elements of the matrix */ n = D_gather(infd, values, D_rows, col, row,size); ((DCELL *)outrast)[col] = D_bilateral(values, ssigma, csigma, size, weights); } } /* for each column */ /* write raster row to output raster file */ G_put_d_raster_row (outfd, outrast); /* switch rows */ tmp = D_rows[0]; for (i = 0; i < size; i++){ D_rows[i] = D_rows[i + 1]; } D_rows[size-1] = tmp; } /* for each row */ /* write last rows as NULL values */ for (i = 0; i < size/2; i++) { G_set_d_null_value(outrast, ncols); G_put_d_raster_row (outfd, outrast); } /* memory cleaning */ G_free(outrast); G_free(inrast); G_free(values); for (i = 0; i < size; i++) { G_free(D_rows[i]); } free((void *) D_rows); /* closing rastr files */ G_close_cell (infd); G_close_cell (outfd); /* set the map title */ sprintf(title, "Bilateral filter of %s with %dx%d matrix: ssigma %.3f, csigma %.3f", name, size, size, ssigma, csigma ); G_put_cell_title (result, title ); return 0; }