/** * gts_eheap_remove: * @heap: a #GtsEHeap. * @p: a #GtsEHeapPair. * * Removes element corresponding to @p from @heap in O(log n). * * Returns: the element just removed from @heap. */ gpointer gts_eheap_remove (GtsEHeap * heap, GtsEHeapPair * p) { GtsEHeapPair ** pdata; GtsEHeapPair * parent; guint i, par; gpointer data; g_return_val_if_fail (heap != NULL, NULL); g_return_val_if_fail (p != NULL, NULL); pdata = (GtsEHeapPair **)heap->elts->pdata; i = p->pos; data = p->data; g_return_val_if_fail (i > 0 && i <= heap->elts->len, NULL); g_return_val_if_fail (p == pdata[i - 1], NULL); /* move element to the top */ while ((par = PARENT (i))) { parent = pdata[par - 1]; pdata[par - 1] = p; pdata[i - 1] = parent; p->pos = par; parent->pos = i; i = par; } gts_eheap_remove_top (heap, NULL); return data; }
static void surface_hf_refine (GtsSurface * s, CostFunc cost_func, gpointer cost_data, GtsStopFunc stop_func, gpointer stop_data) { GtsEHeap * heap; gdouble top_cost; guint nv = 4; GtsListFace * f; gpointer data[3]; g_return_if_fail (s != NULL); g_return_if_fail (cost_func != NULL); g_return_if_fail (stop_func != NULL); data[0] = heap = gts_eheap_new (NULL, NULL); data[1] = cost_func; data[2] = cost_data; gts_surface_foreach_face (s, (GtsFunc) list_face_update, data); while ((f = gts_eheap_remove_top (heap, &top_cost)) && !(*stop_func) (- top_cost, nv, stop_data)) { GtsVertex * v = LIST_FACE (f)->best; GSList * t, * i; LIST_FACE (f)->heap = NULL; gts_delaunay_add_vertex_to_face (s, v, GTS_FACE (f)); i = t = gts_vertex_triangles (v, NULL); while (i) { list_face_update (i->data, data); i = i->next; } g_slist_free (t); nv++; } if (f) LIST_FACE (f)->heap = NULL; gts_eheap_foreach (heap, (GFunc) list_face_clear_heap, NULL); gts_eheap_destroy (heap); }
static void surface_optimize (GtsSurface * surface, gdouble max_cost) { GtsEHeap * heap; GtsEdge * e; gdouble top_cost; heap = gts_eheap_new ((GtsKeyFunc) edge_swap_cost, NULL); gts_eheap_freeze (heap); gts_surface_foreach_edge (surface, (GtsFunc) create_heap_optimize, heap); gts_eheap_thaw (heap); gts_allow_floating_edges = TRUE; while ((e = gts_eheap_remove_top (heap, &top_cost)) && top_cost < max_cost) edge_swap (e, surface, heap); gts_allow_floating_edges = FALSE; if (e) GTS_OBJECT (e)->reserved = NULL; gts_eheap_foreach (heap, (GFunc) gts_object_reset_reserved, NULL); gts_eheap_destroy (heap); }
/** * gts_graph_bisection_bkl_refine: * @bg: a #GtsGraphBisection. * @mmax: the maximum number of unsuccessful successive moves. * @imbalance: the maximum relative imbalance allowed between the * weights of both halves of the partition. * * An implementation of the simplified boundary Kernighan-Lin * algorithm for graph bisection refinement as described in Karypis * and Kumar (1997). * * The algorithm stops if @mmax consecutive modes do not lead to a * decrease in the number of edges cut. This last @mmax moves are * undone. * * Returns: the decrease in the weight of the edges cut by the bisection. */ gdouble gts_graph_bisection_bkl_refine (GtsGraphBisection * bg, guint mmax, gfloat imbalance) { GtsEHeap * h1, * h2; GtsGNode * n; guint nm = 0, i; GtsGNode ** moves; gdouble bestcost = 0., totalcost = 0., best_balance; gboolean balanced = FALSE; g_return_val_if_fail (bg != NULL, 0.); g_return_val_if_fail (mmax > 0, 0.); g_return_val_if_fail (imbalance >= 0. && imbalance <= 1., 0.); h1 = gts_eheap_new ((GtsKeyFunc) node_move_cost1, bg); gts_eheap_freeze (h1); g_hash_table_foreach (bg->bg1, (GHFunc) build_bheap, h1); gts_eheap_thaw (h1); h2 = gts_eheap_new ((GtsKeyFunc) node_move_cost2, bg); gts_eheap_freeze (h2); g_hash_table_foreach (bg->bg2, (GHFunc) build_bheap, h2); gts_eheap_thaw (h2); moves = g_malloc (sizeof (GtsGNode *)*mmax); imbalance *= gts_graph_weight (bg->g); best_balance = fabs (gts_graph_weight (bg->g1) - gts_graph_weight (bg->g2)); if (best_balance <= imbalance) balanced = TRUE; do { GtsGraph * g1, * g2; GHashTable * bg1, * bg2; gdouble cost; if (gts_graph_weight (bg->g1) > gts_graph_weight (bg->g2)) { n = gts_eheap_remove_top (h1, &cost); g1 = bg->g1; g2 = bg->g2; bg1 = bg->bg1; bg2 = bg->bg2; } else { n = gts_eheap_remove_top (h2, &cost); g1 = bg->g2; g2 = bg->g1; bg1 = bg->bg2; bg2 = bg->bg1; } if (n) { gdouble balance; GTS_OBJECT (n)->reserved = n; gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n)); gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); g_hash_table_remove (bg1, n); if (gts_gnode_degree (n, g1)) g_hash_table_insert (bg2, n, n); update_neighbors (n, bg, h1, h2); totalcost += cost; balance = fabs (gts_graph_weight (g1) - gts_graph_weight (g2)); if (!balanced && balance <= imbalance) { bestcost = totalcost; best_balance = balance; balanced = TRUE; nm = 0; } else if (totalcost < bestcost && (balance < best_balance || balance <= imbalance)) { bestcost = totalcost; best_balance = balance; nm = 0; } else if (totalcost == bestcost && balance < best_balance) { best_balance = balance; nm = 0; } else moves[nm++] = n; } } while (n && nm < mmax); gts_container_foreach (GTS_CONTAINER (bg->g), (GtsFunc) gts_object_reset_reserved, NULL); gts_eheap_destroy (h1); gts_eheap_destroy (h2); /* undo last nm moves */ for (i = 0; i < nm; i++) { GtsGNode * n = moves[i]; GtsGraph * g1, * g2; GHashTable * bg1, * bg2; if (gts_containee_is_contained (GTS_CONTAINEE (n), GTS_CONTAINER (bg->g1))) { g1 = bg->g1; g2 = bg->g2; bg1 = bg->bg1; bg2 = bg->bg2; } else { g1 = bg->g2; g2 = bg->g1; bg1 = bg->bg2; bg2 = bg->bg1; } gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n)); gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); g_hash_table_remove (bg1, n); if (gts_gnode_degree (n, g1)) g_hash_table_insert (bg2, n, n); update_neighbors (n, bg, NULL, NULL); } g_free (moves); return bestcost; }
/** * gts_graph_bisection_kl_refine: * @bg: a #GtsGraphBisection. * @mmax: the maximum number of unsuccessful successive moves. * * An implementation of the simplified Kernighan-Lin algorithm for * graph bisection refinement as described in Karypis and Kumar * (1997). * * The algorithm stops if @mmax consecutive modes do not lead to a * decrease in the number of edges cut. This last @mmax moves are * undone. * * Returns: the decrease in the weight of the edges cut by the bisection. */ gdouble gts_graph_bisection_kl_refine (GtsGraphBisection * bg, guint mmax) { GtsEHeap * h1, * h2; GtsGNode * n; guint nm = 0, i; GtsGNode ** moves; gdouble bestcost = 0., totalcost = 0., best_balance; g_return_val_if_fail (bg != NULL, 0.); g_return_val_if_fail (mmax > 0, 0.); h1 = gts_eheap_new ((GtsKeyFunc) node_move_cost1, bg); gts_eheap_freeze (h1); gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) build_heap, h1); gts_eheap_thaw (h1); h2 = gts_eheap_new ((GtsKeyFunc) node_move_cost2, bg); gts_eheap_freeze (h2); gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) build_heap, h2); gts_eheap_thaw (h2); moves = g_malloc (sizeof (GtsGNode *)*mmax); best_balance = fabs (gts_graph_weight (bg->g1) - gts_graph_weight (bg->g2)); do { GtsGraph * g1, * g2; gdouble cost; if (gts_graph_weight (bg->g1) > gts_graph_weight (bg->g2)) { n = gts_eheap_remove_top (h1, &cost); g1 = bg->g1; g2 = bg->g2; } else { n = gts_eheap_remove_top (h2, &cost); g1 = bg->g2; g2 = bg->g1; } if (n) { GSList * i; GTS_OBJECT (n)->reserved = NULL; gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n)); gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); totalcost += cost; if (totalcost < bestcost) { bestcost = totalcost; nm = 0; } else if (totalcost == bestcost) { gdouble balance = fabs (gts_graph_weight (g1) - gts_graph_weight (g2)); if (balance < best_balance) { best_balance = balance; nm = 0; } } else moves[nm++] = n; i = GTS_SLIST_CONTAINER (n)->items; while (i) { GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); if (GTS_OBJECT (n1)->reserved && gts_containee_is_contained (GTS_CONTAINEE (n1), GTS_CONTAINER (bg->g))) { GtsEHeap * h = gts_containee_is_contained (GTS_CONTAINEE (n1), GTS_CONTAINER (bg->g1)) ? h1 : h2; gts_eheap_remove (h, GTS_OBJECT (n1)->reserved); GTS_OBJECT (n1)->reserved = gts_eheap_insert (h, n1); } i = i->next; } } } while (n && nm < mmax); gts_eheap_foreach (h1, (GFunc) gts_object_reset_reserved, NULL); gts_eheap_foreach (h2, (GFunc) gts_object_reset_reserved, NULL); gts_eheap_destroy (h1); gts_eheap_destroy (h2); /* undo last nm moves */ for (i = 0; i < nm; i++) { GtsGNode * n = moves[i]; GtsGraph * g1 = gts_containee_is_contained (GTS_CONTAINEE (n), GTS_CONTAINER (bg->g1)) ? bg->g1 : bg->g2; GtsGraph * g2 = g1 == bg->g1 ? bg->g2 : bg->g1; gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n)); gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); } g_free (moves); return bestcost; }
/** * gts_graph_bfgg_bisection: * @g: a #GtsGraph. * @ntry: the number of randomly selected initial seeds. * * An implementation of a "Breadth-First Graph Growing" algorithm. * * @ntry randomly chosen seeds are used and the best partition is retained. * * Returns: a new #GtsGraphBisection of @g. */ GtsGraphBisection * gts_graph_bfgg_bisection (GtsGraph * g, guint ntry) { gfloat size, bestcost = G_MAXFLOAT, smin; GtsGraph * bestg1 = NULL, * bestg2 = NULL; GtsEHeap * degree_heap; GtsGNode * seed; GtsGraphBisection * bg; g_return_val_if_fail (g != NULL, NULL); bg = g_malloc (sizeof (GtsGraphBisection)); bg->g = g; size = gts_graph_weight (g)/2.; smin = 0.9*size; degree_heap = gts_eheap_new ((GtsKeyFunc) degree_cost, g); gts_eheap_freeze (degree_heap); gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_seed, degree_heap); gts_eheap_thaw (degree_heap); while (ntry && ((seed = gts_eheap_remove_top (degree_heap, NULL)))) { GtsGraph * g1, * g2; GtsGNode * n; gdouble cost; GtsGraphTraverse * t = gts_graph_traverse_new (g, seed, GTS_BREADTH_FIRST, TRUE); g1 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass), g->node_class, g->edge_class); g2 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass), g->node_class, g->edge_class); while ((n = gts_graph_traverse_next (t))) if (gts_graph_weight (g1) + gts_gnode_weight (n) <= size) { gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); GTS_OBJECT (n)->reserved = n; } gts_graph_traverse_destroy (t); gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_unused, g2); cost = gts_graph_edges_cut_weight (g1); if (!bestg1 || (cost < bestcost && gts_graph_weight (g1) >= smin)) { if (bestg1) bestcost = cost; if (bestg1) gts_object_destroy (GTS_OBJECT (bestg1)); if (bestg2) gts_object_destroy (GTS_OBJECT (bestg2)); bestg1 = g1; bestg2 = g2; } else { gts_object_destroy (GTS_OBJECT (g1)); gts_object_destroy (GTS_OBJECT (g2)); } ntry--; } gts_eheap_destroy (degree_heap); #ifdef DEBUG fprintf (stderr, "bestcost: %5g g1: %5g|%5d g2: %5g|%5d\n", bestcost, gts_graph_weight (bestg1), gts_container_size (GTS_CONTAINER (bestg1)), gts_graph_weight (bestg2), gts_container_size (GTS_CONTAINER (bestg2))); #endif bg->g1 = bestg1; bg->g2 = bestg2; /* boundary nodes */ bg->bg1 = g_hash_table_new (NULL, NULL); gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) boundary_node1, bg); bg->bg2 = g_hash_table_new (NULL, NULL); gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) boundary_node2, bg); return bg; }
/** * gts_graph_ggg_bisection: * @g: a #GtsGraph. * @ntry: the number of randomly selected initial seeds. * * An implementation of the "Greedy Graph Growing" algorithm of * Karypis and Kumar (1997). * * @ntry randomly chosen seeds are used and the best partition is retained. * * Returns: a new #GtsGraphBisection of @g. */ GtsGraphBisection * gts_graph_ggg_bisection (GtsGraph * g, guint ntry) { gfloat size, bestcost = G_MAXFLOAT, smin; GtsGraph * bestg1 = NULL, * bestg2 = NULL; gboolean balanced = FALSE; GtsEHeap * degree_heap; GtsGNode * seed; GtsGraphBisection * bg; g_return_val_if_fail (g != NULL, NULL); bg = g_malloc (sizeof (GtsGraphBisection)); bg->g = g; size = gts_graph_weight (g)/2.; smin = 0.9*size; degree_heap = gts_eheap_new ((GtsKeyFunc) degree_cost, g); gts_eheap_freeze (degree_heap); gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_seed, degree_heap); gts_eheap_thaw (degree_heap); while (ntry && ((seed = gts_eheap_remove_top (degree_heap, NULL)))) { GtsGraph * g1, * g2; GtsGNode * n; gdouble cost; gpointer data[2]; GtsEHeap * heap; g1 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass), g->node_class, g->edge_class); g2 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass), g->node_class, g->edge_class); data[0] = g; data[1] = g1; heap = gts_eheap_new ((GtsKeyFunc) node_cost, data); gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed)); GTS_OBJECT (seed)->reserved = seed; gts_gnode_foreach_neighbor (seed, g, (GtsFunc) add_neighbor, heap); while ((n = gts_eheap_remove_top (heap, &cost))) if (gts_graph_weight (g1) + gts_gnode_weight (n) <= size) { gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); GTS_OBJECT (n)->reserved = n; gts_gnode_foreach_neighbor (n, g, (GtsFunc) add_neighbor, heap); } else GTS_OBJECT (n)->reserved = NULL; gts_eheap_destroy (heap); gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_unused, g2); cost = gts_graph_edges_cut_weight (g1); if (!bestg1 || (!balanced && gts_graph_weight (g1) >= smin) || (cost < bestcost && gts_graph_weight (g1) >= smin)) { if (bestg1) bestcost = cost; if (bestg1) gts_object_destroy (GTS_OBJECT (bestg1)); if (bestg2) gts_object_destroy (GTS_OBJECT (bestg2)); bestg1 = g1; bestg2 = g2; if (gts_graph_weight (g1) >= smin) balanced = TRUE; } else { gts_object_destroy (GTS_OBJECT (g1)); gts_object_destroy (GTS_OBJECT (g2)); } ntry--; } gts_eheap_destroy (degree_heap); #ifdef DEBUG fprintf (stderr, "bestcost: %5g g1: %5g|%5d g2: %5g|%5d\n", bestcost, gts_graph_weight (bestg1), gts_container_size (GTS_CONTAINER (bestg1)), gts_graph_weight (bestg2), gts_container_size (GTS_CONTAINER (bestg2))); #endif g_assert (bestg1 != NULL); bg->g1 = bestg1; g_assert (bestg2 != NULL); bg->g2 = bestg2; /* boundary nodes */ bg->bg1 = g_hash_table_new (NULL, NULL); gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) boundary_node1, bg); bg->bg2 = g_hash_table_new (NULL, NULL); gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) boundary_node2, bg); return bg; }