예제 #1
0
/* 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);
}
예제 #2
0
void connect_enforce(struct vtx_data **graph,       /* data structure for graph */
                     int               nvtxs,       /* number of vertices in full graph */
                     int               using_ewgts, /* are edge weights being used? */
                     int *             assignment,  /* set number of each vtx (length n) */
                     double *          goal,        /* desired sizes for each set */
                     int               nsets_tot,   /* total number sets created */
                     int *             total_move,  /* total number of vertices moved */
                     int *             max_move     /* largest connected component moved */
                     )
{
  struct vtx_data **subgraph;           /* data structure for domain graph */
  int               subnvtxs;           /* number of vertices in a domain */
  int               subnedges;          /* number of edges in a domain */
  struct heap *     heap;               /* data structure for sorting set sizes */
  int *             heap_map;           /* pointers from sets to heap locations */
  int *             list_ptrs;          /* header of vtx list for each domain */
  int *             setlists;           /* linked list of vtxs for each domain */
  int *             vtxlist;            /* space for breadth first search list */
  int *             comp_lists;         /* list of vtxs in each connected comp */
  int *             clist_ptrs;         /* pointers to heads of comp_lists */
  int *             subsets;            /* list of active domains (all of them) */
  int *             subsets2;           /* list of active domains (all of them) */
  double *          set_size;           /* weighted sizes of different partitions */
  double            size;               /* size of subset being moved to new domain */
  int *             bndy_list;          /* list of domains adjacent to component */
  double *          bndy_size;          /* size of these boundaries */
  double *          comp_size;          /* sizes of different connected components */
  double            comp_size_max;      /* size of largest connected component */
  int               comp_max_index = 0; /* which component is largest? */
  int *             glob2loc;           /* global to domain renumbering */
  int *             loc2glob;           /* domain to global renumbering */
  int *             degree;             /* number of neighbors of a vertex */
  int *             comp_flag;          /* component number for each vtx */
  double            ewgt;               /* edge weight */
  int               nbndy;              /* number of sets adjecent to component */
  int               domain;             /* which subdomain I'm working on */
  int               new_domain;         /* subdomain to move some vertices to */
  double            max_bndy;           /* max connectivity to other domain */
  int               ncomps;             /* number of connected components */
  int               change;             /* how many vertices change set? */
  int               max_change;         /* largest subset moved together */
  int               vtx;                /* vertex in a connected component */
  int               set;                /* set a neighboring vertex is in */
  int               i, j, k, l;         /* loop counters */
  double            heap_extract_max();
  int               make_maps(), find_comps();
  void              make_setlists(), make_subgraph(), remake_graph();
  void              heap_build(), heap_update_val();

  change     = 0;
  max_change = 0;

  /* Allocate space & initialize some values. */

  set_size  = smalloc(nsets_tot * sizeof(double));
  bndy_size = smalloc(nsets_tot * sizeof(double));
  bndy_list = smalloc(nsets_tot * sizeof(int));

  setlists  = smalloc((nvtxs + 1) * sizeof(int));
  list_ptrs = smalloc(nsets_tot * sizeof(int));

  glob2loc = smalloc((nvtxs + 1) * sizeof(int));
  loc2glob = smalloc((nvtxs + 1) * sizeof(int));
  subsets  = smalloc(nsets_tot * sizeof(int));
  heap     = (struct heap *)smalloc((nsets_tot + 1) * sizeof(struct heap));
  heap_map = smalloc(nsets_tot * sizeof(int));

  for (i = 0; i < nsets_tot; i++) {
    set_size[i]  = 0;
    bndy_list[i] = 0;
    bndy_size[i] = 0;
    subsets[i]   = i;
  }

  for (i = 1; i <= nvtxs; i++) {
    set_size[assignment[i]] += graph[i]->vwgt;
  }

  for (i = 0; i < nsets_tot; i++) {
    heap[i + 1].tag = i;
    heap[i + 1].val = set_size[i] - goal[i];
  }

  make_setlists(setlists, list_ptrs, nsets_tot, subsets, assignment, NULL, nvtxs, TRUE);

  heap_build(heap, nsets_tot, heap_map);

  for (i = 0; i < nsets_tot; i++) {
    /* Find largest remaining set to work on next */
    size = heap_extract_max(heap, nsets_tot - i, &domain, heap_map);

    /* Construct subdomain graph. */
    subnvtxs = make_maps(setlists, list_ptrs, domain, glob2loc, loc2glob);
    if (subnvtxs > 1) {

      subgraph = (struct vtx_data **)smalloc((subnvtxs + 1) * sizeof(struct vtx_data *));
      degree   = smalloc((subnvtxs + 1) * sizeof(int));

      make_subgraph(graph, subgraph, subnvtxs, &subnedges, assignment, domain, glob2loc, loc2glob,
                    degree, using_ewgts);

      /* Find connected components. */
      comp_flag = smalloc((subnvtxs + 1) * sizeof(int));
      vtxlist   = smalloc(subnvtxs * sizeof(int));
      ncomps    = find_comps(subgraph, subnvtxs, comp_flag, vtxlist);
      sfree(vtxlist);

      /* Restore original graph */
      remake_graph(subgraph, subnvtxs, loc2glob, degree, using_ewgts);
      sfree(degree);
      sfree(subgraph);

      if (ncomps > 1) {

        /* Figure out sizes of components */
        comp_size = smalloc(ncomps * sizeof(double));
        for (j = 0; j < ncomps; j++) {
          comp_size[j] = 0;
        }
        for (j = 1; j <= subnvtxs; j++) {
          comp_size[comp_flag[j]] += graph[loc2glob[j]]->vwgt;
        }
        comp_size_max = 0;
        for (j = 0; j < ncomps; j++) {
          if (comp_size[j] > comp_size_max) {
            comp_size_max  = comp_size[j];
            comp_max_index = j;
          }
        }
        for (j = 0; j < ncomps; j++) {
          if (j != comp_max_index) {
            change += comp_size[j];
            if (comp_size[j] > max_change)
              max_change = comp_size[j];
          }
        }
        sfree(comp_size);

        /* Make data structures for traversing components */
        comp_lists = smalloc((subnvtxs + 1) * sizeof(int));
        clist_ptrs = smalloc(ncomps * sizeof(int));
        if (ncomps > nsets_tot) {
          subsets2 = smalloc(ncomps * sizeof(int));
          for (j        = 0; j < ncomps; j++)
            subsets2[j] = j;
        }
        else
          subsets2 = subsets;
        make_setlists(comp_lists, clist_ptrs, ncomps, subsets2, comp_flag, NULL, subnvtxs, TRUE);
        if (ncomps > nsets_tot) {
          sfree(subsets2);
        }

        /* Move all but the largest component. */
        ewgt = 1;
        for (j = 0; j < ncomps; j++)
          if (j != comp_max_index) {

            /* Figure out to which other domain it is most connected. */
            nbndy = 0;
            k     = clist_ptrs[j];
            while (k != 0) {
              vtx = loc2glob[k];
              for (l = 1; l <= graph[vtx]->nedges; l++) {
                set = assignment[graph[vtx]->edges[l]];
                if (set != domain) {
                  if (bndy_size[set] == 0)
                    bndy_list[nbndy++] = set;
                  if (using_ewgts)
                    ewgt = graph[vtx]->ewgts[l];
                  bndy_size[set] += ewgt;
                }
              }

              k = comp_lists[k];
            }

            /* Select a new domain. */
            /* Instead of just big boundary, penalize too-large sets. */
            /* Could be more aggressive to improve balance. */
            max_bndy   = 0;
            new_domain = -1;
            for (k = 0; k < nbndy; k++) {
              l = bndy_list[k];
              if (bndy_size[l] * goal[l] / (set_size[l] + 1) > max_bndy) {
                new_domain = bndy_list[k];
                max_bndy   = bndy_size[l] * goal[l] / (set_size[l] + 1);
              }
            }
            if (new_domain == -1) {
              printf("Error in connect_enforce: new_domain = -1.  Disconnected graph?\n");
              new_domain = domain;
            }

            /* Clear bndy_size array */
            for (k                    = 0; k < nbndy; k++)
              bndy_size[bndy_list[k]] = 0;

            k = clist_ptrs[j];

            size = 0;

            while (k != 0) {
              vtx             = loc2glob[k];
              assignment[vtx] = new_domain;
              size += graph[vtx]->vwgt;

              /* Finally, update setlists and list_ptrs */
              /* Note: current domain setlist now bad, but not used
                 again */
              setlists[vtx]         = list_ptrs[new_domain];
              list_ptrs[new_domain] = vtx;

              k = comp_lists[k];
            }
            /*
            printf("Updating set %d (from %d) to size %g\n", new_domain, domain,
            set_size[new_domain] + size - goal[new_domain]);
            */
            if (heap_map[new_domain] > 0) {
              set_size[new_domain] += size;
              heap_update_val(heap, heap_map[new_domain], set_size[new_domain] - goal[new_domain],
                              heap_map);
            }
          }

        sfree(clist_ptrs);
        sfree(comp_lists);
      }
      sfree(comp_flag);
    }
  }

  sfree(heap_map);
  sfree(heap);
  sfree(subsets);
  sfree(loc2glob);
  sfree(glob2loc);
  sfree(list_ptrs);
  sfree(setlists);
  sfree(bndy_list);
  sfree(bndy_size);
  sfree(set_size);

  *total_move = change;
  *max_move   = max_change;
}