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