pcb 4.1.1
An interactive printed circuit board layout editor.

partition.c

Go to the documentation of this file.
00001 /* GTS - Library for the manipulation of triangulated surfaces
00002  * Copyright (C) 1999 Stéphane Popinet
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Library General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Library General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Library General Public
00015  * License along with this library; if not, write to the
00016  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017  * Boston, MA 02111-1307, USA.
00018  */
00019 
00020 #include <math.h>
00021 
00022 #include "gts.h"
00023 
00024 /* #define DEBUG */
00025 
00026 /* Graph partition */
00027 
00034 guint gts_graph_partition_edges_cut (GSList * partition)
00035 {
00036   guint cuts = 0;
00037 
00038   while (partition) {
00039     cuts += gts_graph_edges_cut (partition->data);
00040     partition = partition->next;
00041   }
00042 
00043   return cuts/2;
00044 }
00045 
00052 gfloat gts_graph_partition_edges_cut_weight (GSList * partition)
00053 {
00054   gfloat weight = 0.;
00055 
00056   while (partition) {
00057     weight += gts_graph_edges_cut_weight (partition->data);
00058     partition = partition->next;
00059   }
00060 
00061   return weight/2.;
00062 }
00063 
00071 void gts_graph_partition_print_stats (GSList * partition,
00072                                       FILE * fp)
00073 {
00074   GtsRange weight;
00075   GSList * i;
00076 
00077   g_return_if_fail (partition != NULL);
00078   g_return_if_fail (fp != NULL);
00079 
00080   gts_range_init (&weight);
00081   i = partition;
00082   while (i) {
00083     gts_range_add_value (&weight, gts_graph_weight (i->data));
00084     i = i->next;
00085   }
00086   gts_range_update (&weight);
00087 
00088   fprintf (fp, 
00089            "# parts: %d\n"
00090            "#   edge cuts: %5d edge cuts weight: %5g\n"
00091            "#   weight: ",
00092            g_slist_length (partition),
00093            gts_graph_partition_edges_cut (partition),
00094            gts_graph_partition_edges_cut_weight (partition));
00095   gts_range_print (&weight, fp);
00096   fputc ('\n', fp);
00097 }
00098 
00106 gfloat gts_graph_partition_balance (GSList * partition)
00107 {
00108   gfloat wmin = G_MAXFLOAT;
00109   gfloat wmax = - G_MAXFLOAT;
00110 
00111   g_return_val_if_fail (partition != NULL, 0.);
00112 
00113   while (partition) {
00114     gfloat weight = gts_graph_weight (partition->data);
00115     if (weight < wmin)
00116       wmin = weight;
00117     if (weight > wmax)
00118       wmax = weight;
00119     partition = partition->next;
00120   }
00121   return wmax - wmin;
00122 }
00123 
00131 GSList * gts_graph_partition_clone (GSList * partition)
00132 {
00133   GSList * cparts = NULL;
00134 
00135   while (partition) {
00136     cparts = 
00137       g_slist_prepend (cparts, 
00138                        gts_object_clone (GTS_OBJECT (partition->data)));
00139     partition = partition->next;
00140   }
00141   return cparts;
00142 }
00143 
00150 void gts_graph_partition_destroy (GSList * partition)
00151 {
00152   GSList * i = partition;
00153 
00154   while (i) {
00155     gts_object_destroy (GTS_OBJECT (i->data));
00156     i = i->next;
00157   }
00158   g_slist_free (partition);
00159 }
00160 
00161 static void find_smallest_degree (GtsGNode * n, gpointer * data)
00162 {
00163   GtsGNode ** nmin = data[0];
00164   GtsGraph * g = data[1];
00165   guint * min = data[2];
00166   guint degree = gts_gnode_degree (n, g);
00167 
00168   if (degree < *min) {
00169     *min = degree;
00170     *nmin = n;
00171   }
00172 }
00173 
00174 static gint graph_comp_weight (GtsGraph * g1, GtsGraph * g2)
00175 {
00176   if (gts_graph_weight (g1) > gts_graph_weight (g2))
00177     return 1;
00178   return -1;
00179 }
00180 
00181 static void partition_update (GSList * list, GtsGraph * g)
00182 {
00183   GSList * i;
00184   GtsGraph * g1;
00185   GtsHeap * size_heap;
00186   gboolean reinit = TRUE;
00187 
00188   /* initialize traversals */
00189   i = list;
00190   while (i) {
00191     GtsGNode * seed = GTS_OBJECT (i->data)->reserved;
00192     GTS_OBJECT (seed)->reserved = 
00193       gts_graph_traverse_new (g, seed, GTS_BREADTH_FIRST, reinit);
00194     reinit = FALSE;
00195     i = i->next;
00196   }
00197   
00198   size_heap = gts_heap_new ((GCompareFunc) graph_comp_weight);
00199   i = list;
00200   while (i) {
00201     gts_heap_insert (size_heap, i->data);
00202     i = i->next;
00203   }
00204   while ((g1 = gts_heap_remove_top (size_heap))) {
00205     GtsGraphTraverse * t = GTS_OBJECT (GTS_OBJECT (g1)->reserved)->reserved;
00206     GtsGNode * n = gts_graph_traverse_next (t);
00207     if (n) {
00208       gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (n));
00209       gts_heap_insert (size_heap, g1);
00210     }
00211   }
00212   gts_heap_destroy (size_heap);
00213 
00214   /* destroy traversals */
00215   i = list;
00216   while (i) {
00217     GtsGNode * seed = GTS_OBJECT (i->data)->reserved;
00218     gts_graph_traverse_destroy (GTS_OBJECT (seed)->reserved);
00219     GTS_OBJECT (seed)->reserved = NULL;
00220     i = i->next;
00221   }
00222 }
00223 
00224 static void better_seed (GtsGNode * n, gpointer * data)
00225 {
00226   guint * sum = data[0];
00227   GtsGNode ** seed = data[1];
00228   GtsGraph * g = data[2];
00229   guint sum1 = gts_graph_distance_sum (g, n);
00230   
00231   if (sum1 < *sum) {
00232     *sum = sum1;
00233     *seed = n;
00234   }
00235 }
00236 
00237 static GtsGNode * graph_new_seed (GtsGraph * g, GtsGNode * seed)
00238 {
00239   guint sum = gts_graph_distance_sum (g, seed);
00240   gpointer data[3];
00241   GtsGNode * new_seed = seed;
00242 
00243   data[0] = &sum;
00244   data[1] = &new_seed;
00245   data[2] = g;
00246   gts_gnode_foreach_neighbor (seed, g, (GtsFunc) better_seed, data);
00247 
00248   return new_seed;
00249 }
00250 
00269 GSList * gts_graph_bubble_partition (GtsGraph * g, 
00270                                      guint np, 
00271                                      guint niter,
00272                                      GtsFunc step_info,
00273                                      gpointer data)
00274 {
00275   GSList * list = NULL, * seeds = NULL;
00276   GtsGNode * seed = NULL;
00277   guint min = G_MAXINT/2 - 1;
00278   gpointer info[3];
00279   GtsGraph * g1;
00280   gboolean changed = TRUE;
00281 
00282   g_return_val_if_fail (g != NULL, NULL);
00283   g_return_val_if_fail (np > 0, NULL);
00284 
00285   info[0] = &seed;
00286   info[1] = g;
00287   info[2] = &min;
00288   gts_container_foreach (GTS_CONTAINER (g), 
00289                          (GtsFunc) find_smallest_degree,
00290                          info);
00291   if (seed == NULL)
00292     return NULL;
00293 
00294   g1 = GTS_GRAPH (gts_object_new (GTS_OBJECT (g)->klass));
00295   gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed));
00296   list = g_slist_prepend (list, g1);
00297   GTS_OBJECT (g1)->reserved = seed;
00298   seeds = g_slist_prepend (seeds, seed);
00299 
00300   while (--np && seed)
00301     if ((seed = gts_graph_farthest (g, seeds))) {
00302       g1 = GTS_GRAPH (gts_object_new (GTS_OBJECT (g)->klass));
00303       gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed));
00304       list = g_slist_prepend (list, g1);
00305       GTS_OBJECT (g1)->reserved = seed;
00306       seeds = g_slist_prepend (seeds, seed);
00307     }
00308   g_slist_free (seeds);
00309   
00310   partition_update (list, g);
00311 
00312   while (changed && niter--) {
00313     GSList * i;
00314 
00315     changed = FALSE;
00316     i = list;
00317     while (i) {
00318       GtsGraph * g1 = i->data;
00319       GtsGNode * seed = GTS_OBJECT (g1)->reserved;
00320       GtsGNode * new_seed = graph_new_seed (g1, seed);
00321       if (new_seed != seed) {
00322         changed = TRUE;
00323         GTS_OBJECT (g1)->reserved = new_seed;
00324       }
00325       i = i->next;
00326     }
00327 
00328     if (changed) {
00329       i = list;
00330       while (i) {
00331         GtsGraph * g1 = i->data;
00332         GtsGNode * seed = GTS_OBJECT (g1)->reserved;
00333 
00334         gts_object_destroy (GTS_OBJECT (g1));
00335         i->data = g1 = GTS_GRAPH (gts_object_new (GTS_OBJECT (g)->klass));
00336         gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed));
00337         GTS_OBJECT (g1)->reserved = seed;
00338         i = i->next;
00339       }
00340       partition_update (list, g);
00341       if (step_info)
00342         (* step_info) (list, data);
00343     }
00344   }
00345   g_slist_foreach (list, (GFunc) gts_object_reset_reserved, NULL);
00346   return list;
00347 }
00348 
00349 /* Graph bisection */
00350 
00351 static gdouble node_cost (GtsGNode * n, gpointer * data)
00352 {
00353   GtsGraph * g = data[0];
00354   GtsGraph * g1 = data[1];
00355   GSList * i = GTS_SLIST_CONTAINER (n)->items;
00356   gdouble cost = 0.;
00357 
00358   while (i) {
00359     GtsGEdge * e = i->data;
00360     GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, e);
00361 
00362     if (gts_containee_is_contained (GTS_CONTAINEE (n1), GTS_CONTAINER (g))) {
00363       if (gts_containee_is_contained (GTS_CONTAINEE (n1), GTS_CONTAINER (g1)))
00364         cost -= gts_gedge_weight (e);
00365       else 
00366         cost += gts_gedge_weight (e);
00367     }
00368     i = i->next;
00369   }
00370 
00371   return cost;
00372 }
00373 
00374 static void add_neighbor (GtsGNode * n, GtsEHeap * heap)
00375 {
00376   if (GTS_OBJECT (n)->reserved == n)
00377     return;
00378   if (GTS_OBJECT (n)->reserved)
00379     gts_eheap_remove (heap, GTS_OBJECT (n)->reserved);
00380   GTS_OBJECT (n)->reserved = gts_eheap_insert (heap, n);
00381 }
00382 
00383 static void add_unused (GtsGNode * n, GtsGraph * g2)
00384 {
00385   if (GTS_OBJECT (n)->reserved)
00386     GTS_OBJECT (n)->reserved = NULL;
00387   else
00388     gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n));
00389 }
00390 
00391 static gdouble degree_cost (GtsGNode * n, GtsGraph * g)
00392 {
00393   return gts_gnode_degree (n, g); 
00394 }
00395 
00396 static void add_seed (GtsGNode * n, GtsEHeap * heap)
00397 {
00398   gts_eheap_insert (heap, n);
00399 }
00400 
00401 static void boundary_node1 (GtsGNode * n, GtsGraphBisection * bg)
00402 {
00403   GSList * i = GTS_SLIST_CONTAINER (n)->items;
00404 
00405   while (i) {
00406     GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data);
00407     if (gts_containee_is_contained (GTS_CONTAINEE (n1), 
00408                                     GTS_CONTAINER (bg->g2))) {
00409       g_hash_table_insert (bg->bg1, n, n1);
00410       return;
00411     }
00412     i = i->next;
00413   }
00414 }
00415 
00416 static void boundary_node2 (GtsGNode * n, GtsGraphBisection * bg)
00417 {
00418   GSList * i = GTS_SLIST_CONTAINER (n)->items;
00419 
00420   while (i) {
00421     GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data);
00422     if (gts_containee_is_contained (GTS_CONTAINEE (n1), 
00423                                     GTS_CONTAINER (bg->g1))) {
00424       g_hash_table_insert (bg->bg2, n, n1);
00425       return;
00426     }
00427     i = i->next;
00428   }
00429 }
00430 
00431 static void check_bg (GtsGNode * n, gpointer * data)
00432 {
00433   GHashTable * bg = data[0];
00434   GtsGraph * g = data[1];
00435   gboolean * ok = data[2];
00436   guint * nb = data[3];
00437   guint nn = gts_gnode_degree (n, g);
00438 
00439   if (nn > 0)
00440     (*nb)++;
00441   if ((nn > 0 && !g_hash_table_lookup (bg, n)) ||
00442       (nn == 0 && g_hash_table_lookup (bg, n))) {
00443     g_warning ("nn: %d lookup: %p\n",
00444                nn, g_hash_table_lookup (bg, n));
00445     *ok = FALSE;
00446   }
00447 }
00448 
00458 gboolean gts_graph_bisection_check (GtsGraphBisection * bg)
00459 {
00460   gboolean ok = TRUE;
00461   guint nb;
00462   gpointer data[4];
00463 
00464   g_return_val_if_fail (bg != NULL, FALSE);
00465 
00466   nb = 0;
00467   data[0] = bg->bg1;
00468   data[1] = bg->g2;
00469   data[2] = &ok;
00470   data[3] = &nb;
00471   gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) check_bg, data);
00472   g_return_val_if_fail (g_hash_table_size (bg->bg1) == nb, FALSE);
00473 
00474   nb = 0;
00475   data[0] = bg->bg2;
00476   data[1] = bg->g1;
00477   gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) check_bg, data);
00478   g_return_val_if_fail (g_hash_table_size (bg->bg2) == nb, FALSE);
00479 
00480   return ok;
00481 }
00482 
00495 GtsGraphBisection * gts_graph_ggg_bisection (GtsGraph * g, guint ntry)
00496 {
00497   gfloat size, bestcost = G_MAXFLOAT, smin;
00498   GtsGraph * bestg1 = NULL, * bestg2 = NULL;
00499   gboolean balanced = FALSE;
00500   GtsEHeap * degree_heap;
00501   GtsGNode * seed;
00502   GtsGraphBisection * bg;
00503 
00504   g_return_val_if_fail (g != NULL, NULL);
00505 
00506   bg = g_malloc (sizeof (GtsGraphBisection));
00507   bg->g = g;
00508 
00509   size = gts_graph_weight (g)/2.;
00510   smin = 0.9*size;
00511 
00512   degree_heap = gts_eheap_new ((GtsKeyFunc) degree_cost, g);
00513   gts_eheap_freeze (degree_heap);
00514   gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_seed, degree_heap);
00515   gts_eheap_thaw (degree_heap);
00516 
00517   while (ntry && ((seed = gts_eheap_remove_top (degree_heap, NULL)))) {
00518     GtsGraph * g1, * g2;
00519     GtsGNode * n;
00520     gdouble cost;
00521     gpointer data[2];
00522     GtsEHeap * heap;
00523   
00524     g1 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass),
00525                         g->node_class, g->edge_class);
00526     g2 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass),
00527                         g->node_class, g->edge_class);
00528     
00529     data[0] = g;
00530     data[1] = g1;
00531     heap = gts_eheap_new ((GtsKeyFunc) node_cost, data);
00532 
00533     gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed));
00534     GTS_OBJECT (seed)->reserved = seed;
00535     gts_gnode_foreach_neighbor (seed, g, (GtsFunc) add_neighbor, heap);
00536 
00537     while ((n = gts_eheap_remove_top (heap, &cost)))
00538       if (gts_graph_weight (g1) + gts_gnode_weight (n) <= size) {
00539         gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (n));
00540         GTS_OBJECT (n)->reserved = n;
00541         gts_gnode_foreach_neighbor (n, g, (GtsFunc) add_neighbor, heap);
00542       }
00543       else
00544         GTS_OBJECT (n)->reserved = NULL;
00545     gts_eheap_destroy (heap);
00546     
00547     gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_unused, g2);
00548 
00549     cost = gts_graph_edges_cut_weight (g1);
00550     if (!bestg1 || 
00551         (!balanced && gts_graph_weight (g1) >= smin) ||
00552         (cost < bestcost && gts_graph_weight (g1) >= smin)) {
00553       if (bestg1)
00554         bestcost = cost;
00555       if (bestg1)
00556         gts_object_destroy (GTS_OBJECT (bestg1));
00557       if (bestg2)
00558         gts_object_destroy (GTS_OBJECT (bestg2));
00559       bestg1 = g1;
00560       bestg2 = g2;
00561       if (gts_graph_weight (g1) >= smin)
00562         balanced = TRUE;
00563     }
00564     else {
00565       gts_object_destroy (GTS_OBJECT (g1));
00566       gts_object_destroy (GTS_OBJECT (g2));
00567     }
00568 
00569     ntry--;
00570   }
00571   gts_eheap_destroy (degree_heap);
00572 
00573 #ifdef DEBUG
00574   fprintf (stderr, "bestcost: %5g g1: %5g|%5d g2: %5g|%5d\n",
00575            bestcost, 
00576            gts_graph_weight (bestg1), 
00577            gts_container_size (GTS_CONTAINER (bestg1)),
00578            gts_graph_weight (bestg2), 
00579            gts_container_size (GTS_CONTAINER (bestg2)));
00580 #endif
00581 
00582   g_assert (bestg1 != NULL);
00583   bg->g1 = bestg1;
00584   g_assert (bestg2 != NULL);
00585   bg->g2 = bestg2;
00586   
00587   /* boundary nodes */
00588   bg->bg1 = g_hash_table_new (NULL, NULL);
00589   gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) boundary_node1, bg);
00590   bg->bg2 = g_hash_table_new (NULL, NULL);
00591   gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) boundary_node2, bg);
00592 
00593   return bg;
00594 }
00595 
00607 GtsGraphBisection * gts_graph_bfgg_bisection (GtsGraph * g, guint ntry)
00608 {
00609   gfloat size, bestcost = G_MAXFLOAT, smin;
00610   GtsGraph * bestg1 = NULL, * bestg2 = NULL;
00611   GtsEHeap * degree_heap;
00612   GtsGNode * seed;
00613   GtsGraphBisection * bg;
00614 
00615   g_return_val_if_fail (g != NULL, NULL);
00616 
00617   bg = g_malloc (sizeof (GtsGraphBisection));
00618   bg->g = g;
00619 
00620   size = gts_graph_weight (g)/2.;
00621   smin = 0.9*size;
00622 
00623   degree_heap = gts_eheap_new ((GtsKeyFunc) degree_cost, g);
00624   gts_eheap_freeze (degree_heap);
00625   gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_seed, degree_heap);
00626   gts_eheap_thaw (degree_heap);
00627 
00628   while (ntry && ((seed = gts_eheap_remove_top (degree_heap, NULL)))) {
00629     GtsGraph * g1, * g2;
00630     GtsGNode * n;
00631     gdouble cost;
00632     GtsGraphTraverse * t = gts_graph_traverse_new (g, seed, 
00633                                                    GTS_BREADTH_FIRST, TRUE);
00634     
00635     g1 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass),
00636                         g->node_class, g->edge_class);
00637     g2 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass),
00638                         g->node_class, g->edge_class);
00639 
00640     while ((n = gts_graph_traverse_next (t)))
00641       if (gts_graph_weight (g1) + gts_gnode_weight (n) <= size) {
00642         gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (n));
00643         GTS_OBJECT (n)->reserved = n;
00644       }
00645     gts_graph_traverse_destroy (t);
00646     
00647     gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_unused, g2);
00648 
00649     cost = gts_graph_edges_cut_weight (g1);
00650     if (!bestg1 || (cost < bestcost && gts_graph_weight (g1) >= smin)) {
00651       if (bestg1)
00652         bestcost = cost;
00653       if (bestg1)
00654         gts_object_destroy (GTS_OBJECT (bestg1));
00655       if (bestg2)
00656         gts_object_destroy (GTS_OBJECT (bestg2));
00657       bestg1 = g1;
00658       bestg2 = g2;
00659     }
00660     else {
00661       gts_object_destroy (GTS_OBJECT (g1));
00662       gts_object_destroy (GTS_OBJECT (g2));
00663     }
00664 
00665     ntry--;
00666   }
00667   gts_eheap_destroy (degree_heap);
00668 
00669 #ifdef DEBUG
00670   fprintf (stderr, "bestcost: %5g g1: %5g|%5d g2: %5g|%5d\n",
00671            bestcost, 
00672            gts_graph_weight (bestg1), 
00673            gts_container_size (GTS_CONTAINER (bestg1)),
00674            gts_graph_weight (bestg2), 
00675            gts_container_size (GTS_CONTAINER (bestg2)));
00676 #endif
00677 
00678   bg->g1 = bestg1;
00679   bg->g2 = bestg2;
00680   
00681   /* boundary nodes */
00682   bg->bg1 = g_hash_table_new (NULL, NULL);
00683   gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) boundary_node1, bg);
00684   bg->bg2 = g_hash_table_new (NULL, NULL);
00685   gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) boundary_node2, bg);
00686 
00687   return bg;
00688 }
00689 
00690 static gdouble node_move_cost1 (GtsGNode * n, GtsGraphBisection * bg)
00691 {
00692   return gts_gnode_move_cost (n, bg->g1, bg->g2);
00693 }
00694 
00695 static gdouble node_move_cost2 (GtsGNode * n, GtsGraphBisection * bg)
00696 {
00697   return gts_gnode_move_cost (n, bg->g2, bg->g1);
00698 }
00699 
00700 static void build_heap (GtsGNode * n, GtsEHeap * heap)
00701 {
00702   GTS_OBJECT (n)->reserved = gts_eheap_insert (heap, n);
00703 }
00704 
00720 gdouble gts_graph_bisection_kl_refine (GtsGraphBisection * bg,
00721                                        guint mmax)
00722 {
00723   GtsEHeap * h1, * h2;
00724   GtsGNode * n;
00725   guint nm = 0, i;
00726   GtsGNode ** moves;
00727   gdouble bestcost = 0., totalcost = 0., best_balance;
00728 
00729   g_return_val_if_fail (bg != NULL, 0.);
00730   g_return_val_if_fail (mmax > 0, 0.);
00731 
00732   h1 = gts_eheap_new ((GtsKeyFunc) node_move_cost1, bg);
00733   gts_eheap_freeze (h1);
00734   gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) build_heap, h1);
00735   gts_eheap_thaw (h1);
00736 
00737   h2 = gts_eheap_new ((GtsKeyFunc) node_move_cost2, bg);
00738   gts_eheap_freeze (h2);
00739   gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) build_heap, h2);
00740   gts_eheap_thaw (h2);
00741 
00742   moves = g_malloc (sizeof (GtsGNode *)*mmax);
00743   best_balance = fabs (gts_graph_weight (bg->g1) - gts_graph_weight (bg->g2));
00744 
00745   do {
00746     GtsGraph * g1, * g2;
00747     gdouble cost;
00748 
00749     if (gts_graph_weight (bg->g1) > gts_graph_weight (bg->g2)) {
00750       n = gts_eheap_remove_top (h1, &cost);
00751       g1 = bg->g1;
00752       g2 = bg->g2;
00753     }
00754     else {
00755       n = gts_eheap_remove_top (h2, &cost);
00756       g1 = bg->g2;
00757       g2 = bg->g1;
00758     }
00759     if (n) {
00760       GSList * i;
00761 
00762       GTS_OBJECT (n)->reserved = NULL;
00763       gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n));
00764       gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n));
00765 
00766       totalcost += cost;
00767       if (totalcost < bestcost) {
00768         bestcost = totalcost;
00769         nm = 0;
00770       }
00771       else if (totalcost == bestcost) {
00772         gdouble balance = fabs (gts_graph_weight (g1) - gts_graph_weight (g2));
00773 
00774         if (balance < best_balance) {
00775           best_balance = balance;
00776           nm = 0;
00777         }
00778       }        
00779       else
00780         moves[nm++] = n;
00781 
00782       i = GTS_SLIST_CONTAINER (n)->items;
00783       while (i) {
00784         GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data);
00785         if (GTS_OBJECT (n1)->reserved && 
00786             gts_containee_is_contained (GTS_CONTAINEE (n1), 
00787                                         GTS_CONTAINER (bg->g))) {
00788           GtsEHeap * h = 
00789             gts_containee_is_contained (GTS_CONTAINEE (n1), 
00790                                         GTS_CONTAINER (bg->g1)) ? h1 : h2;
00791           gts_eheap_remove (h, GTS_OBJECT (n1)->reserved);
00792           GTS_OBJECT (n1)->reserved = gts_eheap_insert (h, n1);
00793         }
00794         i = i->next;
00795       }
00796     }
00797   } while (n && nm < mmax);
00798 
00799   gts_eheap_foreach (h1, (GFunc) gts_object_reset_reserved, NULL);
00800   gts_eheap_foreach (h2, (GFunc) gts_object_reset_reserved, NULL);
00801   gts_eheap_destroy (h1);
00802   gts_eheap_destroy (h2);
00803 
00804   /* undo last nm moves */
00805   for (i = 0; i < nm; i++) {
00806     GtsGNode * n = moves[i];
00807     GtsGraph * g1 = 
00808       gts_containee_is_contained (GTS_CONTAINEE (n),
00809                                   GTS_CONTAINER (bg->g1)) ? bg->g1 : bg->g2;
00810     GtsGraph * g2 = g1 == bg->g1 ? bg->g2 : bg->g1;
00811     
00812     gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n));
00813     gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n));
00814   }
00815   g_free (moves);
00816 
00817   return bestcost;
00818 }
00819 
00820 static void build_bheap (GtsGNode * n, GtsGNode * n1, GtsEHeap * heap)
00821 {
00822   GTS_OBJECT (n)->reserved = gts_eheap_insert (heap, n);
00823 }
00824 
00825 static void update_neighbors (GtsGNode * n, GtsGraphBisection * bg,
00826                               GtsEHeap * h1, GtsEHeap * h2)
00827 {
00828   GSList * i;
00829 
00830   i = GTS_SLIST_CONTAINER (n)->items;
00831   while (i) {
00832     GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data);
00833     if (gts_containee_is_contained (GTS_CONTAINEE (n1), 
00834                                     GTS_CONTAINER (bg->g))) {
00835       GtsEHeap * h;
00836       GtsGraph /* * g1,*/ * g2;
00837       GHashTable * bg1;
00838 
00839       if (gts_containee_is_contained (GTS_CONTAINEE (n1),
00840                                       GTS_CONTAINER (bg->g1))) {
00841         h = h1;
00842         //g1 = bg->g1;
00843         g2 = bg->g2;
00844         bg1 = bg->bg1;
00845       }
00846       else {
00847         h = h2;
00848         //g1 = bg->g2;
00849         g2 = bg->g1;
00850         bg1 = bg->bg2;
00851       }
00852       g_hash_table_remove (bg1, n1);
00853       if (h && GTS_OBJECT (n1)->reserved && GTS_OBJECT (n1)->reserved != n1) {
00854         gts_eheap_remove (h, GTS_OBJECT (n1)->reserved);
00855         GTS_OBJECT (n1)->reserved = NULL;
00856       }
00857       if (gts_gnode_degree (n1, g2)) {
00858         g_hash_table_insert (bg1, n1, n1);
00859         if (h && GTS_OBJECT (n1)->reserved != n1)
00860           GTS_OBJECT (n1)->reserved = gts_eheap_insert (h, n1);
00861       }
00862     }
00863     i = i->next;
00864   }  
00865 }
00866 
00884 gdouble gts_graph_bisection_bkl_refine (GtsGraphBisection * bg,
00885                                         guint mmax,
00886                                         gfloat imbalance)
00887 {
00888   GtsEHeap * h1, * h2;
00889   GtsGNode * n;
00890   guint nm = 0, i;
00891   GtsGNode ** moves;
00892   gdouble bestcost = 0., totalcost = 0., best_balance;
00893   gboolean balanced = FALSE;
00894 
00895   g_return_val_if_fail (bg != NULL, 0.);
00896   g_return_val_if_fail (mmax > 0, 0.);
00897   g_return_val_if_fail (imbalance >= 0. && imbalance <= 1., 0.);
00898 
00899   h1 = gts_eheap_new ((GtsKeyFunc) node_move_cost1, bg);
00900   gts_eheap_freeze (h1);
00901   g_hash_table_foreach (bg->bg1, (GHFunc) build_bheap, h1);
00902   gts_eheap_thaw (h1);
00903 
00904   h2 = gts_eheap_new ((GtsKeyFunc) node_move_cost2, bg);
00905   gts_eheap_freeze (h2);
00906   g_hash_table_foreach (bg->bg2, (GHFunc) build_bheap, h2);
00907   gts_eheap_thaw (h2);
00908 
00909   moves = g_malloc (sizeof (GtsGNode *)*mmax);
00910   imbalance *= gts_graph_weight (bg->g);
00911   best_balance = fabs (gts_graph_weight (bg->g1) - gts_graph_weight (bg->g2));
00912   if (best_balance <= imbalance)
00913     balanced = TRUE;
00914 
00915   do {
00916     GtsGraph * g1, * g2;
00917     GHashTable * bg1, * bg2;
00918     gdouble cost;
00919 
00920     if (gts_graph_weight (bg->g1) > gts_graph_weight (bg->g2)) {
00921       n = gts_eheap_remove_top (h1, &cost);
00922       g1 = bg->g1;
00923       g2 = bg->g2;
00924       bg1 = bg->bg1;
00925       bg2 = bg->bg2;
00926     }
00927     else {
00928       n = gts_eheap_remove_top (h2, &cost);
00929       g1 = bg->g2;
00930       g2 = bg->g1;
00931       bg1 = bg->bg2;
00932       bg2 = bg->bg1;
00933     }
00934     if (n) {
00935       gdouble balance;
00936         
00937       GTS_OBJECT (n)->reserved = n;
00938       gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n));
00939       gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n));
00940       g_hash_table_remove (bg1, n);
00941       if (gts_gnode_degree (n, g1))
00942         g_hash_table_insert (bg2, n, n);
00943 
00944       update_neighbors (n, bg, h1, h2);
00945 
00946       totalcost += cost;
00947       balance = fabs (gts_graph_weight (g1) - gts_graph_weight (g2));
00948       
00949       if (!balanced && balance <= imbalance) {
00950         bestcost = totalcost;
00951         best_balance = balance;
00952         balanced = TRUE;
00953         nm = 0;
00954       }
00955       else if (totalcost < bestcost && 
00956                (balance < best_balance || balance <= imbalance)) {
00957         bestcost = totalcost;
00958         best_balance = balance;
00959         nm = 0;
00960       }
00961       else if (totalcost == bestcost && balance < best_balance) {
00962         best_balance = balance;
00963         nm = 0;
00964       }
00965       else
00966         moves[nm++] = n;
00967     }
00968   } while (n && nm < mmax);
00969 
00970   gts_container_foreach (GTS_CONTAINER (bg->g), 
00971                          (GtsFunc) gts_object_reset_reserved, NULL);
00972   gts_eheap_destroy (h1);
00973   gts_eheap_destroy (h2);
00974 
00975   /* undo last nm moves */
00976   for (i = 0; i < nm; i++) {
00977     GtsGNode * n = moves[i];
00978     GtsGraph * g1, * g2;
00979     GHashTable * bg1, * bg2;
00980 
00981     if (gts_containee_is_contained (GTS_CONTAINEE (n),
00982                                     GTS_CONTAINER (bg->g1))) {
00983       g1 = bg->g1;
00984       g2 = bg->g2;
00985       bg1 = bg->bg1;
00986       bg2 = bg->bg2;
00987     }
00988     else {
00989       g1 = bg->g2;
00990       g2 = bg->g1;
00991       bg1 = bg->bg2;
00992       bg2 = bg->bg1;
00993     }
00994     
00995     gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n));
00996     gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n));
00997     g_hash_table_remove (bg1, n);
00998     if (gts_gnode_degree (n, g1))
00999       g_hash_table_insert (bg2, n, n);
01000 
01001     update_neighbors (n, bg, NULL, NULL);
01002   }
01003   g_free (moves);
01004 
01005   return bestcost;
01006 }
01007 
01008 /* Multilevel partitioning */
01009 
01010 static void bisection_children (GtsGNodeSplit * ns, GtsGraphBisection * bg)
01011 {
01012   GtsGraph * g, * g1;
01013   GHashTable * bbg;
01014   GtsGNode * n1 = GTS_GNODE_SPLIT_N1 (ns);
01015   GtsGNode * n2 = GTS_GNODE_SPLIT_N2 (ns);
01016 
01017   if (gts_containee_is_contained (GTS_CONTAINEE (ns->n),
01018                                   GTS_CONTAINER (bg->g1))) {
01019     g = bg->g1;
01020     g1 = bg->g2;
01021     bbg = bg->bg1;
01022   }
01023   else {
01024     g = bg->g2;
01025     g1 = bg->g1;
01026     bbg = bg->bg2;
01027   }
01028 
01029   gts_allow_floating_gnodes = TRUE;
01030   gts_container_remove (GTS_CONTAINER (g), GTS_CONTAINEE (ns->n));
01031   gts_allow_floating_gnodes = FALSE;
01032   gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (n1));
01033   gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (n2));
01034 
01035   if (g_hash_table_lookup (bbg, ns->n)) {
01036     g_hash_table_remove (bbg, ns->n);
01037     if (gts_gnode_degree (n1, g1) > 0)
01038       g_hash_table_insert (bbg, n1, n1);
01039     if (gts_gnode_degree (n2, g1) > 0)
01040       g_hash_table_insert (bbg, n2, n2);
01041   }
01042 }
01043 
01062 GtsGraphBisection * gts_graph_bisection_new (GtsWGraph * wg,
01063                                              guint ntry,
01064                                              guint mmax,
01065                                              guint nmin,
01066                                              gfloat imbalance)
01067 {
01068   GtsGraph * g;
01069   GtsPGraph * pg;
01070   GtsGraphBisection * bg;
01071   gdouble cost;
01072 
01073   g_return_val_if_fail (wg != NULL, NULL);
01074 
01075   g = GTS_GRAPH (wg);
01076   pg = gts_pgraph_new (gts_pgraph_class (), g, 
01077                        gts_gnode_split_class (),
01078                        gts_wgnode_class (),
01079                        gts_wgedge_class (),
01080                        nmin);
01081 
01082   bg = gts_graph_ggg_bisection (g, ntry);
01083 #ifdef DEBUG
01084   fprintf (stderr, "before size: %5d weight: %5g cuts: %5d cweight: %5g\n",
01085            gts_container_size (GTS_CONTAINER (bg->g1)),
01086            gts_graph_weight (bg->g1),
01087            gts_graph_edges_cut (bg->g1),
01088            gts_graph_edges_cut_weight (bg->g1));
01089   g_assert (gts_graph_bisection_check (bg));
01090 #endif
01091   while ((cost = gts_graph_bisection_bkl_refine (bg, mmax, imbalance))) {
01092 #ifdef DEBUG
01093     fprintf (stderr, "  cost: %g\n", cost);
01094     g_assert (gts_graph_bisection_check (bg));
01095 #endif
01096   }
01097 #ifdef DEBUG
01098   fprintf (stderr, "after  size: %5d weight: %5g cuts: %5d cweight: %5g\n",
01099            gts_container_size (GTS_CONTAINER (bg->g1)),
01100            gts_graph_weight (bg->g1),
01101            gts_graph_edges_cut (bg->g1),
01102            gts_graph_edges_cut_weight (bg->g1));
01103 #endif
01104   while (gts_pgraph_down (pg, (GtsFunc) bisection_children, bg)) {
01105 #ifdef DEBUG
01106     fprintf (stderr, "before size: %5d weight: %5g cuts: %5d cweight: %5g\n",
01107              gts_container_size (GTS_CONTAINER (bg->g1)),
01108              gts_graph_weight (bg->g1),
01109              gts_graph_edges_cut (bg->g1),
01110              gts_graph_edges_cut_weight (bg->g1));         
01111 #endif
01112     while ((cost = gts_graph_bisection_bkl_refine (bg, mmax, imbalance))) {
01113 #ifdef DEBUG
01114       fprintf (stderr, "  cost: %g\n", cost);
01115       g_assert (gts_graph_bisection_check (bg));
01116 #endif
01117     }
01118 #ifdef DEBUG
01119     fprintf (stderr, "after  size: %5d weight: %5g cuts: %5d cweight: %5g\n",
01120              gts_container_size (GTS_CONTAINER (bg->g1)),
01121              gts_graph_weight (bg->g1),
01122              gts_graph_edges_cut (bg->g1),
01123              gts_graph_edges_cut_weight (bg->g1));
01124 #endif
01125   }
01126   gts_object_destroy (GTS_OBJECT (pg));
01127 
01128   return bg;
01129 }
01130 
01139 void gts_graph_bisection_destroy (GtsGraphBisection * bg,
01140                                   gboolean destroy_graphs)
01141 {
01142   g_return_if_fail (bg != NULL);
01143 
01144   g_hash_table_destroy (bg->bg1);
01145   g_hash_table_destroy (bg->bg2);
01146 
01147   if (destroy_graphs) {
01148     gts_object_destroy (GTS_OBJECT (bg->g1));
01149     gts_object_destroy (GTS_OBJECT (bg->g2));
01150   }
01151 
01152   g_free (bg);
01153 }
01154 
01155 static void recursive_bisection (GtsWGraph * wg,
01156                                  guint np,
01157                                  guint ntry,
01158                                  guint mmax,
01159                                  guint nmin,
01160                                  gfloat imbalance,
01161                                  GSList ** list)
01162 {
01163   if (np == 0)
01164     *list = g_slist_prepend (*list, wg);
01165   else {
01166     GtsGraphBisection * bg = 
01167       gts_graph_bisection_new (wg, ntry, mmax, nmin, imbalance);
01168     GtsGraph * g1 = bg->g1;
01169     GtsGraph * g2 = bg->g2;
01170 
01171     gts_object_destroy (GTS_OBJECT (wg));
01172     gts_graph_bisection_destroy (bg, FALSE);
01173     recursive_bisection (GTS_WGRAPH (g1), np - 1, ntry, mmax, nmin, imbalance,
01174                          list);
01175     recursive_bisection (GTS_WGRAPH (g2), np - 1, ntry, mmax, nmin, imbalance,
01176                          list);
01177   }
01178 }
01179 
01195 GSList * gts_graph_recursive_bisection (GtsWGraph * wg,
01196                                         guint n,
01197                                         guint ntry,
01198                                         guint mmax,
01199                                         guint nmin,
01200                                         gfloat imbalance)
01201 {
01202   GtsGraphBisection * bg;
01203   GtsGraph * g1, * g2;
01204   GSList * list = NULL;
01205 
01206   g_return_val_if_fail (wg != NULL, NULL);
01207   g_return_val_if_fail (n > 0, NULL);
01208   
01209   bg = gts_graph_bisection_new (wg, ntry, mmax, nmin, imbalance);
01210   g1 = bg->g1;
01211   g2 = bg->g2;
01212   gts_graph_bisection_destroy (bg, FALSE);
01213   recursive_bisection (GTS_WGRAPH (g1), n - 1, ntry, mmax, nmin, imbalance, 
01214                        &list);
01215   recursive_bisection (GTS_WGRAPH (g2), n - 1, ntry, mmax, nmin, imbalance,
01216                        &list);
01217 
01218   return list;
01219 }