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