2 * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
4 * This file is part of libFirm.
6 * This file may be distributed and/or modified under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation and appearing in the file LICENSE.GPL included in the
9 * packaging of this file.
11 * Licensees holding valid libFirm Professional Edition licenses may use
12 * this file in accordance with the libFirm Commercial License.
13 * Agreement provided with the Software.
15 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * @brief Heuristic PBQP solver.
24 * @author Sebastian Buchwald
29 #include "adt/array.h"
34 #include "heuristical.h"
36 #include "html_dumper.h"
40 #include "pbqp_edge.h"
41 #include "pbqp_edge_t.h"
42 #include "pbqp_node.h"
43 #include "pbqp_node_t.h"
49 static pbqp_edge **edge_bucket;
50 static pbqp_node **node_buckets[4];
51 static pbqp_node **reduced_bucket = NULL;
52 static int buckets_filled = 0;
58 /* Forward declarations. */
59 static void apply_Brute_Force(pbqp *pbqp);
61 static void insert_into_edge_bucket(pbqp_edge *edge)
63 if (edge_bucket_contains(edge_bucket, edge)) {
64 /* Edge is already inserted. */
68 edge_bucket_insert(&edge_bucket, edge);
71 static void init_buckets(void)
75 edge_bucket_init(&edge_bucket);
76 node_bucket_init(&reduced_bucket);
78 for (i = 0; i < 4; ++i) {
79 node_bucket_init(&node_buckets[i]);
83 static void free_buckets(void)
87 for (i = 0; i < 4; ++i) {
88 node_bucket_free(&node_buckets[i]);
91 edge_bucket_free(&edge_bucket);
92 node_bucket_free(&reduced_bucket);
97 static void fill_node_buckets(pbqp *pbqp)
103 node_len = pbqp->num_nodes;
106 ir_timer_t *t_fill_buckets = ir_timer_register("be_pbqp_fill_buckets", "PBQP Fill Nodes into buckets");
107 ir_timer_reset_and_start(t_fill_buckets);
110 for (node_index = 0; node_index < node_len; ++node_index) {
112 pbqp_node *node = get_node(pbqp, node_index);
116 degree = pbqp_node_get_degree(node);
118 /* We have only one bucket for nodes with arity >= 3. */
123 node_bucket_insert(&node_buckets[degree], node);
129 ir_timer_stop(t_fill_buckets);
130 printf("%-20s: %8.3lf msec\n", ir_timer_get_description(t_fill_buckets), (double)ir_timer_elapsed_usec(t_fill_buckets) / 1000.0);
134 static void normalize_towards_source(pbqp *pbqp, pbqp_edge *edge)
148 src_node = edge->src;
149 tgt_node = edge->tgt;
153 src_vec = src_node->costs;
154 tgt_vec = tgt_node->costs;
158 src_len = src_vec->len;
159 tgt_len = tgt_vec->len;
166 /* Normalize towards source node. */
167 for (src_index = 0; src_index < src_len; ++src_index) {
168 num min = pbqp_matrix_get_row_min(mat, src_index, tgt_vec);
171 if (src_vec->entries[src_index].data == INF_COSTS) {
172 pbqp_matrix_set_row_value(mat, src_index, 0);
174 pbqp_matrix_sub_row_value(mat, src_index, tgt_vec, min);
176 src_vec->entries[src_index].data = pbqp_add(
177 src_vec->entries[src_index].data, min);
179 if (min == INF_COSTS) {
181 unsigned edge_len = pbqp_node_get_degree(src_node);
183 for (edge_index = 0; edge_index < edge_len; ++edge_index) {
184 pbqp_edge *edge_candidate = src_node->edges[edge_index];
185 if (edge_candidate != edge) {
186 insert_into_edge_bucket(edge_candidate);
194 static void normalize_towards_target(pbqp *pbqp, pbqp_edge *edge)
208 src_node = edge->src;
209 tgt_node = edge->tgt;
213 src_vec = src_node->costs;
214 tgt_vec = tgt_node->costs;
218 src_len = src_vec->len;
219 tgt_len = tgt_vec->len;
226 for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
227 num min = pbqp_matrix_get_col_min(mat, tgt_index, src_vec);
230 if (tgt_vec->entries[tgt_index].data == INF_COSTS) {
231 pbqp_matrix_set_col_value(mat, tgt_index, 0);
233 pbqp_matrix_sub_col_value(mat, tgt_index, src_vec, min);
235 tgt_vec->entries[tgt_index].data = pbqp_add(
236 tgt_vec->entries[tgt_index].data, min);
238 if (min == INF_COSTS) {
240 unsigned edge_len = pbqp_node_get_degree(tgt_node);
242 for (edge_index = 0; edge_index < edge_len; ++edge_index) {
243 pbqp_edge *edge_candidate = tgt_node->edges[edge_index];
244 if (edge_candidate != edge) {
245 insert_into_edge_bucket(edge_candidate);
253 static void reorder_node(pbqp_node *node)
255 unsigned degree = pbqp_node_get_degree(node);
256 /* Assume node lost one incident edge. */
257 unsigned old_degree = degree + 1;
259 if (!buckets_filled) return;
261 /* Same bucket as before */
262 if (degree > 2) return;
264 if (!node_bucket_contains(node_buckets[old_degree], node)) {
265 /* Old arity is new arity, so we have nothing to do. */
266 assert(node_bucket_contains(node_buckets[degree], node));
270 /* Delete node from old bucket... */
271 node_bucket_remove(&node_buckets[old_degree], node);
273 /* ..and add to new one. */
274 node_bucket_insert(&node_buckets[degree], node);
278 static void check_melting_possibility(pbqp *pbqp, pbqp_edge *edge)
293 src_node = edge->src;
294 tgt_node = edge->tgt;
298 src_vec = src_node->costs;
299 tgt_vec = tgt_node->costs;
303 src_len = src_vec->len;
304 tgt_len = tgt_vec->len;
311 if (src_len == 1 && tgt_len == 1) {
312 //panic("Something is wrong");
316 for (src_index = 0; src_index < src_len; ++src_index) {
318 if (src_vec->entries[src_index].data == INF_COSTS) {
321 for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
322 if (tgt_vec->entries[tgt_index].data == INF_COSTS) {
325 if (mat->entries[src_index * tgt_len + tgt_index] == 0) {
334 if (mat->entries[src_index * tgt_len + tgt_index] == INF_COSTS) {
340 allRowsOk &= onlyOneZero;
344 for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
346 if (tgt_vec->entries[tgt_index].data == INF_COSTS) {
349 for (src_index = 0; src_index < src_len; ++src_index) {
350 if (src_vec->entries[src_index].data == INF_COSTS) {
353 if (mat->entries[src_index * tgt_len + tgt_index] == 0) {
362 if (mat->entries[src_index * tgt_len + tgt_index] == INF_COSTS) {
368 allColsOk &= onlyOneZero;
371 if (allRowsOk && allColsOk) {
377 static void simplify_edge(pbqp *pbqp, pbqp_edge *edge)
390 src_node = edge->src;
391 tgt_node = edge->tgt;
395 /* If edge are already deleted, we have nothing to do. */
396 if (!is_connected(src_node, edge) || !is_connected(tgt_node, edge))
400 if (pbqp->dump_file) {
402 sprintf(txt, "Simplification of Edge n%d-n%d", src_node->index, tgt_node->index);
403 dump_section(pbqp->dump_file, 3, txt);
407 src_vec = src_node->costs;
408 tgt_vec = tgt_node->costs;
412 src_len = src_vec->len;
413 tgt_len = tgt_vec->len;
421 if (pbqp->dump_file) {
422 fputs("Input:<br>\n", pbqp->dump_file);
423 dump_simplifyedge(pbqp, edge);
427 normalize_towards_source(pbqp, edge);
428 normalize_towards_target(pbqp, edge);
431 if (pbqp->dump_file) {
432 fputs("<br>\nOutput:<br>\n", pbqp->dump_file);
433 dump_simplifyedge(pbqp, edge);
437 if (pbqp_matrix_is_zero(mat, src_vec, tgt_vec)) {
439 if (pbqp->dump_file) {
440 fputs("edge has been eliminated<br>\n", pbqp->dump_file);
451 reorder_node(src_node);
452 reorder_node(tgt_node);
456 static void initial_simplify_edges(pbqp *pbqp)
464 ir_timer_t *t_int_simpl = ir_timer_register("be_pbqp_init_simp", "PBQP Initial simplify edges");
465 ir_timer_reset_and_start(t_int_simpl);
469 if (pbqp->dump_file) {
470 pbqp_dump_input(pbqp);
471 dump_section(pbqp->dump_file, 1, "2. Simplification of Cost Matrices");
475 node_len = pbqp->num_nodes;
479 /* First simplify all edges. */
480 for (node_index = 0; node_index < node_len; ++node_index) {
482 pbqp_node *node = get_node(pbqp, node_index);
489 edge_len = pbqp_node_get_degree(node);
491 for (edge_index = 0; edge_index < edge_len; ++edge_index) {
492 pbqp_edge *edge = edges[edge_index];
494 /* Simplify only once per edge. */
495 if (node != edge->src) continue;
497 simplify_edge(pbqp, edge);
502 ir_timer_stop(t_int_simpl);
503 printf("%-20s: %8.3lf msec\n", ir_timer_get_description(t_int_simpl), (double)ir_timer_elapsed_usec(t_int_simpl) / 1000.0);
507 static num determine_solution(pbqp *pbqp)
514 ir_timer_t *t_det_solution = ir_timer_register("be_det_solution", "PBQP Determine Solution");
515 ir_timer_reset_and_start(t_det_solution);
525 file = pbqp->dump_file;
528 dump_section(file, 1, "4. Determine Solution/Minimum");
529 dump_section(file, 2, "4.1. Trivial Solution");
533 /* Solve trivial nodes and calculate solution. */
534 node_len = node_bucket_get_length(node_buckets[0]);
538 pbqp->num_r0 = node_len;
542 for (node_index = 0; node_index < node_len; ++node_index) {
543 pbqp_node *node = node_buckets[0][node_index];
546 node->solution = vector_get_min_index(node->costs);
547 solution = pbqp_add(solution,
548 node->costs->entries[node->solution].data);
552 fprintf(file, "node n%d is set to %d<br>\n", node->index, node->solution);
553 dump_node(file, node);
560 dump_section(file, 2, "Minimum");
561 #if KAPS_USE_UNSIGNED
562 fprintf(file, "Minimum is equal to %u.", solution);
564 fprintf(file, "Minimum is equal to %lld.", solution);
570 ir_timer_stop(t_det_solution);
571 printf("%-20s: %8.3lf msec\n", ir_timer_get_description(t_det_solution), (double)ir_timer_elapsed_usec(t_det_solution) / 1000.0);
577 static void back_propagate(pbqp *pbqp)
580 unsigned node_len = node_bucket_get_length(reduced_bucket);
585 if (pbqp->dump_file) {
586 dump_section(pbqp->dump_file, 2, "Back Propagation");
590 for (node_index = node_len; node_index > 0; --node_index) {
591 pbqp_node *node = reduced_bucket[node_index - 1];
593 switch (pbqp_node_get_degree(node)) {
595 back_propagate_RI(pbqp, node);
598 back_propagate_RII(pbqp, node);
601 panic("Only nodes with degree one or two should be in this bucket");
607 static void apply_heuristic_reductions(pbqp *pbqp)
610 if (edge_bucket_get_length(edge_bucket) > 0) {
612 } else if (node_bucket_get_length(node_buckets[1]) > 0) {
614 } else if (node_bucket_get_length(node_buckets[2]) > 0) {
616 } else if (node_bucket_get_length(node_buckets[3]) > 0) {
624 static void apply_heuristic_reductions_co(pbqp *pbqp, plist_t *rpeo)
628 ir_timer_t *t_edge = ir_timer_register("be_pbqp_edges", "pbqp reduce independent edges");
629 ir_timer_t *t_r0 = ir_timer_register("be_pbqp_r0", "pbqp R0 reductions");
630 ir_timer_t *t_r1 = ir_timer_register("be_pbqp_r1", "pbqp R1 reductions");
631 ir_timer_t *t_r2 = ir_timer_register("be_pbqp_r2", "pbqp R2 reductions");
632 ir_timer_t *t_rn = ir_timer_register("be_pbqp_rN", "pbqp RN reductions");
635 ir_timer_reset(t_edge);
636 ir_timer_reset(t_r0);
637 ir_timer_reset(t_r1);
638 ir_timer_reset(t_r2);
639 ir_timer_reset(t_rn);
643 if (edge_bucket_get_length(edge_bucket) > 0) {
645 ir_timer_start(t_r0);
653 } else if (node_bucket_get_length(node_buckets[1]) > 0) {
655 ir_timer_start(t_r1);
663 } else if (node_bucket_get_length(node_buckets[2]) > 0) {
665 ir_timer_start(t_r2);
673 } else if (node_bucket_get_length(node_buckets[3]) > 0) {
675 ir_timer_start(t_rn);
678 apply_RN_co(pbqp, rpeo);
685 printf("%-20s: %8.3lf msec\n", ir_timer_get_description(t_edge), (double)ir_timer_elapsed_usec(t_edge) / 1000.0);
686 printf("%-20s: %8.3lf msec\n", ir_timer_get_description(t_r0), (double)ir_timer_elapsed_usec(t_r0) / 1000.0);
687 printf("%-20s: %8.3lf msec\n", ir_timer_get_description(t_r1), (double)ir_timer_elapsed_usec(t_r1) / 1000.0);
688 printf("%-20s: %8.3lf msec\n", ir_timer_get_description(t_r2), (double)ir_timer_elapsed_usec(t_r2) / 1000.0);
689 printf("%-20s: %8.3lf msec\n", ir_timer_get_description(t_rn), (double)ir_timer_elapsed_usec(t_rn) / 1000.0);
697 void solve_pbqp_heuristical(pbqp *pbqp)
699 /* Reduce nodes degree ... */
700 initial_simplify_edges(pbqp);
702 /* ... and put node into bucket representing their degree. */
703 fill_node_buckets(pbqp);
706 FILE *fh = fopen("solutions.pb", "a");
707 fprintf(fh, "Solution");
711 apply_heuristic_reductions(pbqp);
713 pbqp->solution = determine_solution(pbqp);
716 fh = fopen("solutions.pb", "a");
717 fprintf(fh, ": %lld RE:%u R0:%u R1:%u R2:%u RN/BF:%u\n", pbqp->solution,
718 pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
723 /* Solve reduced nodes. */
724 back_propagate(pbqp);
729 void solve_pbqp_heuristical_co(pbqp *pbqp, plist_t *rpeo)
731 /* Reduce nodes degree ... */
732 initial_simplify_edges(pbqp);
734 /* ... and put node into bucket representing their degree. */
735 fill_node_buckets(pbqp);
738 FILE *fh = fopen("solutions.pb", "a");
739 fprintf(fh, "Solution");
743 apply_heuristic_reductions_co(pbqp, rpeo);
745 pbqp->solution = determine_solution(pbqp);
748 fh = fopen("solutions.pb", "a");
749 fprintf(fh, ": %lld RE:%u R0:%u R1:%u R2:%u RN/BF:%u\n", pbqp->solution,
750 pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
755 /* Solve reduced nodes. */
756 back_propagate(pbqp);
761 void apply_edge(pbqp *pbqp)
763 pbqp_edge *edge = edge_bucket_pop(&edge_bucket);
765 simplify_edge(pbqp, edge);
768 void apply_RI(pbqp *pbqp)
770 pbqp_node *node = node_bucket_pop(&node_buckets[1]);
771 pbqp_edge *edge = node->edges[0];
772 pbqp_matrix *mat = edge->costs;
773 int is_src = edge->src == node;
774 pbqp_node *other_node;
776 assert(pbqp_node_get_degree(node) == 1);
779 other_node = edge->tgt;
781 other_node = edge->src;
785 if (pbqp->dump_file) {
787 sprintf(txt, "RI-Reduction of Node n%d", node->index);
788 dump_section(pbqp->dump_file, 2, txt);
789 pbqp_dump_graph(pbqp);
790 fputs("<br>\nBefore reduction:<br>\n", pbqp->dump_file);
791 dump_node(pbqp->dump_file, node);
792 dump_node(pbqp->dump_file, other_node);
793 dump_edge(pbqp->dump_file, edge);
798 pbqp_matrix_add_to_all_cols(mat, node->costs);
799 normalize_towards_target(pbqp, edge);
801 pbqp_matrix_add_to_all_rows(mat, node->costs);
802 normalize_towards_source(pbqp, edge);
804 disconnect_edge(other_node, edge);
807 if (pbqp->dump_file) {
808 fputs("<br>\nAfter reduction:<br>\n", pbqp->dump_file);
809 dump_node(pbqp->dump_file, other_node);
813 reorder_node(other_node);
821 /* Add node to back propagation list. */
822 node_bucket_insert(&reduced_bucket, node);
825 void apply_RII(pbqp *pbqp)
827 pbqp_node *node = node_bucket_pop(&node_buckets[2]);
828 pbqp_edge *src_edge = node->edges[0];
829 pbqp_edge *tgt_edge = node->edges[1];
830 int src_is_src = src_edge->src == node;
831 int tgt_is_src = tgt_edge->src == node;
832 pbqp_matrix *src_mat;
833 pbqp_matrix *tgt_mat;
848 assert(pbqp_node_get_degree(node) == 2);
851 src_node = src_edge->tgt;
853 src_node = src_edge->src;
857 tgt_node = tgt_edge->tgt;
859 tgt_node = tgt_edge->src;
862 /* Swap nodes if necessary. */
863 if (tgt_node->index < src_node->index) {
875 src_is_src = src_edge->src == node;
876 tgt_is_src = tgt_edge->src == node;
880 if (pbqp->dump_file) {
882 sprintf(txt, "RII-Reduction of Node n%d", node->index);
883 dump_section(pbqp->dump_file, 2, txt);
884 pbqp_dump_graph(pbqp);
885 fputs("<br>\nBefore reduction:<br>\n", pbqp->dump_file);
886 dump_node(pbqp->dump_file, src_node);
887 dump_edge(pbqp->dump_file, src_edge);
888 dump_node(pbqp->dump_file, node);
889 dump_edge(pbqp->dump_file, tgt_edge);
890 dump_node(pbqp->dump_file, tgt_node);
894 src_mat = src_edge->costs;
895 tgt_mat = tgt_edge->costs;
897 src_vec = src_node->costs;
898 tgt_vec = tgt_node->costs;
899 node_vec = node->costs;
901 row_len = src_vec->len;
902 col_len = tgt_vec->len;
903 node_len = node_vec->len;
905 mat = pbqp_matrix_alloc(pbqp, row_len, col_len);
907 for (row_index = 0; row_index < row_len; ++row_index) {
908 for (col_index = 0; col_index < col_len; ++col_index) {
909 vec = vector_copy(pbqp, node_vec);
912 vector_add_matrix_col(vec, src_mat, row_index);
914 vector_add_matrix_row(vec, src_mat, row_index);
918 vector_add_matrix_col(vec, tgt_mat, col_index);
920 vector_add_matrix_row(vec, tgt_mat, col_index);
923 mat->entries[row_index * col_len + col_index] = vector_get_min(vec);
925 obstack_free(&pbqp->obstack, vec);
929 pbqp_edge *edge = get_edge(pbqp, src_node->index, tgt_node->index);
931 /* Disconnect node. */
932 disconnect_edge(src_node, src_edge);
933 disconnect_edge(tgt_node, tgt_edge);
941 /* Add node to back propagation list. */
942 node_bucket_insert(&reduced_bucket, node);
945 edge = alloc_edge(pbqp, src_node->index, tgt_node->index, mat);
948 pbqp_matrix_add(edge->costs, mat);
950 /* Free local matrix. */
951 obstack_free(&pbqp->obstack, mat);
953 reorder_node(src_node);
954 reorder_node(tgt_node);
958 if (pbqp->dump_file) {
959 fputs("<br>\nAfter reduction:<br>\n", pbqp->dump_file);
960 dump_edge(pbqp->dump_file, edge);
964 /* Edge has changed so we simplify it. */
965 simplify_edge(pbqp, edge);
968 static void select_alternative(pbqp_node *node, unsigned selected_index)
974 unsigned max_degree = pbqp_node_get_degree(node);
977 node->solution = selected_index;
978 node_vec = node->costs;
979 node_len = node_vec->len;
980 assert(selected_index < node_len);
982 /* Set all other costs to infinity. */
983 for (node_index = 0; node_index < node_len; ++node_index) {
984 if (node_index != selected_index) {
985 node_vec->entries[node_index].data = INF_COSTS;
989 /* Add all incident edges to edge bucket, since they are now independent. */
990 for (edge_index = 0; edge_index < max_degree; ++edge_index) {
991 insert_into_edge_bucket(node->edges[edge_index]);
995 static pbqp_node *get_node_with_max_degree(void)
997 pbqp_node **bucket = node_buckets[3];
998 unsigned bucket_len = node_bucket_get_length(bucket);
999 unsigned bucket_index;
1000 unsigned max_degree = 0;
1001 pbqp_node *result = NULL;
1003 for (bucket_index = 0; bucket_index < bucket_len; ++bucket_index) {
1004 pbqp_node *candidate = bucket[bucket_index];
1005 unsigned degree = pbqp_node_get_degree(candidate);
1007 if (degree > max_degree) {
1009 max_degree = degree;
1016 static unsigned get_local_minimal_alternative(pbqp *pbqp, pbqp_node *node)
1022 unsigned edge_index;
1023 unsigned max_degree = 0;
1024 unsigned node_index;
1026 unsigned min_index = 0;
1027 num min = INF_COSTS;
1032 node_vec = node->costs;
1033 node_len = node_vec->len;
1035 for (node_index = 0; node_index < node_len; ++node_index) {
1036 num value = node_vec->entries[node_index].data;
1038 for (edge_index = 0; edge_index < max_degree; ++edge_index) {
1039 edge = node->edges[edge_index];
1041 is_src = edge->src == node;
1044 vec = vector_copy(pbqp, edge->tgt->costs);
1045 vector_add_matrix_row(vec, mat, node_index);
1047 vec = vector_copy(pbqp, edge->src->costs);
1048 vector_add_matrix_col(vec, mat, node_index);
1051 value = pbqp_add(value, vector_get_min(vec));
1053 obstack_free(&pbqp->obstack, vec);
1058 min_index = node_index;
1065 void apply_RN(pbqp *pbqp)
1067 pbqp_node *node = NULL;
1068 unsigned min_index = 0;
1072 /* We want to reduce a node with maximum degree. */
1073 node = get_node_with_max_degree();
1075 assert(pbqp_node_get_degree(node) > 2);
1078 if (pbqp->dump_file) {
1080 sprintf(txt, "RN-Reduction of Node n%d", node->index);
1081 dump_section(pbqp->dump_file, 2, txt);
1082 pbqp_dump_graph(pbqp);
1086 min_index = get_local_minimal_alternative(pbqp, node);
1089 if (pbqp->dump_file) {
1090 fprintf(pbqp->dump_file, "node n%d is set to %d<br><br>\n",
1091 node->index, min_index);
1097 FILE *fh = fopen("solutions.pb", "a");
1098 fprintf(fh, "[%u]", min_index);
1104 /* Now that we found the local minimum set all other costs to infinity. */
1105 select_alternative(node, min_index);
1108 void apply_RN_co(pbqp *pbqp, plist_t *rpeo)
1110 pbqp_node *node = NULL;
1111 unsigned min_index = 0;
1115 /* We want to reduce the first node in reverse perfect elimination order. */
1117 /* get first element from reverse perfect elimination order */
1118 node = plist_first(rpeo)->data;
1119 /* remove element from reverse perfect elimination order */
1120 plist_erase(rpeo, plist_first(rpeo));
1121 /* insert node at the end of rpeo so the rpeo already exits after pbqp solving */
1122 plist_insert_back(rpeo, node);
1123 } while(node_is_reduced(node));
1126 assert(pbqp_node_get_degree(node) > 2);
1129 if (pbqp->dump_file) {
1131 sprintf(txt, "RN-Reduction of Node n%d", node->index);
1132 dump_section(pbqp->dump_file, 2, txt);
1133 pbqp_dump_graph(pbqp);
1137 min_index = get_local_minimal_alternative(pbqp, node);
1140 if (pbqp->dump_file) {
1141 fprintf(pbqp->dump_file, "node n%d is set to %d<br><br>\n",
1142 node->index, min_index);
1148 FILE *fh = fopen("solutions.pb", "a");
1149 fprintf(fh, "[%u]", min_index);
1155 /* Now that we found the local minimum set all other costs to infinity. */
1156 select_alternative(node, min_index);
1161 static void apply_brute_force_reductions(pbqp *pbqp)
1164 if (edge_bucket_get_length(edge_bucket) > 0) {
1166 } else if (node_bucket_get_length(node_buckets[1]) > 0) {
1168 } else if (node_bucket_get_length(node_buckets[2]) > 0) {
1170 } else if (node_bucket_get_length(node_buckets[3]) > 0) {
1171 apply_Brute_Force(pbqp);
1178 static unsigned get_minimal_alternative(pbqp *pbqp, pbqp_node *node)
1181 unsigned node_index;
1183 unsigned min_index = 0;
1184 num min = INF_COSTS;
1185 unsigned bucket_index;
1189 node_vec = node->costs;
1190 node_len = node_vec->len;
1191 bucket_index = node->bucket_index;
1193 for (node_index = 0; node_index < node_len; ++node_index) {
1194 pbqp_node_bucket bucket_deg3;
1196 unsigned bucket_0_length;
1197 unsigned bucket_red_length;
1199 char *tmp = obstack_finish(&pbqp->obstack);
1201 node_bucket_init(&bucket_deg3);
1203 /* Some node buckets and the edge bucket should be empty. */
1204 assert(node_bucket_get_length(node_buckets[1]) == 0);
1205 assert(node_bucket_get_length(node_buckets[2]) == 0);
1206 assert(edge_bucket_get_length(edge_bucket) == 0);
1208 /* char *tmp = obstack_finish(&pbqp->obstack); */
1210 /* Save current PBQP state. */
1211 node_bucket_copy(&bucket_deg3, node_buckets[3]);
1212 node_bucket_shrink(&node_buckets[3], 0);
1213 node_bucket_deep_copy(pbqp, &node_buckets[3], bucket_deg3);
1214 node_bucket_update(pbqp, node_buckets[3]);
1215 bucket_0_length = node_bucket_get_length(node_buckets[0]);
1216 bucket_red_length = node_bucket_get_length(reduced_bucket);
1218 /* Select alternative and solve PBQP recursively. */
1219 select_alternative(node_buckets[3][bucket_index], node_index);
1220 apply_brute_force_reductions(pbqp);
1222 value = determine_solution(pbqp);
1226 min_index = node_index;
1229 /* Some node buckets and the edge bucket should still be empty. */
1230 assert(node_bucket_get_length(node_buckets[1]) == 0);
1231 assert(node_bucket_get_length(node_buckets[2]) == 0);
1232 assert(edge_bucket_get_length(edge_bucket) == 0);
1234 /* Clear modified buckets... */
1235 node_bucket_shrink(&node_buckets[3], 0);
1237 /* ... and restore old PBQP state. */
1238 node_bucket_shrink(&node_buckets[0], bucket_0_length);
1239 node_bucket_shrink(&reduced_bucket, bucket_red_length);
1240 node_bucket_copy(&node_buckets[3], bucket_deg3);
1241 node_bucket_update(pbqp, node_buckets[3]);
1244 /* obstack_free(&pbqp->obstack, tmp); */
1245 node_bucket_free(&bucket_deg3);
1247 obstack_free(&pbqp->obstack, tmp);
1253 void apply_Brute_Force(pbqp *pbqp)
1255 pbqp_node *node = NULL;
1256 unsigned min_index = 0;
1260 /* We want to reduce a node with maximum degree. */
1261 node = get_node_with_max_degree();
1263 assert(pbqp_node_get_degree(node) > 2);
1266 if (pbqp->dump_file) {
1268 sprintf(txt, "BF-Reduction of Node n%d", node->index);
1269 dump_section(pbqp->dump_file, 2, txt);
1270 pbqp_dump_graph(pbqp);
1278 min_index = get_minimal_alternative(pbqp, node);
1279 node = pbqp->nodes[node->index];
1282 if (pbqp->dump_file) {
1283 fprintf(pbqp->dump_file, "node n%d is set to %d<br><br>\n",
1284 node->index, min_index);
1291 FILE *fh = fopen("solutions.pb", "a");
1292 fprintf(fh, "[%u]", min_index);
1298 /* Now that we found the minimum set all other costs to infinity. */
1299 select_alternative(node, min_index);
1302 void solve_pbqp_brute_force(pbqp *pbqp)
1304 /* Reduce nodes degree ... */
1305 initial_simplify_edges(pbqp);
1307 /* ... and put node into bucket representing their degree. */
1308 fill_node_buckets(pbqp);
1311 FILE *fh = fopen("solutions.pb", "a");
1312 fprintf(fh, "Solution");
1316 apply_brute_force_reductions(pbqp);
1318 pbqp->solution = determine_solution(pbqp);
1321 fh = fopen("solutions.pb", "a");
1322 fprintf(fh, ": %lld RE:%u R0:%u R1:%u R2:%u RN/BF:%u\n", pbqp->solution,
1323 pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
1328 /* Solve reduced nodes. */
1329 back_propagate(pbqp);
1334 void back_propagate_RI(pbqp *pbqp, pbqp_node *node)
1345 edge = node->edges[0];
1347 is_src = edge->src == node;
1354 /* Update pointer for brute force solver. */
1355 other = pbqp->nodes[other->index];
1357 node->solution = pbqp_matrix_get_col_min_index(mat, other->solution, vec);
1362 /* Update pointer for brute force solver. */
1363 other = pbqp->nodes[other->index];
1365 node->solution = pbqp_matrix_get_row_min_index(mat, other->solution, vec);
1369 if (pbqp->dump_file) {
1370 fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
1375 void back_propagate_RII(pbqp *pbqp, pbqp_node *node)
1377 pbqp_edge *src_edge = node->edges[0];
1378 pbqp_edge *tgt_edge = node->edges[1];
1379 int src_is_src = src_edge->src == node;
1380 int tgt_is_src = tgt_edge->src == node;
1381 pbqp_matrix *src_mat;
1382 pbqp_matrix *tgt_mat;
1383 pbqp_node *src_node;
1384 pbqp_node *tgt_node;
1393 src_node = src_edge->tgt;
1395 src_node = src_edge->src;
1399 tgt_node = tgt_edge->tgt;
1401 tgt_node = tgt_edge->src;
1404 /* Swap nodes if necessary. */
1405 if (tgt_node->index < src_node->index) {
1406 pbqp_node *tmp_node;
1407 pbqp_edge *tmp_edge;
1409 tmp_node = src_node;
1410 src_node = tgt_node;
1411 tgt_node = tmp_node;
1413 tmp_edge = src_edge;
1414 src_edge = tgt_edge;
1415 tgt_edge = tmp_edge;
1417 src_is_src = src_edge->src == node;
1418 tgt_is_src = tgt_edge->src == node;
1421 /* Update pointer for brute force solver. */
1422 src_node = pbqp->nodes[src_node->index];
1423 tgt_node = pbqp->nodes[tgt_node->index];
1425 src_mat = src_edge->costs;
1426 tgt_mat = tgt_edge->costs;
1428 node_vec = node->costs;
1430 row_index = src_node->solution;
1431 col_index = tgt_node->solution;
1433 vec = vector_copy(pbqp, node_vec);
1436 vector_add_matrix_col(vec, src_mat, row_index);
1438 vector_add_matrix_row(vec, src_mat, row_index);
1442 vector_add_matrix_col(vec, tgt_mat, col_index);
1444 vector_add_matrix_row(vec, tgt_mat, col_index);
1447 node->solution = vector_get_min_index(vec);
1450 if (pbqp->dump_file) {
1451 fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
1455 obstack_free(&pbqp->obstack, vec);
1458 int node_is_reduced(pbqp_node *node)
1460 if (!reduced_bucket) return 0;
1462 if (pbqp_node_get_degree(node) == 0) return 1;
1464 return node_bucket_contains(reduced_bucket, node);