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