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         unsigned bucket_len = edge_bucket_get_length(edge_bucket);
24
25         if (edge->bucket_index < bucket_len && edge_bucket[edge->bucket_index]
26                         == edge)
27                 /* Edge is already inserted. */
28                 return;
29
30         edge->bucket_index = bucket_len;
31         ARR_APP1(pbqp_edge *, edge_bucket, edge);
32 }
33
34 static void init_buckets(void)
35 {
36         int i;
37
38         edge_bucket = NEW_ARR_F(pbqp_edge *, 0);
39         reduced_bucket = NEW_ARR_F(pbqp_node *, 0);
40
41         for (i = 0; i < 4; ++i) {
42                 node_buckets[i] = NEW_ARR_F(pbqp_node *, 0);
43         }
44 }
45
46 static void free_buckets(void)
47 {
48         int i;
49
50         for (i = 0; i < 4; ++i) {
51                 DEL_ARR_F(node_buckets[i]);
52                 node_buckets[i] = NULL;
53         }
54
55         DEL_ARR_F(edge_bucket);
56         edge_bucket = NULL;
57
58         DEL_ARR_F(reduced_bucket);
59         reduced_bucket = NULL;
60
61         buckets_filled = 0;
62 }
63
64 static void fill_node_buckets(pbqp *pbqp)
65 {
66         unsigned node_index;
67         unsigned node_len;
68
69         assert(pbqp);
70         node_len = pbqp->num_nodes;
71
72         for (node_index = 0; node_index < node_len; ++node_index) {
73                 unsigned   arity;
74                 pbqp_node *node = get_node(pbqp, node_index);
75
76                 if (!node) continue;
77
78                 arity = ARR_LEN(node->edges);
79
80                 /* We have only one bucket for nodes with arity >= 3. */
81                 if (arity > 3) {
82                         arity = 3;
83                 }
84
85                 node->bucket_index = node_bucket_get_length(node_buckets[arity]);
86
87                 ARR_APP1(pbqp_node *, node_buckets[arity], node);
88         }
89
90         buckets_filled = 1;
91 }
92
93 static void normalize_towards_source(pbqp *pbqp, pbqp_edge *edge)
94 {
95         pbqp_matrix    *mat;
96         pbqp_node      *src_node;
97         pbqp_node      *tgt_node;
98         vector         *src_vec;
99         vector         *tgt_vec;
100         int             src_len;
101         int             tgt_len;
102         int             src_index;
103
104         assert(pbqp);
105         assert(edge);
106
107         src_node = edge->src;
108         tgt_node = edge->tgt;
109         assert(src_node);
110         assert(tgt_node);
111
112         src_vec = src_node->costs;
113         tgt_vec = tgt_node->costs;
114         assert(src_vec);
115         assert(tgt_vec);
116
117         src_len = src_vec->len;
118         tgt_len = tgt_vec->len;
119         assert(src_len > 0);
120         assert(tgt_len > 0);
121
122         mat = edge->costs;
123         assert(mat);
124
125         /* Normalize towards source node. */
126         for (src_index = 0; src_index < src_len; ++src_index) {
127                 num min = pbqp_matrix_get_row_min(mat, src_index, tgt_vec);
128
129                 if (min != 0) {
130                         if (src_vec->entries[src_index].data == INF_COSTS) {
131                                 pbqp_matrix_set_row_value(mat, src_index, 0);
132                         } else {
133                                 pbqp_matrix_sub_row_value(mat, src_index, tgt_vec, min);
134                         }
135                         src_vec->entries[src_index].data = pbqp_add(
136                                         src_vec->entries[src_index].data, min);
137
138                         if (min == INF_COSTS) {
139                                 unsigned edge_index;
140                                 unsigned edge_len = ARR_LEN(src_node->edges);
141
142                                 for (edge_index = 0; edge_index < edge_len; ++edge_index) {
143                                         pbqp_edge *edge_candidate = src_node->edges[edge_index];
144                                         if (edge_candidate != edge) {
145                                                 insert_into_edge_bucket(edge_candidate);
146                                         }
147                                 }
148                         }
149                 }
150         }
151 }
152
153 static void normalize_towards_target(pbqp *pbqp, pbqp_edge *edge)
154 {
155         pbqp_matrix    *mat;
156         pbqp_node      *src_node;
157         pbqp_node      *tgt_node;
158         vector         *src_vec;
159         vector         *tgt_vec;
160         int             src_len;
161         int             tgt_len;
162         int             tgt_index;
163
164         assert(pbqp);
165         assert(edge);
166
167         src_node = edge->src;
168         tgt_node = edge->tgt;
169         assert(src_node);
170         assert(tgt_node);
171
172         src_vec = src_node->costs;
173         tgt_vec = tgt_node->costs;
174         assert(src_vec);
175         assert(tgt_vec);
176
177         src_len = src_vec->len;
178         tgt_len = tgt_vec->len;
179         assert(src_len > 0);
180         assert(tgt_len > 0);
181
182         mat = edge->costs;
183         assert(mat);
184
185         for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
186                 num min = pbqp_matrix_get_col_min(mat, tgt_index, src_vec);
187
188                 if (min != 0) {
189                         if (tgt_vec->entries[tgt_index].data == INF_COSTS) {
190                                 pbqp_matrix_set_col_value(mat, tgt_index, 0);
191                         } else {
192                                 pbqp_matrix_sub_col_value(mat, tgt_index, src_vec, min);
193                         }
194                         tgt_vec->entries[tgt_index].data = pbqp_add(
195                                         tgt_vec->entries[tgt_index].data, min);
196
197                         if (min == INF_COSTS) {
198                                 unsigned edge_index;
199                                 unsigned edge_len = ARR_LEN(tgt_node->edges);
200
201                                 for (edge_index = 0; edge_index < edge_len; ++edge_index) {
202                                         pbqp_edge *edge_candidate = tgt_node->edges[edge_index];
203                                         if (edge_candidate != edge) {
204                                                 insert_into_edge_bucket(edge_candidate);
205                                         }
206                                 }
207                         }
208                 }
209         }
210 }
211
212 static void reorder_node(pbqp_node *node)
213 {
214         unsigned    arity;
215         unsigned    old_arity;
216         unsigned    old_bucket_len;
217         unsigned    old_bucket_index;
218         pbqp_node **old_bucket;
219         pbqp_node  *other;
220
221         if (!buckets_filled) return;
222
223         assert(node);
224
225         arity = ARR_LEN(node->edges);
226
227         /* Same bucket as before */
228         if (arity > 2) return;
229
230         /* Assume node lost one incident edge. */
231         old_arity        = arity + 1;
232         old_bucket       = node_buckets[old_arity];
233         old_bucket_len   = node_bucket_get_length(old_bucket);
234         old_bucket_index = node->bucket_index;
235
236         if (old_bucket_len <= old_bucket_index || old_bucket[old_bucket_index]
237                         != node) {
238                 unsigned bucket_len = node_bucket_get_length(node_buckets[arity]);
239
240                 /* Old arity is new arity, so we have nothing to do. */
241                 assert(old_bucket_index < bucket_len);
242                 assert(node_buckets[arity][old_bucket_index] == node);
243                 return;
244         }
245
246         assert(old_bucket[old_bucket_index] == node);
247
248         /* Delete node from old bucket... */
249         other                        = old_bucket[old_bucket_len - 1];
250         other->bucket_index          = old_bucket_index;
251         old_bucket[old_bucket_index] = other;
252         ARR_SHRINKLEN(node_buckets[old_arity], old_bucket_len - 1);
253
254         /* ..and add to new one. */
255         node->bucket_index = node_bucket_get_length(node_buckets[arity]);
256         ARR_APP1(pbqp_node*, node_buckets[arity], node);
257 }
258
259 static void simplify_edge(pbqp *pbqp, pbqp_edge *edge)
260 {
261         pbqp_matrix    *mat;
262         pbqp_node      *src_node;
263         pbqp_node      *tgt_node;
264         vector         *src_vec;
265         vector         *tgt_vec;
266         int             src_len;
267         int             tgt_len;
268
269         assert(pbqp);
270         assert(edge);
271
272         src_node = edge->src;
273         tgt_node = edge->tgt;
274         assert(src_node);
275         assert(tgt_node);
276
277         /* If edge are already deleted, we have nothing to do. */
278         if (!is_connected(src_node, edge) || !is_connected(tgt_node, edge))
279                 return;
280
281         if (pbqp->dump_file) {
282                 char txt[100];
283                 sprintf(txt, "Simplification of Edge n%d-n%d", src_node->index, tgt_node->index);
284                 dump_section(pbqp->dump_file, 3, txt);
285         }
286
287         src_vec = src_node->costs;
288         tgt_vec = tgt_node->costs;
289         assert(src_vec);
290         assert(tgt_vec);
291
292         src_len = src_vec->len;
293         tgt_len = tgt_vec->len;
294         assert(src_len > 0);
295         assert(tgt_len > 0);
296
297         mat = edge->costs;
298         assert(mat);
299
300         if (pbqp->dump_file) {
301                 fputs("Input:<br>\n", pbqp->dump_file);
302                 dump_simplifyedge(pbqp, edge);
303         }
304
305         normalize_towards_source(pbqp, edge);
306         normalize_towards_target(pbqp, edge);
307
308         if (pbqp->dump_file) {
309                 fputs("<br>\nOutput:<br>\n", pbqp->dump_file);
310                 dump_simplifyedge(pbqp, edge);
311         }
312
313         if (pbqp_matrix_is_zero(mat, src_vec, tgt_vec)) {
314                 if (pbqp->dump_file) {
315                         fputs("edge has been eliminated<br>\n", pbqp->dump_file);
316                 }
317
318                 delete_edge(edge);
319                 reorder_node(src_node);
320                 reorder_node(tgt_node);
321         }
322 }
323
324 void solve_pbqp_heuristical(pbqp *pbqp)
325 {
326         unsigned node_index;
327         unsigned node_len;
328
329         assert(pbqp);
330
331         if (pbqp->dump_file) {
332                 pbqp_dump_input(pbqp);
333                 dump_section(pbqp->dump_file, 1, "2. Simplification of Cost Matrices");
334         }
335
336         node_len = pbqp->num_nodes;
337
338         init_buckets();
339
340         /* First simplify all edges. */
341         for (node_index = 0; node_index < node_len; ++node_index) {
342                 unsigned    edge_index;
343                 pbqp_node  *node = get_node(pbqp, node_index);
344                 pbqp_edge **edges;
345                 unsigned    edge_len;
346
347                 if (!node) continue;
348
349                 edges = node->edges;
350                 edge_len = ARR_LEN(edges);
351
352                 for (edge_index = 0; edge_index < edge_len; ++edge_index) {
353                         pbqp_edge *edge = edges[edge_index];
354
355                         /* Simplify only once per edge. */
356                         if (node != edge->src) continue;
357
358                         simplify_edge(pbqp, edge);
359                 }
360         }
361
362         /* Put node into bucket representing their arity. */
363         fill_node_buckets(pbqp);
364
365         for (;;) {
366                 if (edge_bucket_get_length(edge_bucket) > 0) {
367                         apply_edge(pbqp);
368                 } else if (node_bucket_get_length(node_buckets[1]) > 0) {
369                         apply_RI(pbqp);
370                 } else if (node_bucket_get_length(node_buckets[2]) > 0) {
371                         apply_RII(pbqp);
372                 } else if (node_bucket_get_length(node_buckets[3]) > 0) {
373                         apply_RN(pbqp);
374                 } else {
375                         break;
376                 }
377         }
378
379         if (pbqp->dump_file) {
380                 dump_section(pbqp->dump_file, 1, "4. Determine Solution/Minimum");
381                 dump_section(pbqp->dump_file, 2, "4.1. Trivial Solution");
382         }
383
384         /* Solve trivial nodes and calculate solution. */
385         node_len = node_bucket_get_length(node_buckets[0]);
386         for (node_index = 0; node_index < node_len; ++node_index) {
387                 pbqp_node *node = node_buckets[0][node_index];
388                 assert(node);
389
390                 node->solution = vector_get_min_index(node->costs);
391                 pbqp->solution = pbqp_add(pbqp->solution,
392                                 node->costs->entries[node->solution].data);
393                 if (pbqp->dump_file) {
394                         fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
395                         dump_node(pbqp, node);
396                 }
397         }
398
399         if (pbqp->dump_file) {
400                 dump_section(pbqp->dump_file, 2, "Minimum");
401                 fprintf(pbqp->dump_file, "Minimum is equal to %lld.", pbqp->solution);
402                 dump_section(pbqp->dump_file, 2, "Back Propagation");
403         }
404
405         /* Solve reduced nodes. */
406         node_len = node_bucket_get_length(reduced_bucket);
407         for (node_index = node_len; node_index > 0; --node_index) {
408                 pbqp_node *node = reduced_bucket[node_index - 1];
409                 assert(node);
410
411                 switch (ARR_LEN(node->edges)) {
412                         case 1:
413                                 back_propagate_RI(pbqp, node);
414                                 break;
415                         case 2:
416                                 back_propagate_RII(pbqp, node);
417                                 break;
418                         default:
419                                 panic("Only nodes with degree one or two should be in this bucket");
420                                 break;
421                 }
422         }
423
424         free_buckets();
425 }
426
427 void apply_edge(pbqp *pbqp)
428 {
429         unsigned   bucket_len = edge_bucket_get_length(edge_bucket);
430         pbqp_edge *edge       = edge_bucket[bucket_len - 1];
431
432         ARR_SHRINKLEN(edge_bucket, (int)bucket_len - 1);
433
434         simplify_edge(pbqp, edge);
435 }
436
437 void apply_RI(pbqp *pbqp)
438 {
439         pbqp_node  **bucket     = node_buckets[1];
440         unsigned     bucket_len = node_bucket_get_length(bucket);
441         pbqp_node   *node       = bucket[bucket_len - 1];
442         pbqp_edge   *edge       = node->edges[0];
443         pbqp_matrix *mat        = edge->costs;
444         int          is_src     = edge->src == node;
445         pbqp_node   *other_node;
446
447         if (is_src) {
448                 other_node = edge->tgt;
449         } else {
450                 other_node = edge->src;
451         }
452
453         if (pbqp->dump_file) {
454                 char     txt[100];
455                 sprintf(txt, "RI-Reduction of Node n%d", node->index);
456                 dump_section(pbqp->dump_file, 2, txt);
457                 pbqp_dump_graph(pbqp);
458                 fputs("<br>\nBefore reduction:<br>\n", pbqp->dump_file);
459                 dump_node(pbqp, node);
460                 dump_node(pbqp, other_node);
461                 dump_edge(pbqp, edge);
462         }
463
464         if (is_src) {
465                 pbqp_matrix_add_to_all_cols(mat, node->costs);
466                 normalize_towards_target(pbqp, edge);
467         } else {
468                 pbqp_matrix_add_to_all_rows(mat, node->costs);
469                 normalize_towards_source(pbqp, edge);
470         }
471         disconnect_edge(other_node, edge);
472
473         if (pbqp->dump_file) {
474                 fputs("<br>\nAfter reduction:<br>\n", pbqp->dump_file);
475                 dump_node(pbqp, other_node);
476         }
477
478         /* Remove node from bucket... */
479         ARR_SHRINKLEN(bucket, (int)bucket_len - 1);
480         reorder_node(other_node);
481
482         /* ...and add it to back propagation list. */
483         node->bucket_index = node_bucket_get_length(reduced_bucket);
484         ARR_APP1(pbqp_node *, reduced_bucket, node);
485 }
486
487 void apply_RII(pbqp *pbqp)
488 {
489         pbqp_node  **bucket     = node_buckets[2];
490         unsigned     bucket_len = node_bucket_get_length(bucket);
491         pbqp_node   *node       = bucket[bucket_len - 1];
492         pbqp_edge   *src_edge   = node->edges[0];
493         pbqp_edge   *tgt_edge   = node->edges[1];
494         int          src_is_src = src_edge->src == node;
495         int          tgt_is_src = tgt_edge->src == node;
496         pbqp_matrix *src_mat;
497         pbqp_matrix *tgt_mat;
498         pbqp_node   *src_node;
499         pbqp_node   *tgt_node;
500         pbqp_matrix *mat;
501         vector      *vec;
502         vector      *node_vec;
503         vector      *src_vec;
504         vector      *tgt_vec;
505         unsigned     col_index;
506         unsigned     col_len;
507         unsigned     row_index;
508         unsigned     row_len;
509         unsigned     node_len;
510
511         assert(pbqp);
512
513         if (src_is_src) {
514                 src_node = src_edge->tgt;
515         } else {
516                 src_node = src_edge->src;
517         }
518
519         if (tgt_is_src) {
520                 tgt_node = tgt_edge->tgt;
521         } else {
522                 tgt_node = tgt_edge->src;
523         }
524
525         /* Swap nodes if necessary. */
526         if (tgt_node->index < src_node->index) {
527                 pbqp_node *tmp_node;
528                 pbqp_edge *tmp_edge;
529
530                 tmp_node = src_node;
531                 src_node = tgt_node;
532                 tgt_node = tmp_node;
533
534                 tmp_edge = src_edge;
535                 src_edge = tgt_edge;
536                 tgt_edge = tmp_edge;
537
538                 src_is_src = src_edge->src == node;
539                 tgt_is_src = tgt_edge->src == node;
540         }
541
542         if (pbqp->dump_file) {
543                 char     txt[100];
544                 sprintf(txt, "RII-Reduction of Node n%d", node->index);
545                 dump_section(pbqp->dump_file, 2, txt);
546                 pbqp_dump_graph(pbqp);
547                 fputs("<br>\nBefore reduction:<br>\n", pbqp->dump_file);
548                 dump_node(pbqp, src_node);
549                 dump_edge(pbqp, src_edge);
550                 dump_node(pbqp, node);
551                 dump_edge(pbqp, tgt_edge);
552                 dump_node(pbqp, tgt_node);
553         }
554
555         src_mat = src_edge->costs;
556         tgt_mat = tgt_edge->costs;
557
558         src_vec  = src_node->costs;
559         tgt_vec  = tgt_node->costs;
560         node_vec = node->costs;
561
562         row_len  = src_vec->len;
563         col_len  = tgt_vec->len;
564         node_len = node_vec->len;
565
566         mat = pbqp_matrix_alloc(pbqp, row_len, col_len);
567
568         for (row_index = 0; row_index < row_len; ++row_index) {
569                 for (col_index = 0; col_index < col_len; ++col_index) {
570                         vec = vector_copy(pbqp, node_vec);
571
572                         if (src_is_src) {
573                                 vector_add_matrix_col(vec, src_mat, row_index);
574                         } else {
575                                 vector_add_matrix_row(vec, src_mat, row_index);
576                         }
577
578                         if (tgt_is_src) {
579                                 vector_add_matrix_col(vec, tgt_mat, col_index);
580                         } else {
581                                 vector_add_matrix_row(vec, tgt_mat, col_index);
582                         }
583
584                         mat->entries[row_index * col_len + col_index] = vector_get_min(vec);
585
586                         obstack_free(&pbqp->obstack, vec);
587                 }
588         }
589
590         pbqp_edge *edge = get_edge(pbqp, src_node->index, tgt_node->index);
591
592         /* Disconnect node. */
593         disconnect_edge(src_node, src_edge);
594         disconnect_edge(tgt_node, tgt_edge);
595
596         /* Remove node from bucket... */
597         ARR_SHRINKLEN(bucket, (int)bucket_len - 1);
598
599         /* ...and add it to back propagation list. */
600         node->bucket_index = node_bucket_get_length(reduced_bucket);
601         ARR_APP1(pbqp_node *, reduced_bucket, node);
602
603         if (edge == NULL) {
604                 edge = alloc_edge(pbqp, src_node->index, tgt_node->index, mat);
605         } else {
606                 pbqp_matrix_add(edge->costs, mat);
607
608                 /* Free local matrix. */
609                 obstack_free(&pbqp->obstack, mat);
610
611                 reorder_node(src_node);
612                 reorder_node(tgt_node);
613         }
614
615         if (pbqp->dump_file) {
616                 fputs("<br>\nAfter reduction:<br>\n", pbqp->dump_file);
617                 dump_edge(pbqp, edge);
618         }
619
620         /* Edge has changed so we simplify it. */
621         simplify_edge(pbqp, edge);
622 }
623
624 void apply_RN(pbqp *pbqp)
625 {
626         pbqp_node  **bucket       = node_buckets[3];
627         unsigned     bucket_len   = node_bucket_get_length(bucket);
628         unsigned     bucket_index;
629         pbqp_node   *node         = NULL;
630         pbqp_edge   *edge;
631         vector      *node_vec;
632         vector      *vec;
633         pbqp_matrix *mat;
634         unsigned     edge_index;
635         unsigned     max_degree   = 0;
636         unsigned     node_index;
637         unsigned     node_len;
638         unsigned     min_index    = 0;
639         num          min          = INF_COSTS;
640         int          is_src;
641
642         assert(pbqp);
643
644         /* Search for node with maximum degree. */
645         for (bucket_index = 0; bucket_index < bucket_len; ++bucket_index) {
646                 pbqp_node *candidate = bucket[bucket_index];
647                 unsigned   degree    = ARR_LEN(candidate->edges);
648
649                 if (degree > max_degree) {
650                         node = candidate;
651                         max_degree = degree;
652                 }
653         }
654         assert(node);
655         node_vec = node->costs;
656         node_len = node_vec->len;
657
658         if (pbqp->dump_file) {
659                 char     txt[100];
660                 sprintf(txt, "RN-Reduction of Node n%d", node->index);
661                 dump_section(pbqp->dump_file, 2, txt);
662                 pbqp_dump_graph(pbqp);
663         }
664
665         for (node_index = 0; node_index < node_len; ++node_index) {
666                 num value = node_vec->entries[node_index].data;
667
668                 for (edge_index = 0; edge_index < max_degree; ++edge_index) {
669                         edge   = node->edges[edge_index];
670                         mat    = edge->costs;
671                         is_src = edge->src == node;
672
673                         if (is_src) {
674                                 vec = vector_copy(pbqp, edge->tgt->costs);
675                                 vector_add_matrix_row(vec, mat, node_index);
676                         } else {
677                                 vec = vector_copy(pbqp, edge->src->costs);
678                                 vector_add_matrix_col(vec, mat, node_index);
679                         }
680
681                         value = pbqp_add(value, vector_get_min(vec));
682
683                         obstack_free(&pbqp->obstack, vec);
684                 }
685
686                 if (value < min) {
687                         min = value;
688                         min_index = node_index;
689                 }
690         }
691
692         if (pbqp->dump_file) {
693                 fprintf(pbqp->dump_file, "node n%d is set to %d<br><br>\n",
694                                         node->index, min_index);
695                 fprintf(pbqp->dump_file, "Minimal cost of RN reduction: %lld<br>\n",
696                                                         min);
697         }
698
699         node->solution = min_index;
700
701         /* Now that we found the local minimum set all other costs to infinity. */
702         for (node_index = 0; node_index < node_len; ++node_index) {
703                 if (node_index != min_index) {
704                         node_vec->entries[node_index].data = INF_COSTS;
705                 }
706         }
707
708         /* Add all incident edges to edge bucket, since they are now independent. */
709         for (edge_index = 0; edge_index < max_degree; ++edge_index) {
710                 insert_into_edge_bucket(node->edges[edge_index]);
711         }
712 }
713
714 void back_propagate_RI(pbqp *pbqp, pbqp_node *node)
715 {
716         pbqp_edge   *edge;
717         pbqp_node   *other;
718         pbqp_matrix *mat;
719         vector      *vec;
720         int          is_src;
721
722         assert(pbqp);
723         assert(node);
724
725         edge = node->edges[0];
726         mat = edge->costs;
727         is_src = edge->src == node;
728         vec = node->costs;
729
730         if (is_src) {
731                 other = edge->tgt;
732                 assert(other);
733                 vector_add_matrix_col(vec, mat, other->solution);
734         } else {
735                 other = edge->src;
736                 assert(other);
737                 vector_add_matrix_row(vec, mat, other->solution);
738         }
739
740         node->solution = vector_get_min_index(vec);
741         if (pbqp->dump_file) {
742                 fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
743         }
744 }
745
746 void back_propagate_RII(pbqp *pbqp, pbqp_node *node)
747 {
748         pbqp_edge   *src_edge   = node->edges[0];
749         pbqp_edge   *tgt_edge   = node->edges[1];
750         int          src_is_src = src_edge->src == node;
751         int          tgt_is_src = tgt_edge->src == node;
752         pbqp_matrix *src_mat;
753         pbqp_matrix *tgt_mat;
754         pbqp_node   *src_node;
755         pbqp_node   *tgt_node;
756         vector      *vec;
757         vector      *node_vec;
758         unsigned     col_index;
759         unsigned     row_index;
760
761         assert(pbqp);
762
763         if (src_is_src) {
764                 src_node = src_edge->tgt;
765         } else {
766                 src_node = src_edge->src;
767         }
768
769         if (tgt_is_src) {
770                 tgt_node = tgt_edge->tgt;
771         } else {
772                 tgt_node = tgt_edge->src;
773         }
774
775         /* Swap nodes if necessary. */
776         if (tgt_node->index < src_node->index) {
777                 pbqp_node *tmp_node;
778                 pbqp_edge *tmp_edge;
779
780                 tmp_node = src_node;
781                 src_node = tgt_node;
782                 tgt_node = tmp_node;
783
784                 tmp_edge = src_edge;
785                 src_edge = tgt_edge;
786                 tgt_edge = tmp_edge;
787
788                 src_is_src = src_edge->src == node;
789                 tgt_is_src = tgt_edge->src == node;
790         }
791
792         src_mat = src_edge->costs;
793         tgt_mat = tgt_edge->costs;
794
795         node_vec = node->costs;
796
797         row_index = src_node->solution;
798         col_index = tgt_node->solution;
799
800         vec = vector_copy(pbqp, node_vec);
801
802         if (src_is_src) {
803                 vector_add_matrix_col(vec, src_mat, row_index);
804         } else {
805                 vector_add_matrix_row(vec, src_mat, row_index);
806         }
807
808         if (tgt_is_src) {
809                 vector_add_matrix_col(vec, tgt_mat, col_index);
810         } else {
811                 vector_add_matrix_row(vec, tgt_mat, col_index);
812         }
813
814         node->solution = vector_get_min_index(vec);
815         if (pbqp->dump_file) {
816                 fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
817         }
818
819         obstack_free(&pbqp->obstack, vec);
820 }
821
822 int node_is_reduced(pbqp_node *node)
823 {
824         if (!reduced_bucket) return 0;
825
826         assert(node);
827         if (ARR_LEN(node->edges) == 0) return 1;
828
829         unsigned bucket_length = node_bucket_get_length(reduced_bucket);
830         unsigned bucket_index  = node->bucket_index;
831
832         return bucket_index < bucket_length && reduced_bucket[bucket_index] == node;
833 }