7605ffb580acf47e627893f143695cb7afb549c2
[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 num add(num x, num y)
21 {
22         if (x == INF_COSTS || y == INF_COSTS) return INF_COSTS;
23
24         return x + y;
25 }
26
27 static void init_buckets(void)
28 {
29         int i;
30
31         edge_bucket = NEW_ARR_F(pbqp_edge *, 0);
32         reduced_bucket = NEW_ARR_F(pbqp_node *, 0);
33
34         for (i = 0; i < 4; ++i) {
35                 node_buckets[i] = NEW_ARR_F(pbqp_node *, 0);
36         }
37 }
38
39 static void fill_node_buckets(pbqp *pbqp)
40 {
41         unsigned node_index;
42         unsigned node_len;
43
44         assert(pbqp);
45         node_len = pbqp->num_nodes;
46
47         for (node_index = 0; node_index < node_len; ++node_index) {
48                 unsigned   arity;
49                 pbqp_node *node = get_node(pbqp, node_index);
50
51                 if (!node) continue;
52
53                 arity = ARR_LEN(node->edges);
54
55                 /* We have only one bucket for nodes with arity >= 3. */
56                 if (arity > 3) {
57                         arity = 3;
58                 }
59
60                 node->bucket_index = ARR_LEN(node_buckets[arity]);
61
62                 ARR_APP1(pbqp_node *, node_buckets[arity], node);
63         }
64
65         buckets_filled = 1;
66 }
67
68 static void normalize_towards_source(pbqp *pbqp, pbqp_edge *edge)
69 {
70         pbqp_matrix    *mat;
71         pbqp_node      *src_node;
72         pbqp_node      *tgt_node;
73         vector         *src_vec;
74         vector         *tgt_vec;
75         int             src_len;
76         int             tgt_len;
77         int             src_index;
78
79         assert(pbqp);
80         assert(edge);
81
82         src_node = edge->src;
83         tgt_node = edge->tgt;
84         assert(src_node);
85         assert(tgt_node);
86
87         src_vec = src_node->costs;
88         tgt_vec = tgt_node->costs;
89         assert(src_vec);
90         assert(tgt_vec);
91
92         src_len = src_vec->len;
93         tgt_len = tgt_vec->len;
94         assert(src_len > 0);
95         assert(tgt_len > 0);
96
97         mat = edge->costs;
98         assert(mat);
99
100         /* Normalize towards source node. */
101         for (src_index = 0; src_index < src_len; ++src_index) {
102                 num min = pbqp_matrix_get_row_min(mat, src_index, tgt_vec);
103
104                 if (min != 0) {
105                         pbqp_matrix_sub_row_value(mat, src_index, tgt_vec, min);
106                         src_vec->entries[src_index].data = add(
107                                         src_vec->entries[src_index].data, min);
108
109                         // TODO add to edge_list if inf
110                 }
111         }
112 }
113
114 static void normalize_towards_target(pbqp *pbqp, pbqp_edge *edge)
115 {
116         pbqp_matrix    *mat;
117         pbqp_node      *src_node;
118         pbqp_node      *tgt_node;
119         vector         *src_vec;
120         vector         *tgt_vec;
121         int             src_len;
122         int             tgt_len;
123         int             tgt_index;
124
125         assert(pbqp);
126         assert(edge);
127
128         src_node = edge->src;
129         tgt_node = edge->tgt;
130         assert(src_node);
131         assert(tgt_node);
132
133         src_vec = src_node->costs;
134         tgt_vec = tgt_node->costs;
135         assert(src_vec);
136         assert(tgt_vec);
137
138         src_len = src_vec->len;
139         tgt_len = tgt_vec->len;
140         assert(src_len > 0);
141         assert(tgt_len > 0);
142
143         mat = edge->costs;
144         assert(mat);
145
146         for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
147                 num min = pbqp_matrix_get_col_min(mat, tgt_index, src_vec);
148
149                 if (min != 0) {
150                         pbqp_matrix_sub_col_value(mat, tgt_index, src_vec, min);
151                         tgt_vec->entries[tgt_index].data = add(
152                                         tgt_vec->entries[tgt_index].data, min);
153
154                         // TODO add to edge_list if inf
155                 }
156         }
157 }
158
159 static void reorder_node(pbqp_node *node)
160 {
161         unsigned arity;
162         unsigned old_arity;
163         unsigned old_bucket_len;
164
165         if (!buckets_filled) return;
166
167         assert(node);
168
169         arity = ARR_LEN(node->edges);
170
171         /* Equal bucket as before */
172         if (arity > 2) return;
173
174         /* Assume node lost one incident edge. */
175         old_arity = arity + 1;
176
177         if (ARR_LEN(node_buckets[old_arity]) <= (int)node->bucket_index
178                         || node_buckets[old_arity][node->bucket_index] != node) {
179                 /* Old arity is new arity, so we have nothing to do. */
180                 return;
181         }
182
183         old_bucket_len = ARR_LEN(node_buckets[old_arity]);
184         assert (node_buckets[old_arity][node->bucket_index] == node);
185
186         /* Delete node from old bucket... */
187         node_buckets[old_arity][old_bucket_len - 1]->bucket_index
188                         = node->bucket_index;
189         node_buckets[old_arity][node->bucket_index]
190                         = node_buckets[old_arity][old_bucket_len - 1];
191         ARR_SHRINKLEN(node_buckets[old_arity], (int)old_bucket_len - 1);
192
193         /* ..and add to new one. */
194         node->bucket_index = ARR_LEN(node_buckets[arity]);
195         ARR_APP1(pbqp_node *, node_buckets[arity], node);
196 }
197
198 static void simplify_edge(pbqp *pbqp, pbqp_edge *edge)
199 {
200         pbqp_matrix    *mat;
201         pbqp_node      *src_node;
202         pbqp_node      *tgt_node;
203         vector         *src_vec;
204         vector         *tgt_vec;
205         int             src_len;
206         int             tgt_len;
207
208         assert(pbqp);
209         assert(edge);
210
211         src_node = edge->src;
212         tgt_node = edge->tgt;
213         assert(src_node);
214         assert(tgt_node);
215
216         if(pbqp->dump_file) {
217                 char txt[100];
218                 sprintf(txt, "Simplification of Edge n%d-n%d", src_node->index, tgt_node->index);
219                 dump_section(pbqp->dump_file, 3, txt);
220         }
221
222         src_vec = src_node->costs;
223         tgt_vec = tgt_node->costs;
224         assert(src_vec);
225         assert(tgt_vec);
226
227         src_len = src_vec->len;
228         tgt_len = tgt_vec->len;
229         assert(src_len > 0);
230         assert(tgt_len > 0);
231
232         mat = edge->costs;
233         assert(mat);
234
235         if (pbqp->dump_file) {
236                 fputs("Input:<br>\n", pbqp->dump_file);
237                 dump_simplifyedge(pbqp, edge);
238         }
239
240         normalize_towards_source(pbqp, edge);
241         normalize_towards_target(pbqp, edge);
242
243         if (pbqp->dump_file) {
244                 fputs("<br>\nOutput:<br>\n", pbqp->dump_file);
245                 dump_simplifyedge(pbqp, edge);
246         }
247
248         if (pbqp_matrix_is_zero(mat, src_vec, tgt_vec)) {
249                 if (pbqp->dump_file) {
250                         fputs("edge has been eliminated", pbqp->dump_file);
251
252                         delete_edge(edge);
253                         reorder_node(src_node);
254                         reorder_node(tgt_node);
255                 }
256         }
257 }
258
259 void solve_pbqp_heuristical(pbqp *pbqp)
260 {
261         unsigned node_index;
262         unsigned node_len;
263
264         assert(pbqp);
265
266         if (pbqp->dump_file) {
267                 pbqp_dump_input(pbqp);
268                 dump_section(pbqp->dump_file, 1, "2. Simplification of Cost Matrices");
269         }
270
271         node_len = pbqp->num_nodes;
272
273         init_buckets();
274
275         /* First simplify all edges. */
276         for (node_index = 0; node_index < node_len; ++node_index) {
277                 unsigned    edge_index;
278                 pbqp_node  *node = get_node(pbqp, node_index);
279                 pbqp_edge **edges;
280                 unsigned    edge_len;
281
282                 if (!node) continue;
283
284                 edges = node->edges;
285                 edge_len = ARR_LEN(edges);
286
287                 for (edge_index = 0; edge_index < edge_len; ++edge_index) {
288                         pbqp_edge *edge = edges[edge_index];
289
290                         /* Simplify only once per edge. */
291                         if (node != edge->src) continue;
292
293                         simplify_edge(pbqp, edge);
294                 }
295         }
296
297         /* Put node into bucket representing their arity. */
298         fill_node_buckets(pbqp);
299
300         for (;;) {
301                 if (ARR_LEN(edge_bucket) > 0) {
302                         panic("Please implement edge simplification");
303                 } else if (ARR_LEN(node_buckets[1]) > 0) {
304                         applyRI(pbqp);
305                 } else if (ARR_LEN(node_buckets[2]) > 0) {
306                         panic("Please implement RII simplification");
307                 } else if (ARR_LEN(node_buckets[3]) > 0) {
308                         panic("Please implement RN simplification");
309                 } else {
310                         break;
311                 }
312         }
313
314         if (pbqp->dump_file) {
315                 dump_section(pbqp->dump_file, 1, "4. Determine Solution/Minimum");
316                 dump_section(pbqp->dump_file, 2, "4.1. Trivial Solution");
317         }
318
319         /* Solve trivial nodes and calculate solution. */
320         node_len = ARR_LEN(node_buckets[0]);
321         for (node_index = 0; node_index < node_len; ++node_index) {
322                 pbqp_node *node = node_buckets[0][node_index];
323                 assert(node);
324
325                 node->solution = vector_get_min_index(node->costs);
326                 pbqp->solution = add(pbqp->solution,
327                                 node->costs->entries[node->solution].data);
328                 if (pbqp->dump_file) {
329                         fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
330                         dump_node(pbqp, node);
331                 }
332         }
333
334         if (pbqp->dump_file) {
335                 dump_section(pbqp->dump_file, 2, "Minimum");
336                 fprintf(pbqp->dump_file, "Minimum is equal to %d.", pbqp->solution);
337                 dump_section(pbqp->dump_file, 2, "Back Propagation");
338         }
339
340         /* Solve reduced nodes. */
341         node_len = ARR_LEN(reduced_bucket);
342         for (node_index = node_len; node_index > 0; --node_index) {
343                 pbqp_node *node = reduced_bucket[node_index - 1];
344                 assert(node);
345
346                 switch (ARR_LEN(node->edges)) {
347                         case 1:
348                                 back_propagate_RI(pbqp, node);
349                                 break;
350                         case 2:
351                                 panic("Please implement back propagation for RII");
352                                 break;
353                         default:
354                                 panic("Only nodes with degree one or two should be in this bucket");
355                                 break;
356                 }
357         }
358 }
359
360 void applyRI(pbqp *pbqp)
361 {
362         pbqp_node  **bucket     = node_buckets[1];
363         unsigned     bucket_len = ARR_LEN(bucket);
364         pbqp_node   *node       = bucket[bucket_len - 1];
365         pbqp_edge   *edge       = node->edges[0];
366         pbqp_matrix *mat        = edge->costs;
367         int          is_src     = edge->src == node;
368         pbqp_node   *other_node;
369
370         if (is_src) {
371                 other_node = edge->tgt;
372         } else {
373                 other_node = edge->src;
374         }
375
376         if (pbqp->dump_file) {
377                 char     txt[100];
378                 sprintf(txt, "RI-Reduktion of Node n%d", node->index);
379                 dump_section(pbqp->dump_file, 2, txt);
380                 pbqp_dump_graph(pbqp);
381                 fputs("<br>\nBefore reduction:<br>\n", pbqp->dump_file);
382                 dump_node(pbqp, node);
383                 dump_node(pbqp, other_node);
384                 dump_edge(pbqp, edge);
385         }
386
387         if (is_src) {
388                 pbqp_matrix_add_to_all_cols(mat, node->costs);
389                 normalize_towards_target(pbqp, edge);
390         } else {
391                 pbqp_matrix_add_to_all_rows(mat, node->costs);
392                 normalize_towards_source(pbqp, edge);
393         }
394         disconnect_edge(other_node, edge);
395
396         if (pbqp->dump_file) {
397                 fputs("<br>\nAfter reduction:<br>\n", pbqp->dump_file);
398                 dump_node(pbqp, other_node);
399         }
400
401         /* Remove node from bucket... */
402         ARR_SHRINKLEN(bucket, (int)bucket_len - 1);
403         reorder_node(other_node);
404
405         /* ...and add it to back propagation list. */
406         node->bucket_index = ARR_LEN(reduced_bucket);
407         ARR_APP1(pbqp_node *, reduced_bucket, node);
408 }
409
410 void applyRII(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   *src_edge   = node->edges[0];
416         pbqp_edge   *tgt_edge   = node->edges[1];
417         int          src_is_src = src_edge->src == node;
418         int          tgt_is_src = tgt_edge->src == node;
419         pbqp_matrix *src_mat;
420         pbqp_matrix *tgt_mat;
421         pbqp_node   *src_node;
422         pbqp_node   *tgt_node;
423         pbqp_matrix *mat;
424         vector      *vec;
425         vector      *node_vec;
426         vector      *src_vec;
427         vector      *tgt_vec;
428         unsigned     col_index;
429         unsigned     col_len;
430         unsigned     row_index;
431         unsigned     row_len;
432         unsigned     node_len;
433
434         if (src_is_src) {
435                 src_node = src_edge->tgt;
436         } else {
437                 src_node = src_edge->src;
438         }
439
440         if (tgt_is_src) {
441                 tgt_node = tgt_edge->tgt;
442         } else {
443                 tgt_node = tgt_edge->src;
444         }
445
446         /* Swap nodes if necessary. */
447         if (tgt_node->index < src_node->index) {
448                 pbqp_node *tmp_node;
449                 pbqp_edge *tmp_edge;
450
451                 tmp_node = src_node;
452                 src_node = tgt_node;
453                 tgt_node = tmp_node;
454
455                 tmp_edge = src_edge;
456                 src_edge = tgt_edge;
457                 tgt_edge = tmp_edge;
458
459                 src_is_src = src_edge->src == node;
460                 tgt_is_src = tgt_edge->src == node;
461         }
462
463         src_mat = src_edge->costs;
464         tgt_mat = tgt_edge->costs;
465
466         src_vec  = src_node->costs;
467         tgt_vec  = tgt_node->costs;
468         node_vec = node->costs;
469
470         row_len  = ARR_LEN(src_vec);
471         col_len  = ARR_LEN(tgt_vec);
472         node_len = ARR_LEN(node_vec);
473
474         mat = pbqp_matrix_alloc(pbqp, row_len, col_len);
475
476         for (row_index = 0; row_index < row_len; ++row_index) {
477                 for (col_index = 0; col_index < col_len; ++col_index) {
478                         vec = vector_copy(pbqp, node_vec);
479
480                         if (src_is_src) {
481                                 vector_add_matrix_col(vec, src_mat, row_index);
482                         } else {
483                                 vector_add_matrix_row(vec, src_mat, row_index);
484                         }
485
486                         if (tgt_is_src) {
487                                 vector_add_matrix_col(vec, tgt_mat, col_index);
488                         } else {
489                                 vector_add_matrix_row(vec, tgt_mat, col_index);
490                         }
491
492                         mat->entries[row_index * col_len + col_index] = vector_get_min_index(vec);
493                 }
494         }
495
496         pbqp_edge *edge = get_edge(pbqp, src_node->index, tgt_node->index);
497
498         if (edge == NULL) {
499                 edge = alloc_edge(pbqp, src_node->index, tgt_node->index, mat);
500         } else {
501                 pbqp_matrix_add(edge->costs, mat);
502
503                 /* Free local matrix. */
504                 obstack_free(&pbqp->obstack, mat);
505         }
506
507         /* Disconnect node. */
508         disconnect_edge(src_node, src_edge);
509         disconnect_edge(tgt_node, tgt_edge);
510
511         /* Edge has changed so we simplify it. */
512         simplify_edge(pbqp, edge);
513 }
514
515 void back_propagate_RI(pbqp *pbqp, pbqp_node *node)
516 {
517         pbqp_edge   *edge;
518         pbqp_node   *other;
519         pbqp_matrix *mat;
520         vector      *vec;
521         int          is_src;
522
523         assert(pbqp);
524         assert(node);
525
526         edge = node->edges[0];
527         mat = edge->costs;
528         is_src = edge->src == node;
529         vec = node->costs;
530
531         if (is_src) {
532                 other = edge->tgt;
533                 assert(other);
534                 vector_add_matrix_col(vec, mat, other->solution);
535         } else {
536                 other = edge->src;
537                 assert(other);
538                 vector_add_matrix_row(vec, mat, other->solution);
539         }
540
541         node->solution = vector_get_min_index(vec);
542         if (pbqp->dump_file) {
543                 fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
544         }
545 }
546
547 int node_is_reduced(pbqp_node *node)
548 {
549         if (!reduced_bucket) return 0;
550
551         assert(node);
552         if (ARR_LEN(node->edges) == 0) return 1;
553
554         unsigned bucket_length = ARR_LEN(reduced_bucket);
555         unsigned bucket_index  = node->bucket_index;
556
557         return bucket_index < bucket_length && reduced_bucket[bucket_index] == node;
558 }