a1c3dd53a9b8df3d2e5f74e644e6bb0dbacb0306
[libfirm] / heuristical.c
1 #include "adt/array.h"
2 #include "assert.h"
3 #include "error.h"
4
5 #include "bucket.h"
6 #include "heuristical.h"
7 #include "html_dumper.h"
8 #include "kaps.h"
9 #include "matrix.h"
10 #include "pbqp_edge.h"
11 #include "pbqp_edge_t.h"
12 #include "pbqp_node.h"
13 #include "pbqp_node_t.h"
14 #include "vector.h"
15
16 static pbqp_edge **edge_bucket;
17 static pbqp_node **node_buckets[4];
18 static pbqp_node **reduced_bucket = NULL;
19 static int         buckets_filled = 0;
20
21 static void insert_into_edge_bucket(pbqp_edge *edge)
22 {
23         if (edge_bucket_contains(edge_bucket, edge)) {
24                 /* Edge is already inserted. */
25                 return;
26         }
27
28         edge_bucket_insert(&edge_bucket, edge);
29 }
30
31 static void init_buckets(void)
32 {
33         int i;
34
35         edge_bucket_init(&edge_bucket);
36         node_bucket_init(&reduced_bucket);
37
38         for (i = 0; i < 4; ++i) {
39                 node_bucket_init(&node_buckets[i]);
40         }
41 }
42
43 static void free_buckets(void)
44 {
45         int i;
46
47         for (i = 0; i < 4; ++i) {
48                 node_bucket_free(&node_buckets[i]);
49         }
50
51         edge_bucket_free(&edge_bucket);
52         node_bucket_free(&reduced_bucket);
53
54         buckets_filled = 0;
55 }
56
57 static void fill_node_buckets(pbqp *pbqp)
58 {
59         unsigned node_index;
60         unsigned node_len;
61
62         assert(pbqp);
63         node_len = pbqp->num_nodes;
64
65         for (node_index = 0; node_index < node_len; ++node_index) {
66                 unsigned   degree;
67                 pbqp_node *node = get_node(pbqp, node_index);
68
69                 if (!node) continue;
70
71                 degree = pbqp_node_get_degree(node);
72
73                 /* We have only one bucket for nodes with arity >= 3. */
74                 if (degree > 3) {
75                         degree = 3;
76                 }
77
78                 node_bucket_insert(&node_buckets[degree], node);
79         }
80
81         buckets_filled = 1;
82 }
83
84 static void normalize_towards_source(pbqp *pbqp, pbqp_edge *edge)
85 {
86         pbqp_matrix    *mat;
87         pbqp_node      *src_node;
88         pbqp_node      *tgt_node;
89         vector         *src_vec;
90         vector         *tgt_vec;
91         int             src_len;
92         int             tgt_len;
93         int             src_index;
94
95         assert(pbqp);
96         assert(edge);
97
98         src_node = edge->src;
99         tgt_node = edge->tgt;
100         assert(src_node);
101         assert(tgt_node);
102
103         src_vec = src_node->costs;
104         tgt_vec = tgt_node->costs;
105         assert(src_vec);
106         assert(tgt_vec);
107
108         src_len = src_vec->len;
109         tgt_len = tgt_vec->len;
110         assert(src_len > 0);
111         assert(tgt_len > 0);
112
113         mat = edge->costs;
114         assert(mat);
115
116         /* Normalize towards source node. */
117         for (src_index = 0; src_index < src_len; ++src_index) {
118                 num min = pbqp_matrix_get_row_min(mat, src_index, tgt_vec);
119
120                 if (min != 0) {
121                         if (src_vec->entries[src_index].data == INF_COSTS) {
122                                 pbqp_matrix_set_row_value(mat, src_index, 0);
123                         } else {
124                                 pbqp_matrix_sub_row_value(mat, src_index, tgt_vec, min);
125                         }
126                         src_vec->entries[src_index].data = pbqp_add(
127                                         src_vec->entries[src_index].data, min);
128
129                         if (min == INF_COSTS) {
130                                 unsigned edge_index;
131                                 unsigned edge_len = pbqp_node_get_degree(src_node);
132
133                                 for (edge_index = 0; edge_index < edge_len; ++edge_index) {
134                                         pbqp_edge *edge_candidate = src_node->edges[edge_index];
135                                         if (edge_candidate != edge) {
136                                                 insert_into_edge_bucket(edge_candidate);
137                                         }
138                                 }
139                         }
140                 }
141         }
142 }
143
144 static void normalize_towards_target(pbqp *pbqp, pbqp_edge *edge)
145 {
146         pbqp_matrix    *mat;
147         pbqp_node      *src_node;
148         pbqp_node      *tgt_node;
149         vector         *src_vec;
150         vector         *tgt_vec;
151         int             src_len;
152         int             tgt_len;
153         int             tgt_index;
154
155         assert(pbqp);
156         assert(edge);
157
158         src_node = edge->src;
159         tgt_node = edge->tgt;
160         assert(src_node);
161         assert(tgt_node);
162
163         src_vec = src_node->costs;
164         tgt_vec = tgt_node->costs;
165         assert(src_vec);
166         assert(tgt_vec);
167
168         src_len = src_vec->len;
169         tgt_len = tgt_vec->len;
170         assert(src_len > 0);
171         assert(tgt_len > 0);
172
173         mat = edge->costs;
174         assert(mat);
175
176         for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
177                 num min = pbqp_matrix_get_col_min(mat, tgt_index, src_vec);
178
179                 if (min != 0) {
180                         if (tgt_vec->entries[tgt_index].data == INF_COSTS) {
181                                 pbqp_matrix_set_col_value(mat, tgt_index, 0);
182                         } else {
183                                 pbqp_matrix_sub_col_value(mat, tgt_index, src_vec, min);
184                         }
185                         tgt_vec->entries[tgt_index].data = pbqp_add(
186                                         tgt_vec->entries[tgt_index].data, min);
187
188                         if (min == INF_COSTS) {
189                                 unsigned edge_index;
190                                 unsigned edge_len = pbqp_node_get_degree(tgt_node);
191
192                                 for (edge_index = 0; edge_index < edge_len; ++edge_index) {
193                                         pbqp_edge *edge_candidate = tgt_node->edges[edge_index];
194                                         if (edge_candidate != edge) {
195                                                 insert_into_edge_bucket(edge_candidate);
196                                         }
197                                 }
198                         }
199                 }
200         }
201 }
202
203 static void reorder_node(pbqp_node *node)
204 {
205         unsigned    degree     = pbqp_node_get_degree(node);
206         /* Assume node lost one incident edge. */
207         unsigned    old_degree = degree + 1;
208
209         if (!buckets_filled) return;
210
211         /* Same bucket as before */
212         if (degree > 2) return;
213
214         if (!node_bucket_contains(node_buckets[old_degree], node)) {
215                 /* Old arity is new arity, so we have nothing to do. */
216                 assert(node_bucket_contains(node_buckets[degree], node));
217                 return;
218         }
219
220         /* Delete node from old bucket... */
221         node_bucket_remove(&node_buckets[old_degree], node);
222
223         /* ..and add to new one. */
224         node_bucket_insert(&node_buckets[degree], node);
225 }
226
227 static void check_melting_possibility(pbqp *pbqp, pbqp_edge *edge)
228 {
229         pbqp_matrix    *mat;
230         pbqp_node      *src_node;
231         pbqp_node      *tgt_node;
232         vector         *src_vec;
233         vector         *tgt_vec;
234         int             src_len;
235         int             tgt_len;
236         int             src_index;
237         int             tgt_index;
238
239         assert(pbqp);
240         assert(edge);
241
242         src_node = edge->src;
243         tgt_node = edge->tgt;
244         assert(src_node);
245         assert(tgt_node);
246
247         src_vec = src_node->costs;
248         tgt_vec = tgt_node->costs;
249         assert(src_vec);
250         assert(tgt_vec);
251
252         src_len = src_vec->len;
253         tgt_len = tgt_vec->len;
254         assert(src_len > 0);
255         assert(tgt_len > 0);
256
257         mat = edge->costs;
258         assert(mat);
259
260         if (src_len == 1 && tgt_len == 1) {
261                 //panic("Something is wrong");
262         }
263
264         int allRowsOk = 1;
265         for (src_index = 0; src_index < src_len; ++src_index) {
266                 int onlyOneZero = 0;
267                 if (src_vec->entries[src_index].data == INF_COSTS) {
268                         continue;
269                 }
270                 for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
271                         if (tgt_vec->entries[tgt_index].data == INF_COSTS) {
272                                 continue;
273                         }
274                         if (mat->entries[src_index * tgt_len + tgt_index] == 0) {
275                                 if (onlyOneZero) {
276                                         onlyOneZero = 0;
277                                         break;
278                                 } else {
279                                         onlyOneZero = 1;
280                                         continue;
281                                 }
282                         }
283                         if (mat->entries[src_index * tgt_len + tgt_index] == INF_COSTS) {
284                                 continue;
285                         }
286                         onlyOneZero = 0;
287                         break;
288                 }
289                 allRowsOk &= onlyOneZero;
290         }
291
292         int allColsOk = 1;
293         for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
294                 int onlyOneZero = 0;
295                 if (tgt_vec->entries[tgt_index].data == INF_COSTS) {
296                         continue;
297                 }
298                 for (src_index = 0; src_index < src_len; ++src_index) {
299                         if (src_vec->entries[src_index].data == INF_COSTS) {
300                                 continue;
301                         }
302                         if (mat->entries[src_index * tgt_len + tgt_index] == 0) {
303                                 if (onlyOneZero) {
304                                         onlyOneZero = 0;
305                                         break;
306                                 } else {
307                                         onlyOneZero = 1;
308                                         continue;
309                                 }
310                         }
311                         if (mat->entries[src_index * tgt_len + tgt_index] == INF_COSTS) {
312                                 continue;
313                         }
314                         onlyOneZero = 0;
315                         break;
316                 }
317                 allColsOk &= onlyOneZero;
318         }
319
320         if (allRowsOk && allColsOk) {
321                 panic("Hurray");
322         }
323 }
324
325 static void simplify_edge(pbqp *pbqp, pbqp_edge *edge)
326 {
327         pbqp_matrix    *mat;
328         pbqp_node      *src_node;
329         pbqp_node      *tgt_node;
330         vector         *src_vec;
331         vector         *tgt_vec;
332         int             src_len;
333         int             tgt_len;
334
335         assert(pbqp);
336         assert(edge);
337
338         src_node = edge->src;
339         tgt_node = edge->tgt;
340         assert(src_node);
341         assert(tgt_node);
342
343         /* If edge are already deleted, we have nothing to do. */
344         if (!is_connected(src_node, edge) || !is_connected(tgt_node, edge))
345                 return;
346
347         if (pbqp->dump_file) {
348                 char txt[100];
349                 sprintf(txt, "Simplification of Edge n%d-n%d", src_node->index, tgt_node->index);
350                 dump_section(pbqp->dump_file, 3, txt);
351         }
352
353         src_vec = src_node->costs;
354         tgt_vec = tgt_node->costs;
355         assert(src_vec);
356         assert(tgt_vec);
357
358         src_len = src_vec->len;
359         tgt_len = tgt_vec->len;
360         assert(src_len > 0);
361         assert(tgt_len > 0);
362
363         mat = edge->costs;
364         assert(mat);
365
366         if (pbqp->dump_file) {
367                 fputs("Input:<br>\n", pbqp->dump_file);
368                 dump_simplifyedge(pbqp, edge);
369         }
370
371         normalize_towards_source(pbqp, edge);
372         normalize_towards_target(pbqp, edge);
373
374         if (pbqp->dump_file) {
375                 fputs("<br>\nOutput:<br>\n", pbqp->dump_file);
376                 dump_simplifyedge(pbqp, edge);
377         }
378
379         if (pbqp_matrix_is_zero(mat, src_vec, tgt_vec)) {
380                 if (pbqp->dump_file) {
381                         fputs("edge has been eliminated<br>\n", pbqp->dump_file);
382                 }
383
384                 delete_edge(edge);
385                 reorder_node(src_node);
386                 reorder_node(tgt_node);
387         } else {
388                 //check_melting_possibility(pbqp, edge);
389         }
390 }
391
392 static void initial_simplify_edges(pbqp *pbqp)
393 {
394         unsigned node_index;
395         unsigned node_len;
396
397         assert(pbqp);
398
399         if (pbqp->dump_file) {
400                 pbqp_dump_input(pbqp);
401                 dump_section(pbqp->dump_file, 1, "2. Simplification of Cost Matrices");
402         }
403
404         node_len = pbqp->num_nodes;
405
406         init_buckets();
407
408         /* First simplify all edges. */
409         for (node_index = 0; node_index < node_len; ++node_index) {
410                 unsigned    edge_index;
411                 pbqp_node  *node = get_node(pbqp, node_index);
412                 pbqp_edge **edges;
413                 unsigned    edge_len;
414
415                 if (!node) continue;
416
417                 edges = node->edges;
418                 edge_len = pbqp_node_get_degree(node);
419
420                 for (edge_index = 0; edge_index < edge_len; ++edge_index) {
421                         pbqp_edge *edge = edges[edge_index];
422
423                         /* Simplify only once per edge. */
424                         if (node != edge->src) continue;
425
426                         simplify_edge(pbqp, edge);
427                 }
428         }
429 }
430
431 num determine_solution(FILE *file)
432 {
433         unsigned node_index;
434         unsigned node_len;
435         num      solution;
436
437         if (file) {
438                 dump_section(file, 1, "4. Determine Solution/Minimum");
439                 dump_section(file, 2, "4.1. Trivial Solution");
440         }
441
442         /* Solve trivial nodes and calculate solution. */
443         node_len = node_bucket_get_length(node_buckets[0]);
444         for (node_index = 0; node_index < node_len; ++node_index) {
445                 pbqp_node *node = node_buckets[0][node_index];
446                 assert(node);
447
448                 node->solution = vector_get_min_index(node->costs);
449                 solution       = pbqp_add(solution,
450                                 node->costs->entries[node->solution].data);
451                 if (file) {
452                         fprintf(file, "node n%d is set to %d<br>\n", node->index, node->solution);
453                         dump_node(file, node);
454                 }
455         }
456
457         if (file) {
458                 dump_section(file, 2, "Minimum");
459                 fprintf(file, "Minimum is equal to %lld.", solution);
460         }
461
462         return solution;
463 }
464
465 static void back_propagate(pbqp *pbqp)
466 {
467         unsigned node_index;
468         unsigned node_len   = node_bucket_get_length(reduced_bucket);
469
470         assert(pbqp);
471         if (pbqp->dump_file) {
472                 dump_section(pbqp->dump_file, 2, "Back Propagation");
473         }
474
475         for (node_index = node_len; node_index > 0; --node_index) {
476                 pbqp_node *node = reduced_bucket[node_index - 1];
477
478                 switch (pbqp_node_get_degree(node)) {
479                         case 1:
480                                 back_propagate_RI(pbqp, node);
481                                 break;
482                         case 2:
483                                 back_propagate_RII(pbqp, node);
484                                 break;
485                         default:
486                                 panic("Only nodes with degree one or two should be in this bucket");
487                                 break;
488                 }
489         }
490 }
491
492 void solve_pbqp_heuristical(pbqp *pbqp)
493 {
494         /* Reduce nodes degree ... */
495         initial_simplify_edges(pbqp);
496
497         /* ... and put node into bucket representing their degree. */
498         fill_node_buckets(pbqp);
499
500         for (;;) {
501                 if (edge_bucket_get_length(edge_bucket) > 0) {
502                         apply_edge(pbqp);
503                 } else if (node_bucket_get_length(node_buckets[1]) > 0) {
504                         apply_RI(pbqp);
505                 } else if (node_bucket_get_length(node_buckets[2]) > 0) {
506                         apply_RII(pbqp);
507                 } else if (node_bucket_get_length(node_buckets[3]) > 0) {
508                         apply_RN(pbqp);
509                 } else {
510                         break;
511                 }
512         }
513
514         pbqp->solution = determine_solution(pbqp->dump_file);
515
516         /* Solve reduced nodes. */
517         back_propagate(pbqp);
518
519         free_buckets();
520 }
521
522 void apply_edge(pbqp *pbqp)
523 {
524         pbqp_edge *edge = edge_bucket_pop(&edge_bucket);
525
526         simplify_edge(pbqp, edge);
527 }
528
529 void apply_RI(pbqp *pbqp)
530 {
531         pbqp_node   *node       = node_bucket_pop(&node_buckets[1]);
532         pbqp_edge   *edge       = node->edges[0];
533         pbqp_matrix *mat        = edge->costs;
534         int          is_src     = edge->src == node;
535         pbqp_node   *other_node;
536
537         if (is_src) {
538                 other_node = edge->tgt;
539         } else {
540                 other_node = edge->src;
541         }
542
543         if (pbqp->dump_file) {
544                 char     txt[100];
545                 sprintf(txt, "RI-Reduction of Node n%d", node->index);
546                 dump_section(pbqp->dump_file, 2, txt);
547                 pbqp_dump_graph(pbqp);
548                 fputs("<br>\nBefore reduction:<br>\n", pbqp->dump_file);
549                 dump_node(pbqp->dump_file, node);
550                 dump_node(pbqp->dump_file, other_node);
551                 dump_edge(pbqp->dump_file, edge);
552         }
553
554         if (is_src) {
555                 pbqp_matrix_add_to_all_cols(mat, node->costs);
556                 normalize_towards_target(pbqp, edge);
557         } else {
558                 pbqp_matrix_add_to_all_rows(mat, node->costs);
559                 normalize_towards_source(pbqp, edge);
560         }
561         disconnect_edge(other_node, edge);
562
563         if (pbqp->dump_file) {
564                 fputs("<br>\nAfter reduction:<br>\n", pbqp->dump_file);
565                 dump_node(pbqp->dump_file, other_node);
566         }
567
568         reorder_node(other_node);
569
570         /* Add node to back propagation list. */
571         node_bucket_insert(&reduced_bucket, node);
572 }
573
574 void apply_RII(pbqp *pbqp)
575 {
576         pbqp_node   *node       = node_bucket_pop(&node_buckets[2]);
577         pbqp_edge   *src_edge   = node->edges[0];
578         pbqp_edge   *tgt_edge   = node->edges[1];
579         int          src_is_src = src_edge->src == node;
580         int          tgt_is_src = tgt_edge->src == node;
581         pbqp_matrix *src_mat;
582         pbqp_matrix *tgt_mat;
583         pbqp_node   *src_node;
584         pbqp_node   *tgt_node;
585         pbqp_matrix *mat;
586         vector      *vec;
587         vector      *node_vec;
588         vector      *src_vec;
589         vector      *tgt_vec;
590         unsigned     col_index;
591         unsigned     col_len;
592         unsigned     row_index;
593         unsigned     row_len;
594         unsigned     node_len;
595
596         assert(pbqp);
597
598         if (src_is_src) {
599                 src_node = src_edge->tgt;
600         } else {
601                 src_node = src_edge->src;
602         }
603
604         if (tgt_is_src) {
605                 tgt_node = tgt_edge->tgt;
606         } else {
607                 tgt_node = tgt_edge->src;
608         }
609
610         /* Swap nodes if necessary. */
611         if (tgt_node->index < src_node->index) {
612                 pbqp_node *tmp_node;
613                 pbqp_edge *tmp_edge;
614
615                 tmp_node = src_node;
616                 src_node = tgt_node;
617                 tgt_node = tmp_node;
618
619                 tmp_edge = src_edge;
620                 src_edge = tgt_edge;
621                 tgt_edge = tmp_edge;
622
623                 src_is_src = src_edge->src == node;
624                 tgt_is_src = tgt_edge->src == node;
625         }
626
627         if (pbqp->dump_file) {
628                 char     txt[100];
629                 sprintf(txt, "RII-Reduction of Node n%d", node->index);
630                 dump_section(pbqp->dump_file, 2, txt);
631                 pbqp_dump_graph(pbqp);
632                 fputs("<br>\nBefore reduction:<br>\n", pbqp->dump_file);
633                 dump_node(pbqp->dump_file, src_node);
634                 dump_edge(pbqp->dump_file, src_edge);
635                 dump_node(pbqp->dump_file, node);
636                 dump_edge(pbqp->dump_file, tgt_edge);
637                 dump_node(pbqp->dump_file, tgt_node);
638         }
639
640         src_mat = src_edge->costs;
641         tgt_mat = tgt_edge->costs;
642
643         src_vec  = src_node->costs;
644         tgt_vec  = tgt_node->costs;
645         node_vec = node->costs;
646
647         row_len  = src_vec->len;
648         col_len  = tgt_vec->len;
649         node_len = node_vec->len;
650
651         mat = pbqp_matrix_alloc(pbqp, row_len, col_len);
652
653         for (row_index = 0; row_index < row_len; ++row_index) {
654                 for (col_index = 0; col_index < col_len; ++col_index) {
655                         vec = vector_copy(pbqp, node_vec);
656
657                         if (src_is_src) {
658                                 vector_add_matrix_col(vec, src_mat, row_index);
659                         } else {
660                                 vector_add_matrix_row(vec, src_mat, row_index);
661                         }
662
663                         if (tgt_is_src) {
664                                 vector_add_matrix_col(vec, tgt_mat, col_index);
665                         } else {
666                                 vector_add_matrix_row(vec, tgt_mat, col_index);
667                         }
668
669                         mat->entries[row_index * col_len + col_index] = vector_get_min(vec);
670
671                         obstack_free(&pbqp->obstack, vec);
672                 }
673         }
674
675         pbqp_edge *edge = get_edge(pbqp, src_node->index, tgt_node->index);
676
677         /* Disconnect node. */
678         disconnect_edge(src_node, src_edge);
679         disconnect_edge(tgt_node, tgt_edge);
680
681         /* Add node to back propagation list. */
682         node_bucket_insert(&reduced_bucket, node);
683
684         if (edge == NULL) {
685                 edge = alloc_edge(pbqp, src_node->index, tgt_node->index, mat);
686         } else {
687                 pbqp_matrix_add(edge->costs, mat);
688
689                 /* Free local matrix. */
690                 obstack_free(&pbqp->obstack, mat);
691
692                 reorder_node(src_node);
693                 reorder_node(tgt_node);
694         }
695
696         if (pbqp->dump_file) {
697                 fputs("<br>\nAfter reduction:<br>\n", pbqp->dump_file);
698                 dump_edge(pbqp->dump_file, edge);
699         }
700
701         /* Edge has changed so we simplify it. */
702         simplify_edge(pbqp, edge);
703 }
704
705 static void select_alternative(pbqp_node *node, unsigned selected_index)
706 {
707         unsigned  edge_index;
708         unsigned  node_index;
709         unsigned  node_len;
710         vector   *node_vec;
711         unsigned  max_degree = pbqp_node_get_degree(node);
712
713         assert(selected_index < max_degree);
714         assert(node);
715         node->solution = selected_index;
716         node_vec = node->costs;
717         node_len = node_vec->len;
718
719         /* Set all other costs to infinity. */
720         for (node_index = 0; node_index < node_len; ++node_index) {
721                 if (node_index != selected_index) {
722                         node_vec->entries[node_index].data = INF_COSTS;
723                 }
724         }
725
726         /* Add all incident edges to edge bucket, since they are now independent. */
727         for (edge_index = 0; edge_index < max_degree; ++edge_index) {
728                 insert_into_edge_bucket(node->edges[edge_index]);
729         }
730 }
731
732 static pbqp_node *get_node_with_max_degree(void)
733 {
734         pbqp_node  **bucket       = node_buckets[3];
735         unsigned     bucket_len   = node_bucket_get_length(bucket);
736         unsigned     bucket_index;
737         unsigned     max_degree   = 0;
738         pbqp_node   *result       = NULL;
739
740         for (bucket_index = 0; bucket_index < bucket_len; ++bucket_index) {
741                 pbqp_node *candidate = bucket[bucket_index];
742                 unsigned   degree    = pbqp_node_get_degree(candidate);
743
744                 if (degree > max_degree) {
745                         result = candidate;
746                         max_degree = degree;
747                 }
748         }
749
750         return result;
751 }
752
753 static unsigned get_local_minimal_alternative(pbqp *pbqp, pbqp_node *node)
754 {
755         pbqp_edge   *edge;
756         vector      *node_vec;
757         vector      *vec;
758         pbqp_matrix *mat;
759         unsigned     edge_index;
760         unsigned     max_degree   = 0;
761         unsigned     node_index;
762         unsigned     node_len;
763         unsigned     min_index    = 0;
764         num          min          = INF_COSTS;
765         int          is_src;
766
767         assert(pbqp);
768         assert(node);
769         node_vec = node->costs;
770         node_len = node_vec->len;
771
772         for (node_index = 0; node_index < node_len; ++node_index) {
773                 num value = node_vec->entries[node_index].data;
774
775                 for (edge_index = 0; edge_index < max_degree; ++edge_index) {
776                         edge   = node->edges[edge_index];
777                         mat    = edge->costs;
778                         is_src = edge->src == node;
779
780                         if (is_src) {
781                                 vec = vector_copy(pbqp, edge->tgt->costs);
782                                 vector_add_matrix_row(vec, mat, node_index);
783                         } else {
784                                 vec = vector_copy(pbqp, edge->src->costs);
785                                 vector_add_matrix_col(vec, mat, node_index);
786                         }
787
788                         value = pbqp_add(value, vector_get_min(vec));
789
790                         obstack_free(&pbqp->obstack, vec);
791                 }
792
793                 if (value < min) {
794                         min = value;
795                         min_index = node_index;
796                 }
797         }
798
799         return min_index;
800 }
801
802 void apply_RN(pbqp *pbqp)
803 {
804         pbqp_node   *node         = NULL;
805         unsigned     min_index    = 0;
806
807         assert(pbqp);
808
809         /* We want to reduce a node with maximum degree. */
810         node = get_node_with_max_degree();
811         assert(node);
812
813         if (pbqp->dump_file) {
814                 char     txt[100];
815                 sprintf(txt, "RN-Reduction of Node n%d", node->index);
816                 dump_section(pbqp->dump_file, 2, txt);
817                 pbqp_dump_graph(pbqp);
818         }
819
820         min_index = get_local_minimal_alternative(pbqp, node);
821
822         if (pbqp->dump_file) {
823                 fprintf(pbqp->dump_file, "node n%d is set to %d<br><br>\n",
824                                         node->index, min_index);
825         }
826
827         /* Now that we found the local minimum set all other costs to infinity. */
828         select_alternative(node, min_index);
829 }
830
831 static unsigned get_minimal_alternative(pbqp *pbqp, pbqp_node *node)
832 {
833         pbqp_edge   *edge;
834         vector      *node_vec;
835         vector      *vec;
836         pbqp_matrix *mat;
837         unsigned     edge_index;
838         unsigned     max_degree   = 0;
839         unsigned     node_index;
840         unsigned     node_len;
841         unsigned     min_index    = 0;
842         num          min          = INF_COSTS;
843         int          is_src;
844
845         assert(pbqp);
846         assert(node);
847         node_vec = node->costs;
848         node_len = node_vec->len;
849
850         for (node_index = 0; node_index < node_len; ++node_index) {
851                 num value = node_vec->entries[node_index].data;
852
853                 /* Some node buckets and the edge bucket should be empty. */
854                 assert(node_bucket_get_length(node_buckets[1]) == 0);
855                 assert(node_bucket_get_length(node_buckets[2]) == 0);
856                 assert(edge_bucket_get_length(edge_bucket)     == 0);
857
858                 /* Save current PBQP state. */
859                 pbqp_node_bucket *bucket_deg0 = node_bucket_deep_copy(node_buckets[0]);
860                 pbqp_node_bucket *bucket_deg3 = node_bucket_deep_copy(node_buckets[3]);
861                 pbqp_node_bucket *bucket_red  = node_bucket_deep_copy(reduced_bucket);
862
863                 /* TODO */
864
865                 if (value < min) {
866                         min = value;
867                         min_index = node_index;
868                 }
869         }
870         return 0;
871 }
872
873 void apply_Brute_Force(pbqp *pbqp)
874 {
875         pbqp_node   *node         = NULL;
876         unsigned     min_index    = 0;
877
878         assert(pbqp);
879
880         /* We want to reduce a node with maximum degree. */
881         node = get_node_with_max_degree();
882         assert(node);
883
884         if (pbqp->dump_file) {
885                 char     txt[100];
886                 sprintf(txt, "BF-Reduction of Node n%d", node->index);
887                 dump_section(pbqp->dump_file, 2, txt);
888                 pbqp_dump_graph(pbqp);
889         }
890
891         min_index = get_minimal_alternative(pbqp, node);
892
893         if (pbqp->dump_file) {
894                 fprintf(pbqp->dump_file, "node n%d is set to %d<br><br>\n",
895                                         node->index, min_index);
896         }
897
898         /* Now that we found the minimum set all other costs to infinity. */
899         select_alternative(node, min_index);
900 }
901
902 void back_propagate_RI(pbqp *pbqp, pbqp_node *node)
903 {
904         pbqp_edge   *edge;
905         pbqp_node   *other;
906         pbqp_matrix *mat;
907         vector      *vec;
908         int          is_src;
909
910         assert(pbqp);
911         assert(node);
912
913         edge = node->edges[0];
914         mat = edge->costs;
915         is_src = edge->src == node;
916         vec = node->costs;
917
918         if (is_src) {
919                 other = edge->tgt;
920                 assert(other);
921                 vector_add_matrix_col(vec, mat, other->solution);
922         } else {
923                 other = edge->src;
924                 assert(other);
925                 vector_add_matrix_row(vec, mat, other->solution);
926         }
927
928         node->solution = vector_get_min_index(vec);
929         if (pbqp->dump_file) {
930                 fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
931         }
932 }
933
934 void back_propagate_RII(pbqp *pbqp, pbqp_node *node)
935 {
936         pbqp_edge   *src_edge   = node->edges[0];
937         pbqp_edge   *tgt_edge   = node->edges[1];
938         int          src_is_src = src_edge->src == node;
939         int          tgt_is_src = tgt_edge->src == node;
940         pbqp_matrix *src_mat;
941         pbqp_matrix *tgt_mat;
942         pbqp_node   *src_node;
943         pbqp_node   *tgt_node;
944         vector      *vec;
945         vector      *node_vec;
946         unsigned     col_index;
947         unsigned     row_index;
948
949         assert(pbqp);
950
951         if (src_is_src) {
952                 src_node = src_edge->tgt;
953         } else {
954                 src_node = src_edge->src;
955         }
956
957         if (tgt_is_src) {
958                 tgt_node = tgt_edge->tgt;
959         } else {
960                 tgt_node = tgt_edge->src;
961         }
962
963         /* Swap nodes if necessary. */
964         if (tgt_node->index < src_node->index) {
965                 pbqp_node *tmp_node;
966                 pbqp_edge *tmp_edge;
967
968                 tmp_node = src_node;
969                 src_node = tgt_node;
970                 tgt_node = tmp_node;
971
972                 tmp_edge = src_edge;
973                 src_edge = tgt_edge;
974                 tgt_edge = tmp_edge;
975
976                 src_is_src = src_edge->src == node;
977                 tgt_is_src = tgt_edge->src == node;
978         }
979
980         src_mat = src_edge->costs;
981         tgt_mat = tgt_edge->costs;
982
983         node_vec = node->costs;
984
985         row_index = src_node->solution;
986         col_index = tgt_node->solution;
987
988         vec = vector_copy(pbqp, node_vec);
989
990         if (src_is_src) {
991                 vector_add_matrix_col(vec, src_mat, row_index);
992         } else {
993                 vector_add_matrix_row(vec, src_mat, row_index);
994         }
995
996         if (tgt_is_src) {
997                 vector_add_matrix_col(vec, tgt_mat, col_index);
998         } else {
999                 vector_add_matrix_row(vec, tgt_mat, col_index);
1000         }
1001
1002         node->solution = vector_get_min_index(vec);
1003         if (pbqp->dump_file) {
1004                 fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
1005         }
1006
1007         obstack_free(&pbqp->obstack, vec);
1008 }
1009
1010 int node_is_reduced(pbqp_node *node)
1011 {
1012         if (!reduced_bucket) return 0;
1013
1014         if (pbqp_node_get_degree(node) == 0) return 1;
1015
1016         return node_bucket_contains(reduced_bucket, node);
1017 }