pcb 4.1.1
An interactive printed circuit board layout editor.
|
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] = ∑ 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 }