Use more bucket functions.
[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   arity;
67                 pbqp_node *node = get_node(pbqp, node_index);
68
69                 if (!node) continue;
70
71                 arity = ARR_LEN(node->edges);
72
73                 /* We have only one bucket for nodes with arity >= 3. */
74                 if (arity > 3) {
75                         arity = 3;
76                 }
77
78                 node_bucket_insert(&node_buckets[arity], 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 = ARR_LEN(src_node->edges);
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 = ARR_LEN(tgt_node->edges);
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    arity;
206         unsigned    old_arity;
207         unsigned    old_bucket_len;
208         unsigned    old_bucket_index;
209         pbqp_node **old_bucket;
210
211         if (!buckets_filled) return;
212
213         assert(node);
214
215         arity = ARR_LEN(node->edges);
216
217         /* Same bucket as before */
218         if (arity > 2) return;
219
220         /* Assume node lost one incident edge. */
221         old_arity        = arity + 1;
222         old_bucket       = node_buckets[old_arity];
223         old_bucket_len   = node_bucket_get_length(old_bucket);
224         old_bucket_index = node->bucket_index;
225
226         if (old_bucket_len <= old_bucket_index || old_bucket[old_bucket_index]
227                         != node) {
228                 unsigned bucket_len = node_bucket_get_length(node_buckets[arity]);
229
230                 /* Old arity is new arity, so we have nothing to do. */
231                 assert(old_bucket_index < bucket_len);
232                 assert(node_buckets[arity][old_bucket_index] == node);
233                 return;
234         }
235
236         assert(old_bucket[old_bucket_index] == node);
237
238         /* Delete node from old bucket... */
239         node_bucket_remove(&node_buckets[old_arity], node);
240
241         /* ..and add to new one. */
242         node->bucket_index = node_bucket_get_length(node_buckets[arity]);
243         ARR_APP1(pbqp_node*, node_buckets[arity], node);
244 }
245
246 static void check_melting_possibility(pbqp *pbqp, pbqp_edge *edge)
247 {
248         pbqp_matrix    *mat;
249         pbqp_node      *src_node;
250         pbqp_node      *tgt_node;
251         vector         *src_vec;
252         vector         *tgt_vec;
253         int             src_len;
254         int             tgt_len;
255         int             src_index;
256         int             tgt_index;
257
258         assert(pbqp);
259         assert(edge);
260
261         src_node = edge->src;
262         tgt_node = edge->tgt;
263         assert(src_node);
264         assert(tgt_node);
265
266         src_vec = src_node->costs;
267         tgt_vec = tgt_node->costs;
268         assert(src_vec);
269         assert(tgt_vec);
270
271         src_len = src_vec->len;
272         tgt_len = tgt_vec->len;
273         assert(src_len > 0);
274         assert(tgt_len > 0);
275
276         mat = edge->costs;
277         assert(mat);
278
279         if (src_len == 1 && tgt_len == 1) {
280                 //panic("Something is wrong");
281         }
282
283         int allRowsOk = 1;
284         for (src_index = 0; src_index < src_len; ++src_index) {
285                 int onlyOneZero = 0;
286                 if (src_vec->entries[src_index].data == INF_COSTS) {
287                         continue;
288                 }
289                 for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
290                         if (tgt_vec->entries[tgt_index].data == INF_COSTS) {
291                                 continue;
292                         }
293                         if (mat->entries[src_index * tgt_len + tgt_index] == 0) {
294                                 if (onlyOneZero) {
295                                         onlyOneZero = 0;
296                                         break;
297                                 } else {
298                                         onlyOneZero = 1;
299                                         continue;
300                                 }
301                         }
302                         if (mat->entries[src_index * tgt_len + tgt_index] == INF_COSTS) {
303                                 continue;
304                         }
305                         onlyOneZero = 0;
306                         break;
307                 }
308                 allRowsOk &= onlyOneZero;
309         }
310
311         int allColsOk = 1;
312         for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
313                 int onlyOneZero = 0;
314                 if (tgt_vec->entries[tgt_index].data == INF_COSTS) {
315                         continue;
316                 }
317                 for (src_index = 0; src_index < src_len; ++src_index) {
318                         if (src_vec->entries[src_index].data == INF_COSTS) {
319                                 continue;
320                         }
321                         if (mat->entries[src_index * tgt_len + tgt_index] == 0) {
322                                 if (onlyOneZero) {
323                                         onlyOneZero = 0;
324                                         break;
325                                 } else {
326                                         onlyOneZero = 1;
327                                         continue;
328                                 }
329                         }
330                         if (mat->entries[src_index * tgt_len + tgt_index] == INF_COSTS) {
331                                 continue;
332                         }
333                         onlyOneZero = 0;
334                         break;
335                 }
336                 allColsOk &= onlyOneZero;
337         }
338
339         if (allRowsOk && allColsOk) {
340                 panic("Hurray");
341         }
342 }
343
344 static void simplify_edge(pbqp *pbqp, pbqp_edge *edge)
345 {
346         pbqp_matrix    *mat;
347         pbqp_node      *src_node;
348         pbqp_node      *tgt_node;
349         vector         *src_vec;
350         vector         *tgt_vec;
351         int             src_len;
352         int             tgt_len;
353
354         assert(pbqp);
355         assert(edge);
356
357         src_node = edge->src;
358         tgt_node = edge->tgt;
359         assert(src_node);
360         assert(tgt_node);
361
362         /* If edge are already deleted, we have nothing to do. */
363         if (!is_connected(src_node, edge) || !is_connected(tgt_node, edge))
364                 return;
365
366         if (pbqp->dump_file) {
367                 char txt[100];
368                 sprintf(txt, "Simplification of Edge n%d-n%d", src_node->index, tgt_node->index);
369                 dump_section(pbqp->dump_file, 3, txt);
370         }
371
372         src_vec = src_node->costs;
373         tgt_vec = tgt_node->costs;
374         assert(src_vec);
375         assert(tgt_vec);
376
377         src_len = src_vec->len;
378         tgt_len = tgt_vec->len;
379         assert(src_len > 0);
380         assert(tgt_len > 0);
381
382         mat = edge->costs;
383         assert(mat);
384
385         if (pbqp->dump_file) {
386                 fputs("Input:<br>\n", pbqp->dump_file);
387                 dump_simplifyedge(pbqp, edge);
388         }
389
390         normalize_towards_source(pbqp, edge);
391         normalize_towards_target(pbqp, edge);
392
393         if (pbqp->dump_file) {
394                 fputs("<br>\nOutput:<br>\n", pbqp->dump_file);
395                 dump_simplifyedge(pbqp, edge);
396         }
397
398         if (pbqp_matrix_is_zero(mat, src_vec, tgt_vec)) {
399                 if (pbqp->dump_file) {
400                         fputs("edge has been eliminated<br>\n", pbqp->dump_file);
401                 }
402
403                 delete_edge(edge);
404                 reorder_node(src_node);
405                 reorder_node(tgt_node);
406         } else {
407                 //check_melting_possibility(pbqp, edge);
408         }
409 }
410
411 void solve_pbqp_heuristical(pbqp *pbqp)
412 {
413         unsigned node_index;
414         unsigned node_len;
415
416         assert(pbqp);
417
418         if (pbqp->dump_file) {
419                 pbqp_dump_input(pbqp);
420                 dump_section(pbqp->dump_file, 1, "2. Simplification of Cost Matrices");
421         }
422
423         node_len = pbqp->num_nodes;
424
425         init_buckets();
426
427         /* First simplify all edges. */
428         for (node_index = 0; node_index < node_len; ++node_index) {
429                 unsigned    edge_index;
430                 pbqp_node  *node = get_node(pbqp, node_index);
431                 pbqp_edge **edges;
432                 unsigned    edge_len;
433
434                 if (!node) continue;
435
436                 edges = node->edges;
437                 edge_len = ARR_LEN(edges);
438
439                 for (edge_index = 0; edge_index < edge_len; ++edge_index) {
440                         pbqp_edge *edge = edges[edge_index];
441
442                         /* Simplify only once per edge. */
443                         if (node != edge->src) continue;
444
445                         simplify_edge(pbqp, edge);
446                 }
447         }
448
449         /* Put node into bucket representing their arity. */
450         fill_node_buckets(pbqp);
451
452         for (;;) {
453                 if (edge_bucket_get_length(edge_bucket) > 0) {
454                         apply_edge(pbqp);
455                 } else if (node_bucket_get_length(node_buckets[1]) > 0) {
456                         apply_RI(pbqp);
457                 } else if (node_bucket_get_length(node_buckets[2]) > 0) {
458                         apply_RII(pbqp);
459                 } else if (node_bucket_get_length(node_buckets[3]) > 0) {
460                         apply_RN(pbqp);
461                 } else {
462                         break;
463                 }
464         }
465
466         if (pbqp->dump_file) {
467                 dump_section(pbqp->dump_file, 1, "4. Determine Solution/Minimum");
468                 dump_section(pbqp->dump_file, 2, "4.1. Trivial Solution");
469         }
470
471         /* Solve trivial nodes and calculate solution. */
472         node_len = node_bucket_get_length(node_buckets[0]);
473         for (node_index = 0; node_index < node_len; ++node_index) {
474                 pbqp_node *node = node_buckets[0][node_index];
475                 assert(node);
476
477                 node->solution = vector_get_min_index(node->costs);
478                 pbqp->solution = pbqp_add(pbqp->solution,
479                                 node->costs->entries[node->solution].data);
480                 if (pbqp->dump_file) {
481                         fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
482                         dump_node(pbqp, node);
483                 }
484         }
485
486         if (pbqp->dump_file) {
487                 dump_section(pbqp->dump_file, 2, "Minimum");
488                 fprintf(pbqp->dump_file, "Minimum is equal to %lld.", pbqp->solution);
489                 dump_section(pbqp->dump_file, 2, "Back Propagation");
490         }
491
492         /* Solve reduced nodes. */
493         node_len = node_bucket_get_length(reduced_bucket);
494         for (node_index = node_len; node_index > 0; --node_index) {
495                 pbqp_node *node = reduced_bucket[node_index - 1];
496                 assert(node);
497
498                 switch (ARR_LEN(node->edges)) {
499                         case 1:
500                                 back_propagate_RI(pbqp, node);
501                                 break;
502                         case 2:
503                                 back_propagate_RII(pbqp, node);
504                                 break;
505                         default:
506                                 panic("Only nodes with degree one or two should be in this bucket");
507                                 break;
508                 }
509         }
510
511         free_buckets();
512 }
513
514 void apply_edge(pbqp *pbqp)
515 {
516         pbqp_edge *edge = edge_bucket_pop(&edge_bucket);
517
518         simplify_edge(pbqp, edge);
519 }
520
521 void apply_RI(pbqp *pbqp)
522 {
523         pbqp_node   *node       = node_bucket_pop(&node_buckets[1]);
524         pbqp_edge   *edge       = node->edges[0];
525         pbqp_matrix *mat        = edge->costs;
526         int          is_src     = edge->src == node;
527         pbqp_node   *other_node;
528
529         if (is_src) {
530                 other_node = edge->tgt;
531         } else {
532                 other_node = edge->src;
533         }
534
535         if (pbqp->dump_file) {
536                 char     txt[100];
537                 sprintf(txt, "RI-Reduction of Node n%d", node->index);
538                 dump_section(pbqp->dump_file, 2, txt);
539                 pbqp_dump_graph(pbqp);
540                 fputs("<br>\nBefore reduction:<br>\n", pbqp->dump_file);
541                 dump_node(pbqp, node);
542                 dump_node(pbqp, other_node);
543                 dump_edge(pbqp, edge);
544         }
545
546         if (is_src) {
547                 pbqp_matrix_add_to_all_cols(mat, node->costs);
548                 normalize_towards_target(pbqp, edge);
549         } else {
550                 pbqp_matrix_add_to_all_rows(mat, node->costs);
551                 normalize_towards_source(pbqp, edge);
552         }
553         disconnect_edge(other_node, edge);
554
555         if (pbqp->dump_file) {
556                 fputs("<br>\nAfter reduction:<br>\n", pbqp->dump_file);
557                 dump_node(pbqp, other_node);
558         }
559
560         reorder_node(other_node);
561
562         /* Add node to back propagation list. */
563         node_bucket_insert(&reduced_bucket, node);
564 }
565
566 void apply_RII(pbqp *pbqp)
567 {
568         pbqp_node   *node       = node_bucket_pop(&node_buckets[2]);
569         pbqp_edge   *src_edge   = node->edges[0];
570         pbqp_edge   *tgt_edge   = node->edges[1];
571         int          src_is_src = src_edge->src == node;
572         int          tgt_is_src = tgt_edge->src == node;
573         pbqp_matrix *src_mat;
574         pbqp_matrix *tgt_mat;
575         pbqp_node   *src_node;
576         pbqp_node   *tgt_node;
577         pbqp_matrix *mat;
578         vector      *vec;
579         vector      *node_vec;
580         vector      *src_vec;
581         vector      *tgt_vec;
582         unsigned     col_index;
583         unsigned     col_len;
584         unsigned     row_index;
585         unsigned     row_len;
586         unsigned     node_len;
587
588         assert(pbqp);
589
590         if (src_is_src) {
591                 src_node = src_edge->tgt;
592         } else {
593                 src_node = src_edge->src;
594         }
595
596         if (tgt_is_src) {
597                 tgt_node = tgt_edge->tgt;
598         } else {
599                 tgt_node = tgt_edge->src;
600         }
601
602         /* Swap nodes if necessary. */
603         if (tgt_node->index < src_node->index) {
604                 pbqp_node *tmp_node;
605                 pbqp_edge *tmp_edge;
606
607                 tmp_node = src_node;
608                 src_node = tgt_node;
609                 tgt_node = tmp_node;
610
611                 tmp_edge = src_edge;
612                 src_edge = tgt_edge;
613                 tgt_edge = tmp_edge;
614
615                 src_is_src = src_edge->src == node;
616                 tgt_is_src = tgt_edge->src == node;
617         }
618
619         if (pbqp->dump_file) {
620                 char     txt[100];
621                 sprintf(txt, "RII-Reduction of Node n%d", node->index);
622                 dump_section(pbqp->dump_file, 2, txt);
623                 pbqp_dump_graph(pbqp);
624                 fputs("<br>\nBefore reduction:<br>\n", pbqp->dump_file);
625                 dump_node(pbqp, src_node);
626                 dump_edge(pbqp, src_edge);
627                 dump_node(pbqp, node);
628                 dump_edge(pbqp, tgt_edge);
629                 dump_node(pbqp, tgt_node);
630         }
631
632         src_mat = src_edge->costs;
633         tgt_mat = tgt_edge->costs;
634
635         src_vec  = src_node->costs;
636         tgt_vec  = tgt_node->costs;
637         node_vec = node->costs;
638
639         row_len  = src_vec->len;
640         col_len  = tgt_vec->len;
641         node_len = node_vec->len;
642
643         mat = pbqp_matrix_alloc(pbqp, row_len, col_len);
644
645         for (row_index = 0; row_index < row_len; ++row_index) {
646                 for (col_index = 0; col_index < col_len; ++col_index) {
647                         vec = vector_copy(pbqp, node_vec);
648
649                         if (src_is_src) {
650                                 vector_add_matrix_col(vec, src_mat, row_index);
651                         } else {
652                                 vector_add_matrix_row(vec, src_mat, row_index);
653                         }
654
655                         if (tgt_is_src) {
656                                 vector_add_matrix_col(vec, tgt_mat, col_index);
657                         } else {
658                                 vector_add_matrix_row(vec, tgt_mat, col_index);
659                         }
660
661                         mat->entries[row_index * col_len + col_index] = vector_get_min(vec);
662
663                         obstack_free(&pbqp->obstack, vec);
664                 }
665         }
666
667         pbqp_edge *edge = get_edge(pbqp, src_node->index, tgt_node->index);
668
669         /* Disconnect node. */
670         disconnect_edge(src_node, src_edge);
671         disconnect_edge(tgt_node, tgt_edge);
672
673         /* Add node to back propagation list. */
674         node_bucket_insert(&reduced_bucket, node);
675
676         if (edge == NULL) {
677                 edge = alloc_edge(pbqp, src_node->index, tgt_node->index, mat);
678         } else {
679                 pbqp_matrix_add(edge->costs, mat);
680
681                 /* Free local matrix. */
682                 obstack_free(&pbqp->obstack, mat);
683
684                 reorder_node(src_node);
685                 reorder_node(tgt_node);
686         }
687
688         if (pbqp->dump_file) {
689                 fputs("<br>\nAfter reduction:<br>\n", pbqp->dump_file);
690                 dump_edge(pbqp, edge);
691         }
692
693         /* Edge has changed so we simplify it. */
694         simplify_edge(pbqp, edge);
695 }
696
697 void apply_RN(pbqp *pbqp)
698 {
699         pbqp_node  **bucket       = node_buckets[3];
700         unsigned     bucket_len   = node_bucket_get_length(bucket);
701         unsigned     bucket_index;
702         pbqp_node   *node         = NULL;
703         pbqp_edge   *edge;
704         vector      *node_vec;
705         vector      *vec;
706         pbqp_matrix *mat;
707         unsigned     edge_index;
708         unsigned     max_degree   = 0;
709         unsigned     node_index;
710         unsigned     node_len;
711         unsigned     min_index    = 0;
712         num          min          = INF_COSTS;
713         int          is_src;
714
715         assert(pbqp);
716
717         /* Search for node with maximum degree. */
718         for (bucket_index = 0; bucket_index < bucket_len; ++bucket_index) {
719                 pbqp_node *candidate = bucket[bucket_index];
720                 unsigned   degree    = ARR_LEN(candidate->edges);
721
722                 if (degree > max_degree) {
723                         node = candidate;
724                         max_degree = degree;
725                 }
726         }
727         assert(node);
728         node_vec = node->costs;
729         node_len = node_vec->len;
730
731         if (pbqp->dump_file) {
732                 char     txt[100];
733                 sprintf(txt, "RN-Reduction of Node n%d", node->index);
734                 dump_section(pbqp->dump_file, 2, txt);
735                 pbqp_dump_graph(pbqp);
736         }
737
738         for (node_index = 0; node_index < node_len; ++node_index) {
739                 num value = node_vec->entries[node_index].data;
740
741                 for (edge_index = 0; edge_index < max_degree; ++edge_index) {
742                         edge   = node->edges[edge_index];
743                         mat    = edge->costs;
744                         is_src = edge->src == node;
745
746                         if (is_src) {
747                                 vec = vector_copy(pbqp, edge->tgt->costs);
748                                 vector_add_matrix_row(vec, mat, node_index);
749                         } else {
750                                 vec = vector_copy(pbqp, edge->src->costs);
751                                 vector_add_matrix_col(vec, mat, node_index);
752                         }
753
754                         value = pbqp_add(value, vector_get_min(vec));
755
756                         obstack_free(&pbqp->obstack, vec);
757                 }
758
759                 if (value < min) {
760                         min = value;
761                         min_index = node_index;
762                 }
763         }
764
765         if (pbqp->dump_file) {
766                 fprintf(pbqp->dump_file, "node n%d is set to %d<br><br>\n",
767                                         node->index, min_index);
768                 fprintf(pbqp->dump_file, "Minimal cost of RN reduction: %lld<br>\n",
769                                                         min);
770         }
771
772         node->solution = min_index;
773
774         /* Now that we found the local minimum set all other costs to infinity. */
775         for (node_index = 0; node_index < node_len; ++node_index) {
776                 if (node_index != min_index) {
777                         node_vec->entries[node_index].data = INF_COSTS;
778                 }
779         }
780
781         /* Add all incident edges to edge bucket, since they are now independent. */
782         for (edge_index = 0; edge_index < max_degree; ++edge_index) {
783                 insert_into_edge_bucket(node->edges[edge_index]);
784         }
785 }
786
787 void back_propagate_RI(pbqp *pbqp, pbqp_node *node)
788 {
789         pbqp_edge   *edge;
790         pbqp_node   *other;
791         pbqp_matrix *mat;
792         vector      *vec;
793         int          is_src;
794
795         assert(pbqp);
796         assert(node);
797
798         edge = node->edges[0];
799         mat = edge->costs;
800         is_src = edge->src == node;
801         vec = node->costs;
802
803         if (is_src) {
804                 other = edge->tgt;
805                 assert(other);
806                 vector_add_matrix_col(vec, mat, other->solution);
807         } else {
808                 other = edge->src;
809                 assert(other);
810                 vector_add_matrix_row(vec, mat, other->solution);
811         }
812
813         node->solution = vector_get_min_index(vec);
814         if (pbqp->dump_file) {
815                 fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
816         }
817 }
818
819 void back_propagate_RII(pbqp *pbqp, pbqp_node *node)
820 {
821         pbqp_edge   *src_edge   = node->edges[0];
822         pbqp_edge   *tgt_edge   = node->edges[1];
823         int          src_is_src = src_edge->src == node;
824         int          tgt_is_src = tgt_edge->src == node;
825         pbqp_matrix *src_mat;
826         pbqp_matrix *tgt_mat;
827         pbqp_node   *src_node;
828         pbqp_node   *tgt_node;
829         vector      *vec;
830         vector      *node_vec;
831         unsigned     col_index;
832         unsigned     row_index;
833
834         assert(pbqp);
835
836         if (src_is_src) {
837                 src_node = src_edge->tgt;
838         } else {
839                 src_node = src_edge->src;
840         }
841
842         if (tgt_is_src) {
843                 tgt_node = tgt_edge->tgt;
844         } else {
845                 tgt_node = tgt_edge->src;
846         }
847
848         /* Swap nodes if necessary. */
849         if (tgt_node->index < src_node->index) {
850                 pbqp_node *tmp_node;
851                 pbqp_edge *tmp_edge;
852
853                 tmp_node = src_node;
854                 src_node = tgt_node;
855                 tgt_node = tmp_node;
856
857                 tmp_edge = src_edge;
858                 src_edge = tgt_edge;
859                 tgt_edge = tmp_edge;
860
861                 src_is_src = src_edge->src == node;
862                 tgt_is_src = tgt_edge->src == node;
863         }
864
865         src_mat = src_edge->costs;
866         tgt_mat = tgt_edge->costs;
867
868         node_vec = node->costs;
869
870         row_index = src_node->solution;
871         col_index = tgt_node->solution;
872
873         vec = vector_copy(pbqp, node_vec);
874
875         if (src_is_src) {
876                 vector_add_matrix_col(vec, src_mat, row_index);
877         } else {
878                 vector_add_matrix_row(vec, src_mat, row_index);
879         }
880
881         if (tgt_is_src) {
882                 vector_add_matrix_col(vec, tgt_mat, col_index);
883         } else {
884                 vector_add_matrix_row(vec, tgt_mat, col_index);
885         }
886
887         node->solution = vector_get_min_index(vec);
888         if (pbqp->dump_file) {
889                 fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
890         }
891
892         obstack_free(&pbqp->obstack, vec);
893 }
894
895 int node_is_reduced(pbqp_node *node)
896 {
897         if (!reduced_bucket) return 0;
898
899         assert(node);
900         if (ARR_LEN(node->edges) == 0) return 1;
901
902         return node_bucket_contains(reduced_bucket, node);
903 }