summaryrefslogtreecommitdiffhomepage
path: root/ir/kaps
diff options
context:
space:
mode:
authorAndreas Zwinkau <zwinkau@kit.edu>2011-04-08 14:10:06 +0200
committerAndreas Zwinkau <zwinkau@kit.edu>2011-04-08 14:10:06 +0200
commit1a3b7d363474ab544c13093a2f0b578718d37c7a (patch)
treede8f8252c74d3a2e446fb449c76891f1f495454d /ir/kaps
parent7ddfd63ef9928a20b1f83134f6f627a0c0bb3ecd (diff)
parent5b64d9c1f04f0c48c721022ff276c37a57e32992 (diff)
merge kaps
Diffstat (limited to 'ir/kaps')
-rw-r--r--ir/kaps/brute_force.c386
-rw-r--r--ir/kaps/brute_force.h34
-rw-r--r--ir/kaps/bucket.c182
-rw-r--r--ir/kaps/bucket.h51
-rw-r--r--ir/kaps/bucket_t.h35
-rw-r--r--ir/kaps/heuristical.c143
-rw-r--r--ir/kaps/heuristical.h34
-rw-r--r--ir/kaps/heuristical_co.c225
-rw-r--r--ir/kaps/heuristical_co.h36
-rw-r--r--ir/kaps/heuristical_co_ld.c396
-rw-r--r--ir/kaps/heuristical_co_ld.h16
-rw-r--r--ir/kaps/html_dumper.c225
-rw-r--r--ir/kaps/html_dumper.h43
-rw-r--r--ir/kaps/kaps.c153
-rw-r--r--ir/kaps/kaps.h61
-rw-r--r--ir/kaps/matrix.c386
-rw-r--r--ir/kaps/matrix.h65
-rw-r--r--ir/kaps/matrix_t.h40
-rw-r--r--ir/kaps/optimal.c1465
-rw-r--r--ir/kaps/optimal.h57
-rw-r--r--ir/kaps/pbqp_edge.c130
-rw-r--r--ir/kaps/pbqp_edge.h41
-rw-r--r--ir/kaps/pbqp_edge_t.h39
-rw-r--r--ir/kaps/pbqp_node.c165
-rw-r--r--ir/kaps/pbqp_node.h44
-rw-r--r--ir/kaps/pbqp_node_t.h40
-rw-r--r--ir/kaps/pbqp_t.h74
-rw-r--r--ir/kaps/vector.c202
-rw-r--r--ir/kaps/vector.h56
-rw-r--r--ir/kaps/vector_t.h49
30 files changed, 4873 insertions, 0 deletions
diff --git a/ir/kaps/brute_force.c b/ir/kaps/brute_force.c
new file mode 100644
index 0000000..94111ce
--- /dev/null
+++ b/ir/kaps/brute_force.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief Brute force PBQP solver.
+ * @date 02.12.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "assert.h"
+#include "error.h"
+
+#include "bucket.h"
+#include "brute_force.h"
+#include "optimal.h"
+#if KAPS_DUMP
+#include "html_dumper.h"
+#endif
+#include "kaps.h"
+#include "matrix.h"
+#include "pbqp_edge.h"
+#include "pbqp_edge_t.h"
+#include "pbqp_node.h"
+#include "pbqp_node_t.h"
+#include "vector.h"
+
+#if KAPS_STATISTIC
+static int dump = 0;
+#endif
+
+/* Forward declarations. */
+static void apply_Brute_Force(pbqp_t *pbqp);
+
+static void apply_brute_force_reductions(pbqp_t *pbqp)
+{
+ for (;;) {
+ if (edge_bucket_get_length(edge_bucket) > 0) {
+ apply_edge(pbqp);
+ } else if (node_bucket_get_length(node_buckets[1]) > 0) {
+ apply_RI(pbqp);
+ } else if (node_bucket_get_length(node_buckets[2]) > 0) {
+ apply_RII(pbqp);
+ } else if (node_bucket_get_length(node_buckets[3]) > 0) {
+ apply_Brute_Force(pbqp);
+ } else {
+ return;
+ }
+ }
+}
+
+static unsigned get_minimal_alternative(pbqp_t *pbqp, pbqp_node_t *node)
+{
+ vector_t *node_vec;
+ unsigned node_index;
+ unsigned node_len;
+ unsigned min_index = 0;
+ num min = INF_COSTS;
+ unsigned bucket_index;
+
+ assert(pbqp);
+ assert(node);
+ node_vec = node->costs;
+ node_len = node_vec->len;
+ bucket_index = node->bucket_index;
+
+ for (node_index = 0; node_index < node_len; ++node_index) {
+ pbqp_node_bucket_t bucket_deg3;
+ num value;
+ unsigned bucket_0_length;
+ unsigned bucket_red_length;
+
+ char *tmp = (char*)obstack_finish(&pbqp->obstack);
+
+ node_bucket_init(&bucket_deg3);
+
+ /* Some node buckets and the edge bucket should be empty. */
+ assert(node_bucket_get_length(node_buckets[1]) == 0);
+ assert(node_bucket_get_length(node_buckets[2]) == 0);
+ assert(edge_bucket_get_length(edge_bucket) == 0);
+
+ /* char *tmp = obstack_finish(&pbqp->obstack); */
+
+ /* Save current PBQP state. */
+ node_bucket_copy(&bucket_deg3, node_buckets[3]);
+ node_bucket_shrink(&node_buckets[3], 0);
+ node_bucket_deep_copy(pbqp, &node_buckets[3], bucket_deg3);
+ node_bucket_update(pbqp, node_buckets[3]);
+ bucket_0_length = node_bucket_get_length(node_buckets[0]);
+ bucket_red_length = node_bucket_get_length(reduced_bucket);
+
+ /* Select alternative and solve PBQP recursively. */
+ select_alternative(node_buckets[3][bucket_index], node_index);
+ apply_brute_force_reductions(pbqp);
+
+ value = determine_solution(pbqp);
+
+ if (value < min) {
+ min = value;
+ min_index = node_index;
+ }
+
+ /* Some node buckets and the edge bucket should still be empty. */
+ assert(node_bucket_get_length(node_buckets[1]) == 0);
+ assert(node_bucket_get_length(node_buckets[2]) == 0);
+ assert(edge_bucket_get_length(edge_bucket) == 0);
+
+ /* Clear modified buckets... */
+ node_bucket_shrink(&node_buckets[3], 0);
+
+ /* ... and restore old PBQP state. */
+ node_bucket_shrink(&node_buckets[0], bucket_0_length);
+ node_bucket_shrink(&reduced_bucket, bucket_red_length);
+ node_bucket_copy(&node_buckets[3], bucket_deg3);
+ node_bucket_update(pbqp, node_buckets[3]);
+
+ /* Free copies. */
+ /* obstack_free(&pbqp->obstack, tmp); */
+ node_bucket_free(&bucket_deg3);
+
+ obstack_free(&pbqp->obstack, tmp);
+ }
+
+ return min_index;
+}
+
+static void apply_Brute_Force(pbqp_t *pbqp)
+{
+ pbqp_node_t *node = NULL;
+ unsigned min_index = 0;
+
+ assert(pbqp);
+
+ /* We want to reduce a node with maximum degree. */
+ node = get_node_with_max_degree();
+ assert(node);
+ assert(pbqp_node_get_degree(node) > 2);
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ char txt[100];
+ sprintf(txt, "BF-Reduction of Node n%d", node->index);
+ dump_section(pbqp->dump_file, 2, txt);
+ pbqp_dump_graph(pbqp);
+ }
+#endif
+
+#if KAPS_STATISTIC
+ dump++;
+#endif
+
+ min_index = get_minimal_alternative(pbqp, node);
+ node = pbqp->nodes[node->index];
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ fprintf(pbqp->dump_file, "node n%d is set to %d<br><br>\n",
+ node->index, min_index);
+ }
+#endif
+
+#if KAPS_STATISTIC
+ dump--;
+ if (dump == 0) {
+ FILE *fh = fopen("solutions.pb", "a");
+ fprintf(fh, "[%u]", min_index);
+ fclose(fh);
+ pbqp->num_bf++;
+ }
+#endif
+
+ /* Now that we found the minimum set all other costs to infinity. */
+ select_alternative(node, min_index);
+}
+
+
+
+static void back_propagate_RI(pbqp_t *pbqp, pbqp_node_t *node)
+{
+ pbqp_edge_t *edge;
+ pbqp_node_t *other;
+ pbqp_matrix_t *mat;
+ vector_t *vec;
+ int is_src;
+
+ assert(pbqp);
+ assert(node);
+
+ edge = node->edges[0];
+ mat = edge->costs;
+ is_src = edge->src == node;
+ vec = node->costs;
+
+ if (is_src) {
+ other = edge->tgt;
+ assert(other);
+
+ /* Update pointer for brute force solver. */
+ other = pbqp->nodes[other->index];
+
+ node->solution = pbqp_matrix_get_col_min_index(mat, other->solution, vec);
+ } else {
+ other = edge->src;
+ assert(other);
+
+ /* Update pointer for brute force solver. */
+ other = pbqp->nodes[other->index];
+
+ node->solution = pbqp_matrix_get_row_min_index(mat, other->solution, vec);
+ }
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
+ }
+#endif
+}
+
+static void back_propagate_RII(pbqp_t *pbqp, pbqp_node_t *node)
+{
+ pbqp_edge_t *src_edge = node->edges[0];
+ pbqp_edge_t *tgt_edge = node->edges[1];
+ int src_is_src = src_edge->src == node;
+ int tgt_is_src = tgt_edge->src == node;
+ pbqp_matrix_t *src_mat;
+ pbqp_matrix_t *tgt_mat;
+ pbqp_node_t *src_node;
+ pbqp_node_t *tgt_node;
+ vector_t *vec;
+ vector_t *node_vec;
+ unsigned col_index;
+ unsigned row_index;
+
+ assert(pbqp);
+
+ if (src_is_src) {
+ src_node = src_edge->tgt;
+ } else {
+ src_node = src_edge->src;
+ }
+
+ if (tgt_is_src) {
+ tgt_node = tgt_edge->tgt;
+ } else {
+ tgt_node = tgt_edge->src;
+ }
+
+ /* Swap nodes if necessary. */
+ if (tgt_node->index < src_node->index) {
+ pbqp_node_t *tmp_node;
+ pbqp_edge_t *tmp_edge;
+
+ tmp_node = src_node;
+ src_node = tgt_node;
+ tgt_node = tmp_node;
+
+ tmp_edge = src_edge;
+ src_edge = tgt_edge;
+ tgt_edge = tmp_edge;
+
+ src_is_src = src_edge->src == node;
+ tgt_is_src = tgt_edge->src == node;
+ }
+
+ /* Update pointer for brute force solver. */
+ src_node = pbqp->nodes[src_node->index];
+ tgt_node = pbqp->nodes[tgt_node->index];
+
+ src_mat = src_edge->costs;
+ tgt_mat = tgt_edge->costs;
+
+ node_vec = node->costs;
+
+ row_index = src_node->solution;
+ col_index = tgt_node->solution;
+
+ vec = vector_copy(pbqp, node_vec);
+
+ if (src_is_src) {
+ vector_add_matrix_col(vec, src_mat, row_index);
+ } else {
+ vector_add_matrix_row(vec, src_mat, row_index);
+ }
+
+ if (tgt_is_src) {
+ vector_add_matrix_col(vec, tgt_mat, col_index);
+ } else {
+ vector_add_matrix_row(vec, tgt_mat, col_index);
+ }
+
+ node->solution = vector_get_min_index(vec);
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
+ }
+#endif
+
+ obstack_free(&pbqp->obstack, vec);
+}
+
+static void back_propagate_brute_force(pbqp_t *pbqp)
+{
+ unsigned node_index;
+ unsigned node_len = node_bucket_get_length(reduced_bucket);
+
+ assert(pbqp);
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ dump_section(pbqp->dump_file, 2, "Back Propagation");
+ }
+#endif
+
+ for (node_index = node_len; node_index > 0; --node_index) {
+ pbqp_node_t *node = reduced_bucket[node_index - 1];
+
+ switch (pbqp_node_get_degree(node)) {
+ case 1:
+ back_propagate_RI(pbqp, node);
+ break;
+ case 2:
+ back_propagate_RII(pbqp, node);
+ break;
+ default:
+ panic("Only nodes with degree one or two should be in this bucket");
+ break;
+ }
+ }
+}
+
+void solve_pbqp_brute_force(pbqp_t *pbqp)
+{
+ /* Reduce nodes degree ... */
+ initial_simplify_edges(pbqp);
+
+ /* ... and put node into bucket representing their degree. */
+ fill_node_buckets(pbqp);
+
+#if KAPS_STATISTIC
+ FILE *fh = fopen("solutions.pb", "a");
+ fprintf(fh, "Solution");
+ fclose(fh);
+#endif
+
+ apply_brute_force_reductions(pbqp);
+
+ pbqp->solution = determine_solution(pbqp);
+
+#if KAPS_STATISTIC
+ fh = fopen("solutions.pb", "a");
+ #if KAPS_USE_UNSIGNED
+ fprintf(fh, ": %u RE:%u R0:%u R1:%u R2:%u RM:%u RN/BF:%u\n", pbqp->solution,
+ pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
+ pbqp->num_rm, pbqp->num_rn);
+ #else
+ fprintf(fh, ": %lld RE:%u R0:%u R1:%u R2:%u RM:%u RN/BF:%u\n", pbqp->solution,
+ pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
+ pbqp->num_rm, pbqp->num_bf);
+ #endif
+ fclose(fh);
+#endif
+
+ /* Solve reduced nodes. */
+ back_propagate_brute_force(pbqp);
+
+ free_buckets();
+}
diff --git a/ir/kaps/brute_force.h b/ir/kaps/brute_force.h
new file mode 100644
index 0000000..696dccc
--- /dev/null
+++ b/ir/kaps/brute_force.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief Brute force PBQP solver.
+ * @date 02.12.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_BRUTE_FORCE_H
+#define KAPS_BRUTE_FORCE_H
+
+#include "pbqp_t.h"
+
+void solve_pbqp_brute_force(pbqp_t *pbqp);
+
+#endif /* KAPS_BRUTE_FORCE_H */
diff --git a/ir/kaps/bucket.c b/ir/kaps/bucket.c
new file mode 100644
index 0000000..77e8599
--- /dev/null
+++ b/ir/kaps/bucket.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief Buckets for nodes and edges.
+ * @date 30.11.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "adt/array.h"
+
+#include "bucket.h"
+#include "pbqp_edge_t.h"
+#include "pbqp_node.h"
+#include "pbqp_node_t.h"
+
+int edge_bucket_contains(pbqp_edge_bucket_t bucket, pbqp_edge_t *edge)
+{
+ assert(edge);
+
+ return edge->bucket_index < edge_bucket_get_length(bucket)
+ && bucket[edge->bucket_index] == edge;
+}
+
+void edge_bucket_free(pbqp_edge_bucket_t *bucket)
+{
+ DEL_ARR_F(*bucket);
+ *bucket = NULL;
+}
+
+unsigned edge_bucket_get_length(pbqp_edge_bucket_t bucket)
+{
+ return ARR_LEN(bucket);
+}
+
+void edge_bucket_init(pbqp_edge_bucket_t *bucket)
+{
+ *bucket = NEW_ARR_F(pbqp_edge_t *, 0);
+}
+
+void edge_bucket_insert(pbqp_edge_bucket_t *bucket, pbqp_edge_t *edge)
+{
+ edge->bucket_index = edge_bucket_get_length(*bucket);
+ ARR_APP1(pbqp_edge_t *, *bucket, edge);
+}
+
+pbqp_edge_t *edge_bucket_pop(pbqp_edge_bucket_t *bucket)
+{
+ unsigned bucket_len = edge_bucket_get_length(*bucket);
+ pbqp_edge_t *edge;
+
+ assert(bucket_len > 0);
+
+ edge = (*bucket)[bucket_len - 1];
+
+ ARR_SHRINKLEN(*bucket, (int)bucket_len - 1);
+ edge->bucket_index = UINT_MAX;
+
+ return edge;
+}
+
+void node_bucket_shrink(pbqp_node_bucket_t *bucket, unsigned len)
+{
+ ARR_SHRINKLEN(*bucket, (int)len);
+}
+
+int node_bucket_contains(pbqp_node_bucket_t bucket, pbqp_node_t *node)
+{
+ assert(node);
+
+ return node->bucket_index < node_bucket_get_length(bucket)
+ && bucket[node->bucket_index] == node;
+}
+
+void node_bucket_copy(pbqp_node_bucket_t *dst, pbqp_node_bucket_t src)
+{
+ unsigned src_index;
+ unsigned src_length = node_bucket_get_length(src);
+
+ for (src_index = 0; src_index < src_length; ++src_index) {
+ node_bucket_insert(dst, src[src_index]);
+ }
+}
+
+void node_bucket_update(pbqp_t *pbqp, pbqp_node_bucket_t bucket)
+{
+ unsigned index;
+ unsigned length = node_bucket_get_length(bucket);
+
+ for (index = 0; index < length; ++index) {
+ pbqp->nodes[bucket[index]->index] = bucket[index];
+ }
+}
+
+void node_bucket_free(pbqp_node_bucket_t *bucket)
+{
+ DEL_ARR_F(*bucket);
+ *bucket = NULL;
+}
+
+unsigned node_bucket_get_length(pbqp_node_bucket_t bucket)
+{
+ return ARR_LEN(bucket);
+}
+
+void node_bucket_init(pbqp_node_bucket_t *bucket)
+{
+ *bucket = NEW_ARR_F(pbqp_node_t*, 0);
+}
+
+void node_bucket_insert(pbqp_node_bucket_t *bucket, pbqp_node_t *node)
+{
+ node->bucket_index = node_bucket_get_length(*bucket);
+ ARR_APP1(pbqp_node_t *, *bucket, node);
+}
+
+pbqp_node_t *node_bucket_pop(pbqp_node_bucket_t *bucket)
+{
+ unsigned bucket_len = node_bucket_get_length(*bucket);
+ pbqp_node_t *node;
+
+ assert(bucket_len > 0);
+
+ node = (*bucket)[bucket_len - 1];
+ assert(node);
+
+ ARR_SHRINKLEN(*bucket, (int)bucket_len - 1);
+ node->bucket_index = UINT_MAX;
+
+ return node;
+}
+
+void node_bucket_remove(pbqp_node_bucket_t *bucket, pbqp_node_t *node)
+{
+ unsigned bucket_len = node_bucket_get_length(*bucket);
+ unsigned node_index;
+ pbqp_node_t *other;
+
+ assert(node);
+ assert(node_bucket_contains(*bucket, node));
+ assert(bucket_len > 0);
+
+ node_index = node->bucket_index;
+ other = (*bucket)[bucket_len - 1];
+ other->bucket_index = node_index;
+ (*bucket)[node_index] = other;
+
+ ARR_SHRINKLEN(*bucket, (int)bucket_len - 1);
+ node->bucket_index = UINT_MAX;
+}
+
+void node_bucket_deep_copy(pbqp_t *pbqp, pbqp_node_bucket_t *dst,
+ pbqp_node_bucket_t src)
+{
+ unsigned bucket_index;
+ unsigned bucket_length;
+
+ bucket_length = node_bucket_get_length(src);
+
+ for (bucket_index = 0; bucket_index < bucket_length; ++bucket_index) {
+ node_bucket_insert(dst, pbqp_node_deep_copy(pbqp, *dst, src[bucket_index]));
+ }
+}
diff --git a/ir/kaps/bucket.h b/ir/kaps/bucket.h
new file mode 100644
index 0000000..fd0d92e
--- /dev/null
+++ b/ir/kaps/bucket.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief Buckets for nodes and edges.
+ * @date 30.11.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_BUCKET_H
+#define KAPS_BUCKET_H
+
+#include "bucket_t.h"
+
+int edge_bucket_contains(pbqp_edge_bucket_t bucket, pbqp_edge_t *edge);
+void edge_bucket_free(pbqp_edge_bucket_t *bucket);
+unsigned edge_bucket_get_length(pbqp_edge_bucket_t bucket);
+void edge_bucket_init(pbqp_edge_bucket_t *bucket);
+void edge_bucket_insert(pbqp_edge_bucket_t *bucket, pbqp_edge_t *edge);
+pbqp_edge_t *edge_bucket_pop(pbqp_edge_bucket_t *bucket);
+
+int node_bucket_contains(pbqp_node_bucket_t bucket, pbqp_node_t *node);
+void node_bucket_copy(pbqp_node_bucket_t *dst, pbqp_node_bucket_t src);
+void node_bucket_deep_copy(pbqp_t *pbqp, pbqp_node_bucket_t *dst, pbqp_node_bucket_t src);
+void node_bucket_free(pbqp_node_bucket_t *bucket);
+unsigned node_bucket_get_length(pbqp_node_bucket_t bucket);
+void node_bucket_init(pbqp_node_bucket_t *bucket);
+void node_bucket_insert(pbqp_node_bucket_t *bucket, pbqp_node_t *node);
+pbqp_node_t *node_bucket_pop(pbqp_node_bucket_t *bucket);
+void node_bucket_remove(pbqp_node_bucket_t *bucket, pbqp_node_t *node);
+void node_bucket_shrink(pbqp_node_bucket_t *bucket, unsigned len);
+void node_bucket_update(pbqp_t *pbqp, pbqp_node_bucket_t bucket);
+
+#endif /* KAPS_BUCKET_H */
diff --git a/ir/kaps/bucket_t.h b/ir/kaps/bucket_t.h
new file mode 100644
index 0000000..df9cce5
--- /dev/null
+++ b/ir/kaps/bucket_t.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief Node/edge bucket data types.
+ * @date 30.11.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_BUCKET_T_H
+#define KAPS_BUCKET_T_H
+
+#include "pbqp_t.h"
+
+typedef pbqp_node_t** pbqp_node_bucket_t;
+typedef pbqp_edge_t** pbqp_edge_bucket_t;
+
+#endif /* KAPS_BUCKET_T_H */
diff --git a/ir/kaps/heuristical.c b/ir/kaps/heuristical.c
new file mode 100644
index 0000000..c078f5d
--- /dev/null
+++ b/ir/kaps/heuristical.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief Heuristic PBQP solver.
+ * @date 02.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "adt/array.h"
+#include "assert.h"
+#include "error.h"
+
+#include "bucket.h"
+#include "heuristical.h"
+#include "optimal.h"
+#if KAPS_DUMP
+#include "html_dumper.h"
+#endif
+#include "kaps.h"
+#include "matrix.h"
+#include "pbqp_edge.h"
+#include "pbqp_edge_t.h"
+#include "pbqp_node.h"
+#include "pbqp_node_t.h"
+#include "vector.h"
+
+#include "timing.h"
+
+static void apply_RN(pbqp_t *pbqp)
+{
+ pbqp_node_t *node = NULL;
+ unsigned min_index = 0;
+
+ assert(pbqp);
+
+ /* We want to reduce a node with maximum degree. */
+ node = get_node_with_max_degree();
+ assert(node);
+ assert(pbqp_node_get_degree(node) > 2);
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ char txt[100];
+ sprintf(txt, "RN-Reduction of Node n%d", node->index);
+ dump_section(pbqp->dump_file, 2, txt);
+ pbqp_dump_graph(pbqp);
+ }
+#endif
+
+ min_index = get_local_minimal_alternative(pbqp, node);
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ fprintf(pbqp->dump_file, "node n%d is set to %d<br><br>\n",
+ node->index, min_index);
+ }
+#endif
+
+#if KAPS_STATISTIC
+ FILE *fh = fopen("solutions.pb", "a");
+ fprintf(fh, "[%u]", min_index);
+ fclose(fh);
+ pbqp->num_rn++;
+#endif
+
+ /* Now that we found the local minimum set all other costs to infinity. */
+ select_alternative(node, min_index);
+}
+
+static void apply_heuristic_reductions(pbqp_t *pbqp)
+{
+ for (;;) {
+ if (edge_bucket_get_length(edge_bucket) > 0) {
+ apply_edge(pbqp);
+ } else if (node_bucket_get_length(node_buckets[1]) > 0) {
+ apply_RI(pbqp);
+ } else if (node_bucket_get_length(node_buckets[2]) > 0) {
+ apply_RII(pbqp);
+ } else if (node_bucket_get_length(node_buckets[3]) > 0) {
+ apply_RN(pbqp);
+ } else {
+ return;
+ }
+ }
+}
+
+void solve_pbqp_heuristical(pbqp_t *pbqp)
+{
+ /* Reduce nodes degree ... */
+ initial_simplify_edges(pbqp);
+
+ /* ... and put node into bucket representing their degree. */
+ fill_node_buckets(pbqp);
+
+#if KAPS_STATISTIC
+ FILE *fh = fopen("solutions.pb", "a");
+ fprintf(fh, "Solution");
+ fclose(fh);
+#endif
+
+ apply_heuristic_reductions(pbqp);
+
+ pbqp->solution = determine_solution(pbqp);
+
+#if KAPS_STATISTIC
+ fh = fopen("solutions.pb", "a");
+ #if KAPS_USE_UNSIGNED
+ fprintf(fh, ": %u RE:%u R0:%u R1:%u R2:%u RM:%u RN/BF:%u\n", pbqp->solution,
+ pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
+ pbqp->num_rm, pbqp->num_rn);
+ #else
+ fprintf(fh, ": %lld RE:%u R0:%u R1:%u R2:%u RM:%u RN/BF:%u\n", pbqp->solution,
+ pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
+ pbqp->num_rm, pbqp->num_rn);
+ #endif
+ fclose(fh);
+#endif
+
+ /* Solve reduced nodes. */
+ back_propagate(pbqp);
+
+ free_buckets();
+}
diff --git a/ir/kaps/heuristical.h b/ir/kaps/heuristical.h
new file mode 100644
index 0000000..688b2bf
--- /dev/null
+++ b/ir/kaps/heuristical.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief Heuristic PBQP solver.
+ * @date 02.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_HEURISTICAL_CO_H
+#define KAPS_HEURISTICAL_CO_H
+
+#include "pbqp_t.h"
+
+void solve_pbqp_heuristical(pbqp_t *pbqp);
+
+#endif /* KAPS_HEURISTICAL_CO_H */
diff --git a/ir/kaps/heuristical_co.c b/ir/kaps/heuristical_co.c
new file mode 100644
index 0000000..aa30729
--- /dev/null
+++ b/ir/kaps/heuristical_co.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief Heuristic PBQP solver for SSA-based register allocation.
+ * @date 18.09.2009
+ * @author Thomas Bersch
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "adt/array.h"
+#include "assert.h"
+#include "error.h"
+
+#include "bucket.h"
+#include "heuristical_co.h"
+#include "optimal.h"
+#if KAPS_DUMP
+#include "html_dumper.h"
+#endif
+#include "kaps.h"
+#include "matrix.h"
+#include "pbqp_edge.h"
+#include "pbqp_edge_t.h"
+#include "pbqp_node.h"
+#include "pbqp_node_t.h"
+#include "vector.h"
+
+#include "plist.h"
+#include "timing.h"
+
+static void merge_into_RN_node(pbqp_t *pbqp, plist_t *rpeo)
+{
+ pbqp_node_t *node = NULL;
+
+ assert(pbqp);
+
+ /* We want to reduce the first node in reverse perfect elimination order. */
+ do {
+ /* get first element from reverse perfect elimination order */
+ node = (pbqp_node_t*)plist_first(rpeo)->data;
+ /* remove element from reverse perfect elimination order */
+ plist_erase(rpeo, plist_first(rpeo));
+ /* insert node at the end of rpeo so the rpeo already exits after pbqp solving */
+ plist_insert_back(rpeo, node);
+ } while(node_is_reduced(node));
+
+ assert(node);
+ assert(pbqp_node_get_degree(node) > 2);
+
+ /* Check whether we can merge a neighbor into the current node. */
+ apply_RM(pbqp, node);
+}
+
+static void apply_RN_co(pbqp_t *pbqp)
+{
+ pbqp_node_t *node;
+ unsigned min_index;
+
+ assert(pbqp);
+
+ node = merged_node;
+ merged_node = NULL;
+ assert(node);
+
+ if (node_is_reduced(node))
+ return;
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ char txt[100];
+ sprintf(txt, "RN-Reduction of Node n%d", node->index);
+ dump_section(pbqp->dump_file, 2, txt);
+ pbqp_dump_graph(pbqp);
+ }
+#endif
+
+ min_index = get_local_minimal_alternative(pbqp, node);
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ fprintf(pbqp->dump_file, "node n%d is set to %d<br><br>\n",
+ node->index, min_index);
+ }
+#endif
+
+#if KAPS_STATISTIC
+ FILE *fh = fopen("solutions.pb", "a");
+ fprintf(fh, "[%u]", min_index);
+ fclose(fh);
+ pbqp->num_rn++;
+#endif
+
+ /* Now that we found the local minimum set all other costs to infinity. */
+ select_alternative(node, min_index);
+}
+
+static void apply_heuristic_reductions_co(pbqp_t *pbqp, plist_t *rpeo)
+{
+ #if KAPS_TIMING
+ /* create timers */
+ ir_timer_t *t_edge = ir_timer_new();
+ ir_timer_t *t_r1 = ir_timer_new();
+ ir_timer_t *t_r2 = ir_timer_new();
+ ir_timer_t *t_rn = ir_timer_new();
+ #endif
+
+ for (;;) {
+ if (edge_bucket_get_length(edge_bucket) > 0) {
+ #if KAPS_TIMING
+ ir_timer_start(t_edge);
+ #endif
+
+ apply_edge(pbqp);
+
+ #if KAPS_TIMING
+ ir_timer_stop(t_edge);
+ #endif
+ } else if (node_bucket_get_length(node_buckets[1]) > 0) {
+ #if KAPS_TIMING
+ ir_timer_start(t_r1);
+ #endif
+
+ apply_RI(pbqp);
+
+ #if KAPS_TIMING
+ ir_timer_stop(t_r1);
+ #endif
+ } else if (node_bucket_get_length(node_buckets[2]) > 0) {
+ #if KAPS_TIMING
+ ir_timer_start(t_r2);
+ #endif
+
+ apply_RII(pbqp);
+
+ #if KAPS_TIMING
+ ir_timer_stop(t_r2);
+ #endif
+ } else if (merged_node != NULL) {
+ #if KAPS_TIMING
+ ir_timer_start(t_rn);
+ #endif
+
+ apply_RN_co(pbqp);
+
+ #if KAPS_TIMING
+ ir_timer_stop(t_rn);
+ #endif
+ } else if (node_bucket_get_length(node_buckets[3]) > 0) {
+ #if KAPS_TIMING
+ ir_timer_start(t_rn);
+ #endif
+
+ merge_into_RN_node(pbqp, rpeo);
+
+ #if KAPS_TIMING
+ ir_timer_stop(t_rn);
+ #endif
+ } else {
+ #if KAPS_TIMING
+ printf("PBQP RE reductions: %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_edge) / 1000.0);
+ printf("PBQP R1 reductions: %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_r1) / 1000.0);
+ printf("PBQP R2 reductions: %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_r2) / 1000.0);
+ printf("PBQP RN reductions: %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_rn) / 1000.0);
+ #endif
+
+ return;
+ }
+ }
+}
+
+void solve_pbqp_heuristical_co(pbqp_t *pbqp, plist_t *rpeo)
+{
+ /* Reduce nodes degree ... */
+ initial_simplify_edges(pbqp);
+
+ /* ... and put node into bucket representing their degree. */
+ fill_node_buckets(pbqp);
+
+ #if KAPS_STATISTIC
+ FILE *fh = fopen("solutions.pb", "a");
+ fprintf(fh, "Solution");
+ fclose(fh);
+ #endif
+
+ apply_heuristic_reductions_co(pbqp, rpeo);
+
+ pbqp->solution = determine_solution(pbqp);
+
+ #if KAPS_STATISTIC
+ fh = fopen("solutions.pb", "a");
+ #if KAPS_USE_UNSIGNED
+ fprintf(fh, ": %u RE:%u R0:%u R1:%u R2:%u RM:%u RN/BF:%u\n", pbqp->solution,
+ pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
+ pbqp->num_rm, pbqp->num_rn);
+ #else
+ fprintf(fh, ": %lld RE:%u R0:%u R1:%u R2:%u RM:%u RN/BF:%u\n", pbqp->solution,
+ pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
+ #endif
+ fclose(fh);
+ #endif
+
+ /* Solve reduced nodes. */
+ back_propagate(pbqp);
+
+ free_buckets();
+}
diff --git a/ir/kaps/heuristical_co.h b/ir/kaps/heuristical_co.h
new file mode 100644
index 0000000..2872edc
--- /dev/null
+++ b/ir/kaps/heuristical_co.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief Heuristic PBQP solver for SSA-based register allocation.
+ * @date 18.09.2009
+ * @author Thomas Bersch
+ * @version $Id$
+ */
+#ifndef KAPS_HEURISTICAL_H
+#define KAPS_HEURISTICAL_H
+
+#include "pbqp_t.h"
+
+#include "plist.h"
+
+void solve_pbqp_heuristical_co(pbqp_t *pbqp, plist_t *rpeo);
+
+#endif /* KAPS_HEURISTICAL_H */
diff --git a/ir/kaps/heuristical_co_ld.c b/ir/kaps/heuristical_co_ld.c
new file mode 100644
index 0000000..ba694f9
--- /dev/null
+++ b/ir/kaps/heuristical_co_ld.c
@@ -0,0 +1,396 @@
+/*
+ * heuristical_co_ld.c
+ *
+ * Created on: 06.05.2010
+ * Author: berschth
+ */
+
+#include "config.h"
+
+#include "adt/array.h"
+#include "assert.h"
+#include "error.h"
+
+#include "bucket.h"
+#include "heuristical_co_ld.h"
+#include "optimal.h"
+#if KAPS_DUMP
+#include "html_dumper.h"
+#endif
+#include "kaps.h"
+#include "matrix.h"
+#include "pbqp_edge.h"
+#include "pbqp_edge_t.h"
+#include "pbqp_node.h"
+#include "pbqp_node_t.h"
+#include "vector.h"
+
+#include "plist.h"
+#include "timing.h"
+
+static void back_propagate_RI(pbqp_t *pbqp, pbqp_node_t *node)
+{
+ pbqp_edge_t *edge;
+ pbqp_node_t *other;
+ pbqp_matrix_t *mat;
+ vector_t *vec;
+ int is_src;
+
+ assert(pbqp);
+ assert(node);
+
+ (void) pbqp;
+
+ edge = node->edges[0];
+ mat = edge->costs;
+ is_src = edge->src == node;
+ vec = node->costs;
+
+ if (is_src) {
+ other = edge->tgt;
+ assert(other);
+
+ node->solution = pbqp_matrix_get_col_min_index(mat, other->solution, vec);
+ } else {
+ other = edge->src;
+ assert(other);
+
+ node->solution = pbqp_matrix_get_row_min_index(mat, other->solution, vec);
+ }
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
+ }
+#endif
+}
+
+static void back_propagate_RII(pbqp_t *pbqp, pbqp_node_t *node)
+{
+ pbqp_edge_t *src_edge = node->edges[0];
+ pbqp_edge_t *tgt_edge = node->edges[1];
+ int src_is_src = src_edge->src == node;
+ int tgt_is_src = tgt_edge->src == node;
+ pbqp_matrix_t *src_mat;
+ pbqp_matrix_t *tgt_mat;
+ pbqp_node_t *src_node;
+ pbqp_node_t *tgt_node;
+ vector_t *vec;
+ vector_t *node_vec;
+ unsigned col_index;
+ unsigned row_index;
+
+ assert(pbqp);
+
+ if (src_is_src) {
+ src_node = src_edge->tgt;
+ } else {
+ src_node = src_edge->src;
+ }
+
+ if (tgt_is_src) {
+ tgt_node = tgt_edge->tgt;
+ } else {
+ tgt_node = tgt_edge->src;
+ }
+
+ /* Swap nodes if necessary. */
+ if (tgt_node->index < src_node->index) {
+ pbqp_node_t *tmp_node;
+ pbqp_edge_t *tmp_edge;
+
+ tmp_node = src_node;
+ src_node = tgt_node;
+ tgt_node = tmp_node;
+
+ tmp_edge = src_edge;
+ src_edge = tgt_edge;
+ tgt_edge = tmp_edge;
+
+ src_is_src = src_edge->src == node;
+ tgt_is_src = tgt_edge->src == node;
+ }
+
+ src_mat = src_edge->costs;
+ tgt_mat = tgt_edge->costs;
+
+ node_vec = node->costs;
+
+ row_index = src_node->solution;
+ col_index = tgt_node->solution;
+
+ vec = vector_copy(pbqp, node_vec);
+
+ if (src_is_src) {
+ vector_add_matrix_col(vec, src_mat, row_index);
+ } else {
+ vector_add_matrix_row(vec, src_mat, row_index);
+ }
+
+ if (tgt_is_src) {
+ vector_add_matrix_col(vec, tgt_mat, col_index);
+ } else {
+ vector_add_matrix_row(vec, tgt_mat, col_index);
+ }
+
+ node->solution = vector_get_min_index(vec);
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
+ }
+#endif
+
+ obstack_free(&pbqp->obstack, vec);
+}
+
+static void back_propagate_RN(pbqp_t *pbqp, pbqp_node_t *node)
+{
+ vector_t *vec = NULL;
+ pbqp_node_t *neighbor = NULL;
+ pbqp_edge_t *edge = NULL;
+ unsigned edge_index = 0;
+
+ assert(pbqp);
+
+ vec = vector_copy(pbqp, node->costs);
+
+ for(edge_index = 0; edge_index < pbqp_node_get_degree(node); edge_index++) {
+ /* get neighbor node */
+ edge = node->edges[edge_index];
+ neighbor = edge->src == node ? edge->tgt : edge->src;
+
+ /* node is edge src node */
+ if(edge->src == node)
+ vector_add_matrix_col(vec, edge->costs, neighbor->solution);
+ /* node is edge tgt node */
+ else
+ vector_add_matrix_row(vec, edge->costs, neighbor->solution);
+ }
+
+ assert(vector_get_min(vec) != INF_COSTS);
+ node->solution = vector_get_min_index(vec);
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
+ }
+#endif
+
+ obstack_free(&pbqp->obstack, vec);
+}
+
+static void back_propagate_ld(pbqp_t *pbqp)
+{
+ unsigned node_index;
+ unsigned node_len = node_bucket_get_length(reduced_bucket);
+
+ assert(pbqp);
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ dump_section(pbqp->dump_file, 2, "Back Propagation");
+ }
+#endif
+
+ for (node_index = node_len; node_index > 0; --node_index) {
+ pbqp_node_t *node = reduced_bucket[node_index - 1];
+
+ switch (pbqp_node_get_degree(node)) {
+ case 1:
+ back_propagate_RI(pbqp, node);
+ break;
+ case 2:
+ back_propagate_RII(pbqp, node);
+ break;
+ default:
+ back_propagate_RN(pbqp, node);
+ break;
+ }
+ }
+}
+
+static void merge_into_RN_node(pbqp_t *pbqp, plist_t *rpeo)
+{
+ pbqp_node_t *node = NULL;
+
+ assert(pbqp);
+
+ do {
+ /* get last element from reverse perfect elimination order */
+ node = (pbqp_node_t*)plist_last(rpeo)->data;
+ /* remove element from reverse perfect elimination order */
+ plist_erase(rpeo, plist_last(rpeo));
+ /* insert node at the beginning of rpeo so the rpeo already exits after pbqp solving */
+ plist_insert_front(rpeo, node);
+ } while(node_is_reduced(node));
+
+ assert(node);
+ assert(pbqp_node_get_degree(node) > 2);
+
+ /* Check whether we can merge a neighbor into the current node. */
+ apply_RM(pbqp, node);
+}
+
+static void apply_RN_co_without_selection(pbqp_t *pbqp)
+{
+ pbqp_node_t *node;
+ unsigned edge_index;
+
+ assert(pbqp);
+
+ node = merged_node;
+ merged_node = NULL;
+ assert(node);
+
+ if (node_is_reduced(node))
+ return;
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ char txt[100];
+ sprintf(txt, "RN-Reduction of Node n%d", node->index);
+ dump_section(pbqp->dump_file, 2, txt);
+ pbqp_dump_graph(pbqp);
+ }
+#endif
+
+ /* Disconnect neighbor nodes */
+ for(edge_index = 0; edge_index < pbqp_node_get_degree(node); edge_index++) {
+ pbqp_edge_t *edge;
+ pbqp_node_t *neighbor;
+
+ /* get neighbor node */
+ edge = node->edges[edge_index];
+ assert(edge);
+
+ neighbor = edge->src == node ? edge->tgt : edge->src;
+ assert(neighbor);
+
+ assert(neighbor != node);
+
+ if(!is_connected(neighbor, edge))
+ continue;
+
+ disconnect_edge(neighbor, edge);
+ reorder_node_after_edge_deletion(neighbor);
+ }
+
+ /* Remove node from old bucket */
+ node_bucket_remove(&node_buckets[3], node);
+
+ /* Add node to back propagation list. */
+ node_bucket_insert(&reduced_bucket, node);
+}
+
+static void apply_heuristic_reductions_co(pbqp_t *pbqp, plist_t *rpeo)
+{
+ #if KAPS_TIMING
+ /* create timers */
+ ir_timer_t *t_edge = ir_timer_new();
+ ir_timer_t *t_r1 = ir_timer_new();
+ ir_timer_t *t_r2 = ir_timer_new();
+ ir_timer_t *t_rn = ir_timer_new();
+ #endif
+
+ for (;;) {
+ if (edge_bucket_get_length(edge_bucket) > 0) {
+ #if KAPS_TIMING
+ ir_timer_start(t_edge);
+ #endif
+
+ apply_edge(pbqp);
+
+ #if KAPS_TIMING
+ ir_timer_stop(t_edge);
+ #endif
+ } else if (node_bucket_get_length(node_buckets[1]) > 0) {
+ #if KAPS_TIMING
+ ir_timer_start(t_r1);
+ #endif
+
+ apply_RI(pbqp);
+
+ #if KAPS_TIMING
+ ir_timer_stop(t_r1);
+ #endif
+ } else if (node_bucket_get_length(node_buckets[2]) > 0) {
+ #if KAPS_TIMING
+ ir_timer_start(t_r2);
+ #endif
+
+ apply_RII(pbqp);
+
+ #if KAPS_TIMING
+ ir_timer_stop(t_r2);
+ #endif
+ } else if (merged_node != NULL) {
+ #if KAPS_TIMING
+ ir_timer_start(t_rn);
+ #endif
+
+ apply_RN_co_without_selection(pbqp);
+
+ #if KAPS_TIMING
+ ir_timer_stop(t_rn);
+ #endif
+ } else if (node_bucket_get_length(node_buckets[3]) > 0) {
+ #if KAPS_TIMING
+ ir_timer_start(t_rn);
+ #endif
+
+ merge_into_RN_node(pbqp, rpeo);
+
+ #if KAPS_TIMING
+ ir_timer_stop(t_rn);
+ #endif
+ } else {
+ #if KAPS_TIMING
+ printf("PBQP RE reductions: %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_edge) / 1000.0);
+ printf("PBQP R1 reductions: %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_r1) / 1000.0);
+ printf("PBQP R2 reductions: %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_r2) / 1000.0);
+ printf("PBQP RN reductions: %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_rn) / 1000.0);
+ #endif
+
+ return;
+ }
+ }
+}
+
+void solve_pbqp_heuristical_co_ld(pbqp_t *pbqp, plist_t *rpeo)
+{
+ /* Reduce nodes degree ... */
+ initial_simplify_edges(pbqp);
+
+ /* ... and put node into bucket representing their degree. */
+ fill_node_buckets(pbqp);
+
+ #if KAPS_STATISTIC
+ FILE *fh = fopen("solutions.pb", "a");
+ fprintf(fh, "Solution");
+ fclose(fh);
+ #endif
+
+ apply_heuristic_reductions_co(pbqp, rpeo);
+
+ pbqp->solution = determine_solution(pbqp);
+
+ #if KAPS_STATISTIC
+ fh = fopen("solutions.pb", "a");
+ #if KAPS_USE_UNSIGNED
+ fprintf(fh, ": %u RE:%u R0:%u R1:%u R2:%u RM:%u RN/BF:%u\n", pbqp->solution,
+ pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
+ pbqp->num_rm, pbqp->num_rn);
+ #else
+ fprintf(fh, ": %lld RE:%u R0:%u R1:%u R2:%u RM:%u RN/BF:%u\n", pbqp->solution,
+ pbqp->num_edges, pbqp->num_r0, pbqp->num_r1, pbqp->num_r2,
+ pbqp->num_rm, pbqp->num_rn);
+ #endif
+ fclose(fh);
+ #endif
+
+ /* Solve reduced nodes. */
+ back_propagate_ld(pbqp);
+
+ free_buckets();
+}
diff --git a/ir/kaps/heuristical_co_ld.h b/ir/kaps/heuristical_co_ld.h
new file mode 100644
index 0000000..097fe3b
--- /dev/null
+++ b/ir/kaps/heuristical_co_ld.h
@@ -0,0 +1,16 @@
+/*
+ * heuristical_co_ld.h
+ *
+ * Created on: 06.05.2010
+ * Author: berschth
+ */
+
+#ifndef HEURISTICAL_CO_LD_H_
+#define HEURISTICAL_CO_LD_H_
+
+#include "pbqp_t.h"
+#include "plist.h"
+
+void solve_pbqp_heuristical_co_ld(pbqp_t *pbqp, plist_t *rpeo);
+
+#endif /* HEURISTICAL_CO_LD_H_ */
diff --git a/ir/kaps/html_dumper.c b/ir/kaps/html_dumper.c
new file mode 100644
index 0000000..93d0fd1
--- /dev/null
+++ b/ir/kaps/html_dumper.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief HTML dumper for PBQP.
+ * @date 03.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "adt/array.h"
+#include "assert.h"
+
+#include "pbqp_edge_t.h"
+#include "pbqp_node_t.h"
+#include "optimal.h"
+#include "html_dumper.h"
+#include "kaps.h"
+
+/* Caution: Due to static buffer use only once per statement */
+static const char *cost2a(num const cost)
+{
+ static char buf[10];
+
+ if (cost == INF_COSTS) return "inf";
+#if KAPS_USE_UNSIGNED
+ sprintf(buf, "%u", cost);
+#else
+ sprintf(buf, "%10lld", cost);
+#endif
+ return buf;
+}
+
+/* print vector */
+static void dump_vector(FILE *f, vector_t *vec)
+{
+ unsigned index;
+ assert(vec);
+
+ fprintf(f, "<span class=\"vector\">( ");
+ unsigned len = vec->len;
+ assert(len > 0);
+ for (index = 0; index < len; ++index) {
+#if KAPS_ENABLE_VECTOR_NAMES
+ fprintf(f, "<span title=\"%s\">%s</span> ",
+ vec->entries[index].name, cost2a(vec->entries[index].data));
+#else
+ fprintf(f, "%s ", cost2a(vec->entries[index].data));
+#endif
+ }
+ fprintf(f, " )</span>\n");
+}
+
+static void dump_matrix(FILE *f, pbqp_matrix_t *mat)
+{
+ unsigned row, col;
+ assert(mat);
+ num *p = mat->entries;
+
+ assert(mat->cols> 0);
+ assert(mat->rows> 0);
+ fprintf(f, "\t\\begin{pmatrix}\n");
+ for (row = 0; row < mat->rows; ++row) {
+ fprintf(f, "\t %s", cost2a(*p++));
+
+ for (col = 1; col < mat->cols; ++col) {
+ fprintf(f, "& %s", cost2a(*p++));
+ }
+ fprintf(f, "\\\\\n");
+ }
+ fprintf(f, "\t\\end{pmatrix}\n");
+}
+
+void dump_edge(FILE *file, pbqp_edge_t *edge)
+{
+ fputs("<tex>\n", file);
+ fprintf(file, "\t\\overline\n{C}_{%d,%d}=\n",
+ edge->src->index, edge->tgt->index);
+ dump_matrix(file, edge->costs);
+ fputs("</tex><br>", file);
+}
+
+static void dump_edge_costs(pbqp_t *pbqp)
+{
+ unsigned src_index;
+
+ assert(pbqp);
+ assert(pbqp->dump_file);
+
+ fputs("<p>", pbqp->dump_file);
+ for (src_index = 0; src_index < pbqp->num_nodes; ++src_index) {
+ pbqp_node_t *src_node = get_node(pbqp, src_index);
+
+ if (!src_node)
+ continue;
+
+ unsigned edge_index;
+ unsigned len = ARR_LEN(src_node->edges);
+ for (edge_index = 0; edge_index < len; ++edge_index) {
+ pbqp_edge_t *edge = src_node->edges[edge_index];
+ unsigned tgt_index = edge->tgt->index;
+ if (src_index < tgt_index) {
+ dump_edge(pbqp->dump_file, edge);
+ }
+ }
+ }
+ fputs("</p>", pbqp->dump_file);
+}
+
+void dump_node(FILE *file, pbqp_node_t *node)
+{
+ assert(file);
+
+ if (node) {
+ fprintf(file, "\tc<sub>%d</sub> = ", node->index);
+ dump_vector(file, node->costs);
+ fputs("<br>\n", file);
+ }
+}
+
+static void dump_node_costs(pbqp_t *pbqp)
+{
+ unsigned index;
+
+ assert(pbqp);
+ assert(pbqp->dump_file);
+
+ /* dump node costs */
+ fputs("<p>", pbqp->dump_file);
+ for (index = 0; index < pbqp->num_nodes; ++index) {
+ dump_node(pbqp->dump_file, get_node(pbqp, index));
+ }
+ fputs("</p>", pbqp->dump_file);
+}
+
+void dump_section(FILE *f, int level, const char *txt)
+{
+ assert(f);
+
+ fprintf(f, "<h%d>%s</h%d>\n", level, txt, level);
+}
+
+void pbqp_dump_graph(pbqp_t *pbqp)
+{
+ unsigned src_index;
+
+ assert(pbqp);
+ assert(pbqp->dump_file);
+
+ fputs("<p>\n<graph>\n\tgraph input {\n", pbqp->dump_file);
+ for (src_index = 0; src_index < pbqp->num_nodes; ++src_index) {
+ pbqp_node_t *node = get_node(pbqp, src_index);
+ if (node && !node_is_reduced(node)) {
+ fprintf(pbqp->dump_file, "\t n%d;\n", src_index);
+ }
+ }
+
+ for (src_index = 0; src_index < pbqp->num_nodes; ++src_index) {
+ pbqp_node_t *node = get_node(pbqp, src_index);
+
+ if (!node)
+ continue;
+
+ if (node_is_reduced(node))
+ continue;
+
+ unsigned len = ARR_LEN(node->edges);
+ unsigned edge_index;
+ for (edge_index = 0; edge_index < len; ++edge_index) {
+ pbqp_node_t *tgt_node = node->edges[edge_index]->tgt;
+ unsigned tgt_index = tgt_node->index;
+
+ if (node_is_reduced(tgt_node))
+ continue;
+
+ if (src_index < tgt_index) {
+ fprintf(pbqp->dump_file, "\t n%d -- n%d;\n", src_index,
+ tgt_index);
+ }
+ }
+ }
+ fputs("\t}\n</graph>\n</p>\n", pbqp->dump_file);
+}
+
+void pbqp_dump_input(pbqp_t *pbqp)
+{
+ assert(pbqp);
+ assert(pbqp->dump_file);
+
+ dump_section(pbqp->dump_file, 1, "1. PBQP Problem");
+ dump_section(pbqp->dump_file, 2, "1.1 Topology");
+ pbqp_dump_graph(pbqp);
+ dump_section(pbqp->dump_file, 2, "1.2 Cost Vectors");
+ dump_node_costs(pbqp);
+ dump_section(pbqp->dump_file, 2, "1.3 Cost Matrices");
+ dump_edge_costs(pbqp);
+}
+
+void dump_simplifyedge(pbqp_t *pbqp, pbqp_edge_t *edge)
+{
+ assert(pbqp);
+ assert(pbqp->dump_file);
+
+ dump_node(pbqp->dump_file, edge->src);
+ dump_edge(pbqp->dump_file, edge);
+ dump_node(pbqp->dump_file, edge->tgt);
+}
diff --git a/ir/kaps/html_dumper.h b/ir/kaps/html_dumper.h
new file mode 100644
index 0000000..7f0ac06
--- /dev/null
+++ b/ir/kaps/html_dumper.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief HTML dumper for PBQP.
+ * @date 03.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_HTML_DUMPER_H
+#define KAPS_HTML_DUMPER_H
+
+#include "pbqp_t.h"
+
+void pbqp_dump_input(pbqp_t *pbqp);
+
+void pbqp_dump_graph(pbqp_t *pbqp);
+
+void dump_simplifyedge(pbqp_t *pbqp, pbqp_edge_t *edge);
+
+void dump_section(FILE *f, int level, const char *txt);
+
+void dump_node(FILE *file, pbqp_node_t *node);
+void dump_edge(FILE *file, pbqp_edge_t *edge);
+
+#endif /* KAPS_HTML_DUMPER_H */
diff --git a/ir/kaps/kaps.c b/ir/kaps/kaps.c
new file mode 100644
index 0000000..8bbbd93
--- /dev/null
+++ b/ir/kaps/kaps.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief Partitioned Boolean Quadratic Problem (PBQP) solver.
+ * @date 02.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "adt/array.h"
+#include "adt/xmalloc.h"
+
+#include "kaps.h"
+#include "matrix.h"
+#include "pbqp_edge.h"
+#include "pbqp_edge_t.h"
+#include "pbqp_node.h"
+#include "pbqp_node_t.h"
+#include "vector.h"
+
+pbqp_node_t *get_node(pbqp_t *pbqp, unsigned index)
+{
+ return pbqp->nodes[index];
+}
+
+pbqp_edge_t *get_edge(pbqp_t *pbqp, unsigned src_index, unsigned tgt_index)
+{
+ int i;
+ int len;
+
+ if (tgt_index < src_index) {
+ unsigned tmp = src_index;
+ src_index = tgt_index;
+ tgt_index = tmp;
+ }
+
+ pbqp_node_t *src_node = get_node(pbqp, src_index);
+ pbqp_node_t *tgt_node = get_node(pbqp, tgt_index);
+ assert(src_node);
+ assert(tgt_node);
+
+ len = ARR_LEN(src_node->edges);
+
+ for (i = 0; i < len; ++i) {
+ pbqp_edge_t *cur_edge = src_node->edges[i];
+ if (cur_edge->tgt == tgt_node) {
+ return cur_edge;
+ }
+ }
+
+ return NULL;
+}
+
+pbqp_t *alloc_pbqp(unsigned number_nodes)
+{
+ pbqp_t *pbqp = XMALLOC(pbqp_t);
+
+ obstack_init(&pbqp->obstack);
+
+ pbqp->solution = 0;
+ pbqp->num_nodes = number_nodes;
+#if KAPS_DUMP
+ pbqp->dump_file = NULL;
+#endif
+ pbqp->nodes = OALLOCNZ(&pbqp->obstack, pbqp_node_t*, number_nodes);
+#if KAPS_STATISTIC
+ pbqp->num_bf = 0;
+ pbqp->num_edges = 0;
+ pbqp->num_r0 = 0;
+ pbqp->num_r1 = 0;
+ pbqp->num_r2 = 0;
+ pbqp->num_rm = 0;
+ pbqp->num_rn = 0;
+#endif
+
+ return pbqp;
+}
+
+void free_pbqp(pbqp_t *pbqp)
+{
+ obstack_free(&pbqp->obstack, NULL);
+ xfree(pbqp);
+}
+
+void add_node_costs(pbqp_t *pbqp, unsigned node_index, vector_t *costs)
+{
+ pbqp_node_t *node = get_node(pbqp, node_index);
+
+ if (node == NULL) {
+ node = alloc_node(pbqp, node_index, costs);
+ pbqp->nodes[node_index] = node;
+ } else {
+ vector_add(node->costs, costs);
+ }
+}
+
+void add_edge_costs(pbqp_t *pbqp, unsigned src_index, unsigned tgt_index,
+ pbqp_matrix_t *costs)
+{
+ pbqp_edge_t *edge = get_edge(pbqp, src_index, tgt_index);
+
+ if (tgt_index < src_index) {
+ pbqp_matrix_transpose(pbqp, costs);
+ add_edge_costs(pbqp, tgt_index, src_index, costs);
+ return;
+ }
+
+ if (edge == NULL) {
+ edge = alloc_edge(pbqp, src_index, tgt_index, costs);
+ } else {
+ pbqp_matrix_add(edge->costs, costs);
+ }
+}
+
+num get_node_solution(pbqp_t *pbqp, unsigned node_index)
+{
+ pbqp_node_t *node = get_node(pbqp, node_index);
+ assert(node);
+
+ return node->solution;
+}
+
+num get_solution(pbqp_t *pbqp)
+{
+ return pbqp->solution;
+}
+
+#if KAPS_DUMP
+void set_dumpfile(pbqp *pbqp, FILE *f)
+{
+ assert(pbqp);
+ pbqp->dump_file = f;
+}
+#endif
diff --git a/ir/kaps/kaps.h b/ir/kaps/kaps.h
new file mode 100644
index 0000000..c9097aa
--- /dev/null
+++ b/ir/kaps/kaps.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief Partitioned Boolean Quadratic Problem (PBQP) solver.
+ * @date 02.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_KAPS_H
+#define KAPS_KAPS_H
+
+#include "pbqp_t.h"
+
+/**
+ * Create an empty PBQP instance with the given number of nodes.
+ */
+pbqp_t* alloc_pbqp(unsigned number_nodes);
+
+/**
+ * Free the given PBQP.
+ */
+void free_pbqp(pbqp_t *pbqp);
+
+/**
+ * Add costs vector to given node.
+ */
+void add_node_costs(pbqp_t *pbqp, unsigned node_index, vector_t *costs);
+
+/**
+ * Add costs matrix between given nodes.
+ */
+void add_edge_costs(pbqp_t *pbqp, unsigned src_index, unsigned tgt_index,
+ pbqp_matrix_t *costs);
+
+pbqp_edge_t *get_edge(pbqp_t *pbqp, unsigned src_index, unsigned tgt_index);
+pbqp_node_t *get_node(pbqp_t *pbqp, unsigned index);
+
+num get_node_solution(pbqp_t *pbqp, unsigned node_index);
+num get_solution(pbqp_t *pbqp);
+
+void set_dumpfile(pbqp_t *pbqp, FILE *f);
+
+#endif /* KAPS_KAPS_H */
diff --git a/ir/kaps/matrix.c b/ir/kaps/matrix.c
new file mode 100644
index 0000000..8608057
--- /dev/null
+++ b/ir/kaps/matrix.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief PBQP matrix.
+ * @date 02.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "pbqp_t.h"
+#include "vector.h"
+#include "matrix.h"
+
+pbqp_matrix_t *pbqp_matrix_alloc(pbqp_t *pbqp, unsigned rows, unsigned cols)
+{
+ assert(cols> 0);
+ assert(rows> 0);
+
+ unsigned length = rows * cols;
+
+ pbqp_matrix_t *mat = (pbqp_matrix_t*)obstack_alloc(&pbqp->obstack, sizeof(*mat) + sizeof(*mat->entries) * length);
+ assert(mat);
+
+ mat->cols = cols;
+ mat->rows = rows;
+ memset(mat->entries, 0, sizeof(*mat->entries) * length);
+
+ return mat;
+}
+
+pbqp_matrix_t *pbqp_matrix_copy(pbqp_t *pbqp, pbqp_matrix_t *m)
+{
+ unsigned len = m->rows * m->cols;
+ pbqp_matrix_t *copy = (pbqp_matrix_t*)obstack_copy(&pbqp->obstack, m, sizeof(*copy) + sizeof(*copy->entries) * len);
+ assert(copy);
+
+ return copy;
+}
+
+pbqp_matrix_t *pbqp_matrix_copy_and_transpose(pbqp_t *pbqp, pbqp_matrix_t *m)
+{
+ unsigned i;
+ unsigned j;
+ unsigned cols = m->cols;
+ unsigned rows = m->rows;
+ unsigned len = rows * cols;
+ pbqp_matrix_t *copy = (pbqp_matrix_t*)obstack_alloc(&pbqp->obstack, sizeof(*copy) + sizeof(*copy->entries) * len);
+ assert(copy);
+
+ for (i = 0; i < rows; ++i) {
+ for (j = 0; j < cols; ++j) {
+ copy->entries[j*rows+i] = m->entries[i*cols+j];
+ }
+ }
+
+ copy->cols = rows;
+ copy->rows = cols;
+
+ return copy;
+}
+
+void pbqp_matrix_transpose(pbqp_t *pbqp, pbqp_matrix_t *mat)
+{
+ unsigned len;
+
+ assert(mat);
+ len = mat->rows * mat->cols;
+
+ pbqp_matrix_t *tmp = pbqp_matrix_copy_and_transpose(pbqp, mat);
+
+ memcpy(mat, tmp, sizeof(*mat) + sizeof(*mat->entries) * len);
+
+ obstack_free(&pbqp->obstack, tmp);
+}
+
+void pbqp_matrix_add(pbqp_matrix_t *sum, pbqp_matrix_t *summand)
+{
+ int i;
+ int len;
+
+ assert(sum);
+ assert(summand);
+ assert(sum->cols == summand->cols);
+ assert(sum->rows == summand->rows);
+
+ len = sum->rows * sum->cols;
+
+ for (i = 0; i < len; ++i) {
+ sum->entries[i] = pbqp_add(sum->entries[i], summand->entries[i]);
+ }
+}
+
+void pbqp_matrix_set_col_value(pbqp_matrix_t *mat, unsigned col, num value)
+{
+ unsigned row_index;
+ unsigned row_len;
+
+ assert(mat);
+ assert(col < mat->cols);
+
+ row_len = mat->rows;
+
+ for (row_index = 0; row_index < row_len; ++row_index) {
+ mat->entries[row_index * mat->cols + col] = value;
+ }
+}
+
+void pbqp_matrix_set_row_value(pbqp_matrix_t *mat, unsigned row, num value)
+{
+ unsigned col_index;
+ unsigned col_len;
+
+ assert(mat);
+ assert(row < mat->rows);
+
+ col_len = mat->cols;
+
+ for (col_index = 0; col_index < col_len; ++col_index) {
+ mat->entries[row * mat->cols + col_index] = value;
+ }
+}
+
+void pbqp_matrix_set(pbqp_matrix_t *mat, unsigned row, unsigned col, num value)
+{
+ assert(mat);
+ assert(col < mat->cols);
+ assert(row < mat->rows);
+
+ mat->entries[row * mat->cols + col] = value;
+}
+
+num pbqp_matrix_get_col_min(pbqp_matrix_t *matrix, unsigned col_index, vector_t *flags)
+{
+ unsigned row_index;
+ num min = INF_COSTS;
+
+ assert(matrix);
+ assert(flags);
+ assert(matrix->rows == flags->len);
+
+ unsigned col_len = matrix->cols;
+ unsigned row_len = matrix->rows;
+
+ for (row_index = 0; row_index < row_len; ++row_index) {
+ /* Ignore virtual deleted columns. */
+ if (flags->entries[row_index].data == INF_COSTS) continue;
+
+ num elem = matrix->entries[row_index * col_len + col_index];
+
+ if (elem < min) {
+ min = elem;
+ }
+ }
+
+ return min;
+}
+
+unsigned pbqp_matrix_get_col_min_index(pbqp_matrix_t *matrix, unsigned col_index, vector_t *flags)
+{
+ unsigned row_index;
+ unsigned min_index = 0;
+ num min = INF_COSTS;
+
+ assert(matrix);
+ assert(flags);
+ assert(matrix->rows == flags->len);
+
+ unsigned col_len = matrix->cols;
+ unsigned row_len = matrix->rows;
+
+ for (row_index = 0; row_index < row_len; ++row_index) {
+ /* Ignore virtual deleted columns. */
+ if (flags->entries[row_index].data == INF_COSTS) continue;
+
+ num elem = matrix->entries[row_index * col_len + col_index];
+
+ if (elem < min) {
+ min = elem;
+ min_index = row_index;
+ }
+ }
+
+ return min_index;
+}
+
+void pbqp_matrix_sub_col_value(pbqp_matrix_t *matrix, unsigned col_index,
+ vector_t *flags, num value)
+{
+ unsigned col_len;
+ unsigned row_index;
+ unsigned row_len;
+
+ assert(matrix);
+ assert(flags);
+ assert(matrix->rows == flags->len);
+
+ col_len = matrix->cols;
+ row_len = matrix->rows;
+
+ for (row_index = 0; row_index < row_len; ++row_index) {
+ if (flags->entries[row_index].data == INF_COSTS) {
+ matrix->entries[row_index * col_len + col_index] = 0;
+ continue;
+ }
+ /* inf - x = inf if x < inf */
+ if (matrix->entries[row_index * col_len + col_index] == INF_COSTS && value
+ != INF_COSTS)
+ continue;
+ matrix->entries[row_index * col_len + col_index] -= value;
+ }
+}
+
+num pbqp_matrix_get_row_min(pbqp_matrix_t *matrix, unsigned row_index, vector_t *flags)
+{
+ unsigned col_index;
+ num min = INF_COSTS;
+
+ assert(matrix);
+ assert(flags);
+ assert(matrix->cols == flags->len);
+
+ unsigned len = flags->len;
+
+ for (col_index = 0; col_index < len; ++col_index) {
+ /* Ignore virtual deleted columns. */
+ if (flags->entries[col_index].data == INF_COSTS) continue;
+
+ num elem = matrix->entries[row_index * len + col_index];
+
+ if (elem < min) {
+ min = elem;
+ }
+ }
+
+ return min;
+}
+
+unsigned pbqp_matrix_get_row_min_index(pbqp_matrix_t *matrix, unsigned row_index, vector_t *flags)
+{
+ unsigned col_index;
+ unsigned min_index = 0;
+ num min = INF_COSTS;
+
+ assert(matrix);
+ assert(flags);
+ assert(matrix->cols == flags->len);
+
+ unsigned len = flags->len;
+
+ for (col_index = 0; col_index < len; ++col_index) {
+ /* Ignore virtual deleted columns. */
+ if (flags->entries[col_index].data == INF_COSTS) continue;
+
+ num elem = matrix->entries[row_index * len + col_index];
+
+ if (elem < min) {
+ min = elem;
+ min_index = col_index;
+ }
+ }
+
+ return min_index;
+}
+
+void pbqp_matrix_sub_row_value(pbqp_matrix_t *matrix, unsigned row_index,
+ vector_t *flags, num value)
+{
+ unsigned col_index;
+ unsigned col_len;
+
+ assert(matrix);
+ assert(flags);
+ assert(matrix->cols == flags->len);
+
+ col_len = matrix->cols;
+
+ for (col_index = 0; col_index < col_len; ++col_index) {
+ if (flags->entries[col_index].data == INF_COSTS) {
+ matrix->entries[row_index * col_len + col_index] = 0;
+ continue;
+ }
+ /* inf - x = inf if x < inf */
+ if (matrix->entries[row_index * col_len + col_index] == INF_COSTS && value
+ != INF_COSTS)
+ continue;
+ matrix->entries[row_index * col_len + col_index] -= value;
+ }
+}
+
+int pbqp_matrix_is_zero(pbqp_matrix_t *mat, vector_t *src_vec, vector_t *tgt_vec)
+{
+ unsigned col_index;
+ unsigned col_len;
+ unsigned row_index;
+ unsigned row_len;
+
+ assert(mat);
+ assert(src_vec);
+ assert(tgt_vec);
+ assert(mat->cols = tgt_vec->len);
+ assert(mat->rows = src_vec->len);
+
+ col_len = mat->cols;
+ row_len = mat->rows;
+
+ for (row_index = 0; row_index < row_len; ++row_index) {
+ if (src_vec->entries[row_index].data == INF_COSTS) continue;
+ for (col_index = 0; col_index < col_len; ++col_index) {
+ if (tgt_vec->entries[col_index].data == INF_COSTS) continue;
+
+ if (mat->entries[row_index * col_len + col_index] != 0) {
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+void pbqp_matrix_add_to_all_cols(pbqp_matrix_t *mat, vector_t *vec)
+{
+ unsigned col_index;
+ unsigned col_len;
+ unsigned row_index;
+ unsigned row_len;
+
+ assert(mat);
+ assert(vec);
+ assert(mat->rows == vec->len);
+
+ col_len = mat->cols;
+ row_len = mat->rows;
+
+ for (row_index = 0; row_index < row_len; ++row_index) {
+ num value = vec->entries[row_index].data;
+ for (col_index = 0; col_index < col_len; ++col_index) {
+ mat->entries[row_index * col_len + col_index] = pbqp_add(
+ mat->entries[row_index * col_len + col_index], value);
+ }
+ }
+}
+
+void pbqp_matrix_add_to_all_rows(pbqp_matrix_t *mat, vector_t *vec)
+{
+ unsigned col_index;
+ unsigned col_len;
+ unsigned row_index;
+ unsigned row_len;
+
+ assert(mat);
+ assert(vec);
+ assert(mat->cols == vec->len);
+
+ col_len = mat->cols;
+ row_len = mat->rows;
+
+ for (row_index = 0; row_index < row_len; ++row_index) {
+ for (col_index = 0; col_index < col_len; ++col_index) {
+ num value = vec->entries[col_index].data;
+
+ mat->entries[row_index * col_len + col_index] = pbqp_add(mat->entries[row_index * col_len + col_index], value);
+ }
+ }
+}
diff --git a/ir/kaps/matrix.h b/ir/kaps/matrix.h
new file mode 100644
index 0000000..c87f777
--- /dev/null
+++ b/ir/kaps/matrix.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief PBQP matrix.
+ * @date 02.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_MATRIX_H
+#define KAPS_MATRIX_H
+
+#include "matrix_t.h"
+
+pbqp_matrix_t *pbqp_matrix_alloc(pbqp_t *pbqp, unsigned rows, unsigned cols);
+
+/* Copy the given matrix. */
+pbqp_matrix_t *pbqp_matrix_copy(pbqp_t *pbqp, pbqp_matrix_t *m);
+
+pbqp_matrix_t *pbqp_matrix_copy_and_transpose(pbqp_t *pbqp, pbqp_matrix_t *m);
+
+void pbqp_matrix_transpose(pbqp_t *pbqp, pbqp_matrix_t *mat);
+
+/* sum += summand */
+void pbqp_matrix_add(pbqp_matrix_t *sum, pbqp_matrix_t *summand);
+
+void pbqp_matrix_set(pbqp_matrix_t *mat, unsigned row, unsigned col, num value);
+
+num pbqp_matrix_get_col_min(pbqp_matrix_t *matrix, unsigned col_index, vector_t *flags);
+num pbqp_matrix_get_row_min(pbqp_matrix_t *matrix, unsigned row_index, vector_t *flags);
+
+unsigned pbqp_matrix_get_col_min_index(pbqp_matrix_t *matrix, unsigned col_index, vector_t *flags);
+unsigned pbqp_matrix_get_row_min_index(pbqp_matrix_t *matrix, unsigned row_index, vector_t *flags);
+
+void pbqp_matrix_set_col_value(pbqp_matrix_t *mat, unsigned col, num value);
+void pbqp_matrix_set_row_value(pbqp_matrix_t *mat, unsigned row, num value);
+
+void pbqp_matrix_sub_col_value(pbqp_matrix_t *matrix, unsigned col_index,
+ vector_t *flags, num value);
+void pbqp_matrix_sub_row_value(pbqp_matrix_t *matrix, unsigned row_index,
+ vector_t *flags, num value);
+
+int pbqp_matrix_is_zero(pbqp_matrix_t *mat, vector_t *src_vec, vector_t *tgt_vec);
+
+void pbqp_matrix_add_to_all_cols(pbqp_matrix_t *mat, vector_t *vec);
+void pbqp_matrix_add_to_all_rows(pbqp_matrix_t *mat, vector_t *vec);
+
+#endif /* KAPS_MATRIX_H */
diff --git a/ir/kaps/matrix_t.h b/ir/kaps/matrix_t.h
new file mode 100644
index 0000000..f1458c1
--- /dev/null
+++ b/ir/kaps/matrix_t.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief PBQP matrix data types.
+ * @date 02.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_MATRIX_T_H
+#define KAPS_MATRIX_T_H
+
+#include "pbqp_t.h"
+
+typedef struct pbqp_matrix_t pbqp_matrix_t;
+
+struct pbqp_matrix_t {
+ unsigned rows;
+ unsigned cols;
+ num entries[];
+};
+
+#endif /* KAPS_MATRIX_T_H */
diff --git a/ir/kaps/optimal.c b/ir/kaps/optimal.c
new file mode 100644
index 0000000..fe82844
--- /dev/null
+++ b/ir/kaps/optimal.c
@@ -0,0 +1,1465 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief Optimal reductions and helper functions.
+ * @date 28.12.2009
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "adt/array.h"
+#include "assert.h"
+#include "error.h"
+
+#include "bucket.h"
+#if KAPS_DUMP
+#include "html_dumper.h"
+#endif
+#include "kaps.h"
+#include "matrix.h"
+#include "optimal.h"
+#include "pbqp_edge.h"
+#include "pbqp_edge_t.h"
+#include "pbqp_node.h"
+#include "pbqp_node_t.h"
+#include "vector.h"
+
+#include "plist.h"
+#include "timing.h"
+
+pbqp_edge_t **edge_bucket;
+pbqp_edge_t **rm_bucket;
+pbqp_node_t **node_buckets[4];
+pbqp_node_t **reduced_bucket = NULL;
+pbqp_node_t *merged_node = NULL;
+static int buckets_filled = 0;
+
+static void insert_into_edge_bucket(pbqp_edge_t *edge)
+{
+ if (edge_bucket_contains(edge_bucket, edge)) {
+ /* Edge is already inserted. */
+ return;
+ }
+
+ edge_bucket_insert(&edge_bucket, edge);
+}
+
+static void insert_into_rm_bucket(pbqp_edge_t *edge)
+{
+ if (edge_bucket_contains(rm_bucket, edge)) {
+ /* Edge is already inserted. */
+ return;
+ }
+
+ edge_bucket_insert(&rm_bucket, edge);
+}
+
+static void init_buckets(void)
+{
+ int i;
+
+ edge_bucket_init(&edge_bucket);
+ edge_bucket_init(&rm_bucket);
+ node_bucket_init(&reduced_bucket);
+
+ for (i = 0; i < 4; ++i) {
+ node_bucket_init(&node_buckets[i]);
+ }
+}
+
+void free_buckets(void)
+{
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ node_bucket_free(&node_buckets[i]);
+ }
+
+ edge_bucket_free(&edge_bucket);
+ edge_bucket_free(&rm_bucket);
+ node_bucket_free(&reduced_bucket);
+
+ buckets_filled = 0;
+}
+
+void fill_node_buckets(pbqp_t *pbqp)
+{
+ unsigned node_index;
+ unsigned node_len;
+
+ assert(pbqp);
+ node_len = pbqp->num_nodes;
+
+ #if KAPS_TIMING
+ ir_timer_t *t_fill_buckets = ir_timer_new();
+ ir_timer_start(t_fill_buckets);
+ #endif
+
+ for (node_index = 0; node_index < node_len; ++node_index) {
+ unsigned degree;
+ pbqp_node_t *node = get_node(pbqp, node_index);
+
+ if (!node) continue;
+
+ degree = pbqp_node_get_degree(node);
+
+ /* We have only one bucket for nodes with arity >= 3. */
+ if (degree > 3) {
+ degree = 3;
+ }
+
+ node_bucket_insert(&node_buckets[degree], node);
+ }
+
+ buckets_filled = 1;
+
+ #if KAPS_TIMING
+ ir_timer_stop(t_fill_buckets);
+ printf("PBQP Fill Nodes into buckets: %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_fill_buckets) / 1000.0);
+ #endif
+}
+
+static void normalize_towards_source(pbqp_edge_t *edge)
+{
+ pbqp_matrix_t *mat;
+ pbqp_node_t *src_node;
+ pbqp_node_t *tgt_node;
+ vector_t *src_vec;
+ vector_t *tgt_vec;
+ unsigned src_len;
+ unsigned tgt_len;
+ unsigned src_index;
+ unsigned new_infinity = 0;
+
+ assert(edge);
+
+ src_node = edge->src;
+ tgt_node = edge->tgt;
+ assert(src_node);
+ assert(tgt_node);
+
+ src_vec = src_node->costs;
+ tgt_vec = tgt_node->costs;
+ assert(src_vec);
+ assert(tgt_vec);
+
+ src_len = src_vec->len;
+ tgt_len = tgt_vec->len;
+ assert(src_len > 0);
+ assert(tgt_len > 0);
+
+ mat = edge->costs;
+ assert(mat);
+
+ /* Normalize towards source node. */
+ for (src_index = 0; src_index < src_len; ++src_index) {
+ num min = pbqp_matrix_get_row_min(mat, src_index, tgt_vec);
+
+ if (min != 0) {
+ if (src_vec->entries[src_index].data == INF_COSTS) {
+ pbqp_matrix_set_row_value(mat, src_index, 0);
+ continue;
+ }
+
+ pbqp_matrix_sub_row_value(mat, src_index, tgt_vec, min);
+ src_vec->entries[src_index].data = pbqp_add(
+ src_vec->entries[src_index].data, min);
+
+ if (min == INF_COSTS) {
+ new_infinity = 1;
+ }
+ }
+ }
+
+ if (new_infinity) {
+ unsigned edge_index;
+ unsigned edge_len = pbqp_node_get_degree(src_node);
+
+ for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+ pbqp_edge_t *edge_candidate = src_node->edges[edge_index];
+
+ if (edge_candidate != edge) {
+ insert_into_edge_bucket(edge_candidate);
+ }
+ }
+ }
+}
+
+static void normalize_towards_target(pbqp_edge_t *edge)
+{
+ pbqp_matrix_t *mat;
+ pbqp_node_t *src_node;
+ pbqp_node_t *tgt_node;
+ vector_t *src_vec;
+ vector_t *tgt_vec;
+ unsigned src_len;
+ unsigned tgt_len;
+ unsigned tgt_index;
+ unsigned new_infinity = 0;
+
+ assert(edge);
+
+ src_node = edge->src;
+ tgt_node = edge->tgt;
+ assert(src_node);
+ assert(tgt_node);
+
+ src_vec = src_node->costs;
+ tgt_vec = tgt_node->costs;
+ assert(src_vec);
+ assert(tgt_vec);
+
+ src_len = src_vec->len;
+ tgt_len = tgt_vec->len;
+ assert(src_len > 0);
+ assert(tgt_len > 0);
+
+ mat = edge->costs;
+ assert(mat);
+
+ /* Normalize towards target node. */
+ for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
+ num min = pbqp_matrix_get_col_min(mat, tgt_index, src_vec);
+
+ if (min != 0) {
+ if (tgt_vec->entries[tgt_index].data == INF_COSTS) {
+ pbqp_matrix_set_col_value(mat, tgt_index, 0);
+ continue;
+ }
+
+ pbqp_matrix_sub_col_value(mat, tgt_index, src_vec, min);
+ tgt_vec->entries[tgt_index].data = pbqp_add(
+ tgt_vec->entries[tgt_index].data, min);
+
+ if (min == INF_COSTS) {
+ new_infinity = 1;
+ }
+ }
+ }
+
+ if (new_infinity) {
+ unsigned edge_index;
+ unsigned edge_len = pbqp_node_get_degree(tgt_node);
+
+ for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+ pbqp_edge_t *edge_candidate = tgt_node->edges[edge_index];
+
+ if (edge_candidate != edge) {
+ insert_into_edge_bucket(edge_candidate);
+ }
+ }
+ }
+}
+
+/**
+ * Tries to apply RM for the source node of the given edge.
+ *
+ * Checks whether the source node of edge can be merged into the target node of
+ * edge, and performs the merge, if possible.
+ */
+static void merge_source_into_target(pbqp_t *pbqp, pbqp_edge_t *edge)
+{
+ pbqp_matrix_t *mat;
+ pbqp_node_t *src_node;
+ pbqp_node_t *tgt_node;
+ vector_t *src_vec;
+ vector_t *tgt_vec;
+ unsigned *mapping;
+ unsigned src_len;
+ unsigned tgt_len;
+ unsigned src_index;
+ unsigned tgt_index;
+ unsigned edge_index;
+ unsigned edge_len;
+
+ assert(pbqp);
+ assert(edge);
+
+ src_node = edge->src;
+ tgt_node = edge->tgt;
+ assert(src_node);
+ assert(tgt_node);
+
+ src_vec = src_node->costs;
+ tgt_vec = tgt_node->costs;
+ assert(src_vec);
+ assert(tgt_vec);
+
+ src_len = src_vec->len;
+ tgt_len = tgt_vec->len;
+
+ /* Matrizes are normalized. */
+ assert(src_len > 1);
+ assert(tgt_len > 1);
+
+ mat = edge->costs;
+ assert(mat);
+
+ mapping = NEW_ARR_F(unsigned, tgt_len);
+
+ /* Check that each column has at most one zero entry. */
+ for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
+ unsigned onlyOneZero = 0;
+
+ if (tgt_vec->entries[tgt_index].data == INF_COSTS)
+ continue;
+
+ for (src_index = 0; src_index < src_len; ++src_index) {
+ if (src_vec->entries[src_index].data == INF_COSTS)
+ continue;
+
+ if (mat->entries[src_index * tgt_len + tgt_index] == INF_COSTS)
+ continue;
+
+ /* Matrix entry is finite. */
+ if (onlyOneZero) {
+ DEL_ARR_F(mapping);
+ return;
+ }
+
+ onlyOneZero = 1;
+ mapping[tgt_index] = src_index;
+ }
+ }
+
+ /* We know that we can merge the source node into the target node. */
+ edge_len = pbqp_node_get_degree(src_node);
+
+#if KAPS_STATISTIC
+ pbqp->num_rm++;
+#endif
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ char txt[100];
+ sprintf(txt, "Merging n%d into n%d", src_node->index, tgt_node->index);
+ dump_section(pbqp->dump_file, 3, txt);
+ }
+#endif
+
+ /* Reconnect the source's edges with the target node. */
+ for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+ pbqp_edge_t *old_edge = src_node->edges[edge_index];
+ pbqp_edge_t *new_edge;
+ pbqp_matrix_t *old_matrix;
+ pbqp_matrix_t *new_matrix;
+ pbqp_node_t *other_node;
+ vector_t *other_vec;
+ unsigned other_len;
+ unsigned other_index;
+ unsigned tgt_index;
+
+ assert(old_edge);
+
+ if (old_edge == edge)
+ continue;
+
+ old_matrix = old_edge->costs;
+ assert(old_matrix);
+
+ if (old_edge->tgt == src_node) {
+ other_node = old_edge->src;
+ other_len = old_matrix->rows;
+ }
+ else {
+ other_node = old_edge->tgt;
+ other_len = old_matrix->cols;
+ }
+ assert(other_node);
+ other_vec = other_node->costs;
+
+ new_matrix = pbqp_matrix_alloc(pbqp, tgt_len, other_len);
+
+ /* Source node selects the column of the old_matrix. */
+ if (old_edge->tgt == src_node) {
+ for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
+ unsigned src_index = mapping[tgt_index];
+
+ if (tgt_vec->entries[tgt_index].data == INF_COSTS)
+ continue;
+
+ for (other_index = 0; other_index < other_len; ++other_index) {
+ if (other_vec->entries[other_index].data == INF_COSTS)
+ continue;
+
+ new_matrix->entries[tgt_index*other_len+other_index] = old_matrix->entries[other_index*src_len+src_index];
+ }
+ }
+ }
+ /* Source node selects the row of the old_matrix. */
+ else {
+ for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
+ unsigned src_index = mapping[tgt_index];
+
+ if (tgt_vec->entries[tgt_index].data == INF_COSTS)
+ continue;
+
+ for (other_index = 0; other_index < other_len; ++other_index) {
+ if (other_vec->entries[other_index].data == INF_COSTS)
+ continue;
+
+ new_matrix->entries[tgt_index*other_len+other_index] = old_matrix->entries[src_index*other_len+other_index];
+ }
+ }
+ }
+
+ new_edge = get_edge(pbqp, tgt_node->index, other_node->index);
+
+ add_edge_costs(pbqp, tgt_node->index, other_node->index, new_matrix);
+
+ if (new_edge == NULL) {
+ reorder_node_after_edge_insertion(tgt_node);
+ reorder_node_after_edge_insertion(other_node);
+ }
+
+ delete_edge(old_edge);
+
+ new_edge = get_edge(pbqp, tgt_node->index, other_node->index);
+ simplify_edge(pbqp, new_edge);
+
+ insert_into_rm_bucket(new_edge);
+ }
+
+#if KAPS_STATISTIC
+ pbqp->num_r1--;
+#endif
+}
+
+/**
+ * Tries to apply RM for the target node of the given edge.
+ *
+ * Checks whether the target node of edge can be merged into the source node of
+ * edge, and performs the merge, if possible.
+ */
+static void merge_target_into_source(pbqp_t *pbqp, pbqp_edge_t *edge)
+{
+ pbqp_matrix_t *mat;
+ pbqp_node_t *src_node;
+ pbqp_node_t *tgt_node;
+ vector_t *src_vec;
+ vector_t *tgt_vec;
+ unsigned *mapping;
+ unsigned src_len;
+ unsigned tgt_len;
+ unsigned src_index;
+ unsigned tgt_index;
+ unsigned edge_index;
+ unsigned edge_len;
+
+ assert(pbqp);
+ assert(edge);
+
+ src_node = edge->src;
+ tgt_node = edge->tgt;
+ assert(src_node);
+ assert(tgt_node);
+
+ src_vec = src_node->costs;
+ tgt_vec = tgt_node->costs;
+ assert(src_vec);
+ assert(tgt_vec);
+
+ src_len = src_vec->len;
+ tgt_len = tgt_vec->len;
+
+ /* Matrizes are normalized. */
+ assert(src_len > 1);
+ assert(tgt_len > 1);
+
+ mat = edge->costs;
+ assert(mat);
+
+ mapping = NEW_ARR_F(unsigned, src_len);
+
+ /* Check that each row has at most one zero entry. */
+ for (src_index = 0; src_index < src_len; ++src_index) {
+ unsigned onlyOneZero = 0;
+
+ if (src_vec->entries[src_index].data == INF_COSTS)
+ continue;
+
+ for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
+ if (tgt_vec->entries[tgt_index].data == INF_COSTS)
+ continue;
+
+ if (mat->entries[src_index * tgt_len + tgt_index] == INF_COSTS)
+ continue;
+
+ /* Matrix entry is finite. */
+ if (onlyOneZero) {
+ DEL_ARR_F(mapping);
+ return;
+ }
+
+ onlyOneZero = 1;
+ mapping[src_index] = tgt_index;
+ }
+ }
+
+ /* We know that we can merge the target node into the source node. */
+ edge_len = pbqp_node_get_degree(tgt_node);
+
+#if KAPS_STATISTIC
+ pbqp->num_rm++;
+#endif
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ char txt[100];
+ sprintf(txt, "Merging n%d into n%d", tgt_node->index, src_node->index);
+ dump_section(pbqp->dump_file, 3, txt);
+ }
+#endif
+
+ /* Reconnect the target's edges with the source node. */
+ for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+ pbqp_edge_t *old_edge = tgt_node->edges[edge_index];
+ pbqp_edge_t *new_edge;
+ pbqp_matrix_t *old_matrix;
+ pbqp_matrix_t *new_matrix;
+ pbqp_node_t *other_node;
+ vector_t *other_vec;
+ unsigned other_len;
+ unsigned other_index;
+ unsigned src_index;
+
+ assert(old_edge);
+
+ if (old_edge == edge)
+ continue;
+
+ old_matrix = old_edge->costs;
+ assert(old_matrix);
+
+ if (old_edge->tgt == tgt_node) {
+ other_node = old_edge->src;
+ other_len = old_matrix->rows;
+ }
+ else {
+ other_node = old_edge->tgt;
+ other_len = old_matrix->cols;
+ }
+ assert(other_node);
+ other_vec = other_node->costs;
+
+ new_matrix = pbqp_matrix_alloc(pbqp, src_len, other_len);
+
+ /* Target node selects the column of the old_matrix. */
+ if (old_edge->tgt == tgt_node) {
+ for (src_index = 0; src_index < src_len; ++src_index) {
+ unsigned tgt_index = mapping[src_index];
+
+ if (src_vec->entries[src_index].data == INF_COSTS)
+ continue;
+
+ for (other_index = 0; other_index < other_len; ++other_index) {
+ if (other_vec->entries[other_index].data == INF_COSTS)
+ continue;
+
+ new_matrix->entries[src_index*other_len+other_index] = old_matrix->entries[other_index*tgt_len+tgt_index];
+ }
+ }
+ }
+ /* Source node selects the row of the old_matrix. */
+ else {
+ for (src_index = 0; src_index < src_len; ++src_index) {
+ unsigned tgt_index = mapping[src_index];
+
+ if (src_vec->entries[src_index].data == INF_COSTS)
+ continue;
+
+ for (other_index = 0; other_index < other_len; ++other_index) {
+ if (other_vec->entries[other_index].data == INF_COSTS)
+ continue;
+
+ new_matrix->entries[src_index*other_len+other_index] = old_matrix->entries[tgt_index*other_len+other_index];
+ }
+ }
+ }
+
+ new_edge = get_edge(pbqp, src_node->index, other_node->index);
+
+ add_edge_costs(pbqp, src_node->index, other_node->index, new_matrix);
+
+ if (new_edge == NULL) {
+ reorder_node_after_edge_insertion(src_node);
+ reorder_node_after_edge_insertion(other_node);
+ }
+
+ delete_edge(old_edge);
+
+ new_edge = get_edge(pbqp, src_node->index, other_node->index);
+ simplify_edge(pbqp, new_edge);
+
+ insert_into_rm_bucket(new_edge);
+ }
+
+#if KAPS_STATISTIC
+ pbqp->num_r1--;
+#endif
+}
+
+/**
+ * Merge neighbors into the given node.
+ */
+void apply_RM(pbqp_t *pbqp, pbqp_node_t *node)
+{
+ pbqp_edge_t **edges;
+ unsigned edge_index;
+ unsigned edge_len;
+
+ assert(node);
+ assert(pbqp);
+
+ edges = node->edges;
+ edge_len = pbqp_node_get_degree(node);
+
+ /* Check all incident edges. */
+ for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+ pbqp_edge_t *edge = edges[edge_index];
+
+ insert_into_rm_bucket(edge);
+ }
+
+ /* ALAP: Merge neighbors into given node. */
+ while(edge_bucket_get_length(rm_bucket) > 0) {
+ pbqp_edge_t *edge = edge_bucket_pop(&rm_bucket);
+ assert(edge);
+
+ /* If the edge is not deleted: Try a merge. */
+ if (edge->src == node)
+ merge_target_into_source(pbqp, edge);
+ else if (edge->tgt == node)
+ merge_source_into_target(pbqp, edge);
+ }
+
+ merged_node = node;
+}
+
+void reorder_node_after_edge_deletion(pbqp_node_t *node)
+{
+ unsigned degree = pbqp_node_get_degree(node);
+ /* Assume node lost one incident edge. */
+ unsigned old_degree = degree + 1;
+
+ if (!buckets_filled) return;
+
+ /* Same bucket as before */
+ if (degree > 2) return;
+
+ /* Delete node from old bucket... */
+ node_bucket_remove(&node_buckets[old_degree], node);
+
+ /* ..and add to new one. */
+ node_bucket_insert(&node_buckets[degree], node);
+}
+
+void reorder_node_after_edge_insertion(pbqp_node_t *node)
+{
+ unsigned degree = pbqp_node_get_degree(node);
+ /* Assume node lost one incident edge. */
+ unsigned old_degree = degree - 1;
+
+ if (!buckets_filled) return;
+
+ /* Same bucket as before */
+ if (old_degree > 2) return;
+
+ /* Delete node from old bucket... */
+ node_bucket_remove(&node_buckets[old_degree], node);
+
+ /* ..and add to new one. */
+ node_bucket_insert(&node_buckets[degree], node);
+}
+
+void simplify_edge(pbqp_t *pbqp, pbqp_edge_t *edge)
+{
+ pbqp_matrix_t *mat;
+ pbqp_node_t *src_node;
+ pbqp_node_t *tgt_node;
+ vector_t *src_vec;
+ vector_t *tgt_vec;
+ int src_len;
+ int tgt_len;
+
+ assert(pbqp);
+ assert(edge);
+
+ (void) pbqp;
+
+ src_node = edge->src;
+ tgt_node = edge->tgt;
+ assert(src_node);
+ assert(tgt_node);
+
+ /* If edge are already deleted, we have nothing to do. */
+ if (is_deleted(edge))
+ return;
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ char txt[100];
+ sprintf(txt, "Simplification of Edge n%d-n%d", src_node->index, tgt_node->index);
+ dump_section(pbqp->dump_file, 3, txt);
+ }
+#endif
+
+ src_vec = src_node->costs;
+ tgt_vec = tgt_node->costs;
+ assert(src_vec);
+ assert(tgt_vec);
+
+ src_len = src_vec->len;
+ tgt_len = tgt_vec->len;
+ assert(src_len > 0);
+ assert(tgt_len > 0);
+
+ mat = edge->costs;
+ assert(mat);
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ fputs("Input:<br>\n", pbqp->dump_file);
+ dump_simplifyedge(pbqp, edge);
+ }
+#endif
+
+ normalize_towards_source(edge);
+ normalize_towards_target(edge);
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ fputs("<br>\nOutput:<br>\n", pbqp->dump_file);
+ dump_simplifyedge(pbqp, edge);
+ }
+#endif
+
+ if (pbqp_matrix_is_zero(mat, src_vec, tgt_vec)) {
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ fputs("edge has been eliminated<br>\n", pbqp->dump_file);
+ }
+#endif
+
+#if KAPS_STATISTIC
+ pbqp->num_edges++;
+#endif
+
+ delete_edge(edge);
+ }
+}
+
+void initial_simplify_edges(pbqp_t *pbqp)
+{
+ unsigned node_index;
+ unsigned node_len;
+
+ assert(pbqp);
+
+ #if KAPS_TIMING
+ ir_timer_t *t_int_simpl = ir_timer_new();
+ ir_timer_start(t_int_simpl);
+ #endif
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ pbqp_dump_input(pbqp);
+ dump_section(pbqp->dump_file, 1, "2. Simplification of Cost Matrices");
+ }
+#endif
+
+ node_len = pbqp->num_nodes;
+
+ init_buckets();
+
+ /* First simplify all edges. */
+ for (node_index = 0; node_index < node_len; ++node_index) {
+ unsigned edge_index;
+ pbqp_node_t *node = get_node(pbqp, node_index);
+ pbqp_edge_t **edges;
+ unsigned edge_len;
+
+ if (!node) continue;
+
+ edges = node->edges;
+ edge_len = pbqp_node_get_degree(node);
+
+ for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+ pbqp_edge_t *edge = edges[edge_index];
+
+ /* Simplify only once per edge. */
+ if (node != edge->src) continue;
+
+ simplify_edge(pbqp, edge);
+ }
+ }
+
+ #if KAPS_TIMING
+ ir_timer_stop(t_int_simpl);
+ printf("PBQP Initial simplify edges: %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_int_simpl) / 1000.0);
+ #endif
+}
+
+num determine_solution(pbqp_t *pbqp)
+{
+ unsigned node_index;
+ unsigned node_len;
+ num solution = 0;
+
+ #if KAPS_TIMING
+ ir_timer_t *t_det_solution = ir_timer_new();
+ ir_timer_reset_and_start(t_det_solution);
+ #endif
+
+#if KAPS_DUMP
+ FILE *file;
+#endif
+
+ assert(pbqp);
+
+ (void) pbqp;
+
+#if KAPS_DUMP
+ file = pbqp->dump_file;
+
+ if (file) {
+ dump_section(file, 1, "4. Determine Solution/Minimum");
+ dump_section(file, 2, "4.1. Trivial Solution");
+ }
+#endif
+
+ /* Solve trivial nodes and calculate solution. */
+ node_len = node_bucket_get_length(node_buckets[0]);
+
+#if KAPS_STATISTIC
+ pbqp->num_r0 = node_len;
+#endif
+
+ for (node_index = 0; node_index < node_len; ++node_index) {
+ pbqp_node_t *node = node_buckets[0][node_index];
+ assert(node);
+
+ node->solution = vector_get_min_index(node->costs);
+ solution = pbqp_add(solution,
+ node->costs->entries[node->solution].data);
+
+#if KAPS_DUMP
+ if (file) {
+ fprintf(file, "node n%d is set to %d<br>\n", node->index, node->solution);
+ dump_node(file, node);
+ }
+#endif
+ }
+
+#if KAPS_DUMP
+ if (file) {
+ dump_section(file, 2, "Minimum");
+#if KAPS_USE_UNSIGNED
+ fprintf(file, "Minimum is equal to %u.", solution);
+#else
+ fprintf(file, "Minimum is equal to %lld.", solution);
+#endif
+ }
+#endif
+
+ #if KAPS_TIMING
+ ir_timer_stop(t_det_solution);
+ printf("PBQP Determine Solution: %10.3lf msec\n", (double)ir_timer_elapsed_usec(t_det_solution) / 1000.0);
+ #endif
+
+ return solution;
+}
+
+static void back_propagate_RI(pbqp_t *pbqp, pbqp_node_t *node)
+{
+ pbqp_edge_t *edge;
+ pbqp_node_t *other;
+ pbqp_matrix_t *mat;
+ vector_t *vec;
+ int is_src;
+
+ assert(pbqp);
+ assert(node);
+
+ (void) pbqp;
+
+ edge = node->edges[0];
+ mat = edge->costs;
+ is_src = edge->src == node;
+ vec = node->costs;
+
+ if (is_src) {
+ other = edge->tgt;
+ assert(other);
+
+ node->solution = pbqp_matrix_get_col_min_index(mat, other->solution, vec);
+ } else {
+ other = edge->src;
+ assert(other);
+
+ node->solution = pbqp_matrix_get_row_min_index(mat, other->solution, vec);
+ }
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
+ }
+#endif
+}
+
+static void back_propagate_RII(pbqp_t *pbqp, pbqp_node_t *node)
+{
+ pbqp_edge_t *src_edge = node->edges[0];
+ pbqp_edge_t *tgt_edge = node->edges[1];
+ int src_is_src = src_edge->src == node;
+ int tgt_is_src = tgt_edge->src == node;
+ pbqp_matrix_t *src_mat;
+ pbqp_matrix_t *tgt_mat;
+ pbqp_node_t *src_node;
+ pbqp_node_t *tgt_node;
+ vector_t *vec;
+ vector_t *node_vec;
+ unsigned col_index;
+ unsigned row_index;
+
+ assert(pbqp);
+
+ if (src_is_src) {
+ src_node = src_edge->tgt;
+ } else {
+ src_node = src_edge->src;
+ }
+
+ if (tgt_is_src) {
+ tgt_node = tgt_edge->tgt;
+ } else {
+ tgt_node = tgt_edge->src;
+ }
+
+ /* Swap nodes if necessary. */
+ if (tgt_node->index < src_node->index) {
+ pbqp_node_t *tmp_node;
+ pbqp_edge_t *tmp_edge;
+
+ tmp_node = src_node;
+ src_node = tgt_node;
+ tgt_node = tmp_node;
+
+ tmp_edge = src_edge;
+ src_edge = tgt_edge;
+ tgt_edge = tmp_edge;
+
+ src_is_src = src_edge->src == node;
+ tgt_is_src = tgt_edge->src == node;
+ }
+
+ src_mat = src_edge->costs;
+ tgt_mat = tgt_edge->costs;
+
+ node_vec = node->costs;
+
+ row_index = src_node->solution;
+ col_index = tgt_node->solution;
+
+ vec = vector_copy(pbqp, node_vec);
+
+ if (src_is_src) {
+ vector_add_matrix_col(vec, src_mat, row_index);
+ } else {
+ vector_add_matrix_row(vec, src_mat, row_index);
+ }
+
+ if (tgt_is_src) {
+ vector_add_matrix_col(vec, tgt_mat, col_index);
+ } else {
+ vector_add_matrix_row(vec, tgt_mat, col_index);
+ }
+
+ node->solution = vector_get_min_index(vec);
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ fprintf(pbqp->dump_file, "node n%d is set to %d<br>\n", node->index, node->solution);
+ }
+#endif
+
+ obstack_free(&pbqp->obstack, vec);
+}
+
+void back_propagate(pbqp_t *pbqp)
+{
+ unsigned node_index;
+ unsigned node_len = node_bucket_get_length(reduced_bucket);
+
+ assert(pbqp);
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ dump_section(pbqp->dump_file, 2, "Back Propagation");
+ }
+#endif
+
+ for (node_index = node_len; node_index > 0; --node_index) {
+ pbqp_node_t *node = reduced_bucket[node_index - 1];
+
+ switch (pbqp_node_get_degree(node)) {
+ case 1:
+ back_propagate_RI(pbqp, node);
+ break;
+ case 2:
+ back_propagate_RII(pbqp, node);
+ break;
+ default:
+ panic("Only nodes with degree one or two should be in this bucket");
+ break;
+ }
+ }
+}
+
+void apply_edge(pbqp_t *pbqp)
+{
+ pbqp_edge_t *edge = edge_bucket_pop(&edge_bucket);
+
+ simplify_edge(pbqp, edge);
+}
+
+void apply_RI(pbqp_t *pbqp)
+{
+ pbqp_node_t *node = node_bucket_pop(&node_buckets[1]);
+ pbqp_edge_t *edge = node->edges[0];
+ pbqp_matrix_t *mat = edge->costs;
+ int is_src = edge->src == node;
+ pbqp_node_t *other_node;
+
+ (void ) pbqp;
+ assert(pbqp_node_get_degree(node) == 1);
+
+ if (is_src) {
+ other_node = edge->tgt;
+ } else {
+ other_node = edge->src;
+ }
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ char txt[100];
+ sprintf(txt, "RI-Reduction of Node n%d", node->index);
+ dump_section(pbqp->dump_file, 2, txt);
+ pbqp_dump_graph(pbqp);
+ fputs("<br>\nBefore reduction:<br>\n", pbqp->dump_file);
+ dump_node(pbqp->dump_file, node);
+ dump_node(pbqp->dump_file, other_node);
+ dump_edge(pbqp->dump_file, edge);
+ }
+#endif
+
+ if (is_src) {
+ pbqp_matrix_add_to_all_cols(mat, node->costs);
+ normalize_towards_target(edge);
+ } else {
+ pbqp_matrix_add_to_all_rows(mat, node->costs);
+ normalize_towards_source(edge);
+ }
+ disconnect_edge(other_node, edge);
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ fputs("<br>\nAfter reduction:<br>\n", pbqp->dump_file);
+ dump_node(pbqp->dump_file, other_node);
+ }
+#endif
+
+ reorder_node_after_edge_deletion(other_node);
+
+#if KAPS_STATISTIC
+ pbqp->num_r1++;
+#endif
+
+ /* Add node to back propagation list. */
+ node_bucket_insert(&reduced_bucket, node);
+}
+
+void apply_RII(pbqp_t *pbqp)
+{
+ pbqp_node_t *node = node_bucket_pop(&node_buckets[2]);
+ pbqp_edge_t *src_edge = node->edges[0];
+ pbqp_edge_t *tgt_edge = node->edges[1];
+ int src_is_src = src_edge->src == node;
+ int tgt_is_src = tgt_edge->src == node;
+ pbqp_matrix_t *src_mat;
+ pbqp_matrix_t *tgt_mat;
+ pbqp_node_t *src_node;
+ pbqp_node_t *tgt_node;
+ pbqp_matrix_t *mat;
+ vector_t *vec;
+ vector_t *node_vec;
+ vector_t *src_vec;
+ vector_t *tgt_vec;
+ unsigned col_index;
+ unsigned col_len;
+ unsigned row_index;
+ unsigned row_len;
+ unsigned node_len;
+
+ assert(pbqp);
+ assert(pbqp_node_get_degree(node) == 2);
+
+ if (src_is_src) {
+ src_node = src_edge->tgt;
+ } else {
+ src_node = src_edge->src;
+ }
+
+ if (tgt_is_src) {
+ tgt_node = tgt_edge->tgt;
+ } else {
+ tgt_node = tgt_edge->src;
+ }
+
+ /* Swap nodes if necessary. */
+ if (tgt_node->index < src_node->index) {
+ pbqp_node_t *tmp_node;
+ pbqp_edge_t *tmp_edge;
+
+ tmp_node = src_node;
+ src_node = tgt_node;
+ tgt_node = tmp_node;
+
+ tmp_edge = src_edge;
+ src_edge = tgt_edge;
+ tgt_edge = tmp_edge;
+
+ src_is_src = src_edge->src == node;
+ tgt_is_src = tgt_edge->src == node;
+ }
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ char txt[100];
+ sprintf(txt, "RII-Reduction of Node n%d", node->index);
+ dump_section(pbqp->dump_file, 2, txt);
+ pbqp_dump_graph(pbqp);
+ fputs("<br>\nBefore reduction:<br>\n", pbqp->dump_file);
+ dump_node(pbqp->dump_file, src_node);
+ dump_edge(pbqp->dump_file, src_edge);
+ dump_node(pbqp->dump_file, node);
+ dump_edge(pbqp->dump_file, tgt_edge);
+ dump_node(pbqp->dump_file, tgt_node);
+ }
+#endif
+
+ src_mat = src_edge->costs;
+ tgt_mat = tgt_edge->costs;
+
+ src_vec = src_node->costs;
+ tgt_vec = tgt_node->costs;
+ node_vec = node->costs;
+
+ row_len = src_vec->len;
+ col_len = tgt_vec->len;
+ node_len = node_vec->len;
+
+ mat = pbqp_matrix_alloc(pbqp, row_len, col_len);
+
+ for (row_index = 0; row_index < row_len; ++row_index) {
+ for (col_index = 0; col_index < col_len; ++col_index) {
+ vec = vector_copy(pbqp, node_vec);
+
+ if (src_is_src) {
+ vector_add_matrix_col(vec, src_mat, row_index);
+ } else {
+ vector_add_matrix_row(vec, src_mat, row_index);
+ }
+
+ if (tgt_is_src) {
+ vector_add_matrix_col(vec, tgt_mat, col_index);
+ } else {
+ vector_add_matrix_row(vec, tgt_mat, col_index);
+ }
+
+ mat->entries[row_index * col_len + col_index] = vector_get_min(vec);
+
+ obstack_free(&pbqp->obstack, vec);
+ }
+ }
+
+ pbqp_edge_t *edge = get_edge(pbqp, src_node->index, tgt_node->index);
+
+ /* Disconnect node. */
+ disconnect_edge(src_node, src_edge);
+ disconnect_edge(tgt_node, tgt_edge);
+
+#if KAPS_STATISTIC
+ pbqp->num_r2++;
+#endif
+
+ /* Add node to back propagation list. */
+ node_bucket_insert(&reduced_bucket, node);
+
+ if (edge == NULL) {
+ edge = alloc_edge(pbqp, src_node->index, tgt_node->index, mat);
+ } else {
+ // matrix
+ pbqp_matrix_add(edge->costs, mat);
+
+ /* Free local matrix. */
+ obstack_free(&pbqp->obstack, mat);
+
+ reorder_node_after_edge_deletion(src_node);
+ reorder_node_after_edge_deletion(tgt_node);
+ }
+
+#if KAPS_DUMP
+ if (pbqp->dump_file) {
+ fputs("<br>\nAfter reduction:<br>\n", pbqp->dump_file);
+ dump_edge(pbqp->dump_file, edge);
+ }
+#endif
+
+ /* Edge has changed so we simplify it. */
+ simplify_edge(pbqp, edge);
+}
+
+static void select_column(pbqp_edge_t *edge, unsigned col_index)
+{
+ pbqp_matrix_t *mat;
+ pbqp_node_t *src_node;
+ pbqp_node_t *tgt_node;
+ vector_t *src_vec;
+ vector_t *tgt_vec;
+ unsigned src_len;
+ unsigned tgt_len;
+ unsigned src_index;
+ unsigned new_infinity = 0;
+
+ assert(edge);
+
+ src_node = edge->src;
+ tgt_node = edge->tgt;
+ assert(src_node);
+ assert(tgt_node);
+
+ src_vec = src_node->costs;
+ tgt_vec = tgt_node->costs;
+ assert(src_vec);
+ assert(tgt_vec);
+
+ src_len = src_vec->len;
+ tgt_len = tgt_vec->len;
+ assert(src_len > 0);
+ assert(tgt_len > 0);
+
+ mat = edge->costs;
+ assert(mat);
+
+ for (src_index = 0; src_index < src_len; ++src_index) {
+ num elem = mat->entries[src_index * tgt_len + col_index];
+
+ if (elem != 0) {
+ if (elem == INF_COSTS && src_vec->entries[src_index].data != INF_COSTS)
+ new_infinity = 1;
+
+ src_vec->entries[src_index].data = pbqp_add(
+ src_vec->entries[src_index].data, elem);
+ }
+ }
+
+ if (new_infinity) {
+ unsigned edge_index;
+ unsigned edge_len = pbqp_node_get_degree(src_node);
+
+ for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+ pbqp_edge_t *edge_candidate = src_node->edges[edge_index];
+
+ if (edge_candidate != edge) {
+ insert_into_edge_bucket(edge_candidate);
+ }
+ }
+ }
+
+ delete_edge(edge);
+}
+
+static void select_row(pbqp_edge_t *edge, unsigned row_index)
+{
+ pbqp_matrix_t *mat;
+ pbqp_node_t *src_node;
+ pbqp_node_t *tgt_node;
+ vector_t *tgt_vec;
+ unsigned tgt_len;
+ unsigned tgt_index;
+ unsigned new_infinity = 0;
+
+ assert(edge);
+
+ src_node = edge->src;
+ tgt_node = edge->tgt;
+ assert(tgt_node);
+
+ tgt_vec = tgt_node->costs;
+ assert(tgt_vec);
+
+ tgt_len = tgt_vec->len;
+ assert(tgt_len > 0);
+
+ mat = edge->costs;
+ assert(mat);
+
+ for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
+ num elem = mat->entries[row_index * tgt_len + tgt_index];
+
+ if (elem != 0) {
+ if (elem == INF_COSTS && tgt_vec->entries[tgt_index].data != INF_COSTS)
+ new_infinity = 1;
+
+ tgt_vec->entries[tgt_index].data = pbqp_add(
+ tgt_vec->entries[tgt_index].data, elem);
+ }
+ }
+
+ if (new_infinity) {
+ unsigned edge_index;
+ unsigned edge_len = pbqp_node_get_degree(tgt_node);
+
+ for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+ pbqp_edge_t *edge_candidate = tgt_node->edges[edge_index];
+
+ if (edge_candidate != edge) {
+ insert_into_edge_bucket(edge_candidate);
+ }
+ }
+ }
+
+ delete_edge(edge);
+}
+
+void select_alternative(pbqp_node_t *node, unsigned selected_index)
+{
+ unsigned edge_index;
+ unsigned node_index;
+ unsigned node_len;
+ vector_t *node_vec;
+ unsigned max_degree = pbqp_node_get_degree(node);
+
+ assert(node);
+ node->solution = selected_index;
+ node_vec = node->costs;
+ node_len = node_vec->len;
+ assert(selected_index < node_len);
+
+ /* Set all other costs to infinity. */
+ for (node_index = 0; node_index < node_len; ++node_index) {
+ if (node_index != selected_index) {
+ node_vec->entries[node_index].data = INF_COSTS;
+ }
+ }
+
+ /* Select corresponding row/column for incident edges. */
+ for (edge_index = 0; edge_index < max_degree; ++edge_index) {
+ pbqp_edge_t *edge = node->edges[edge_index];
+
+ if (edge->src == node)
+ select_row(edge, selected_index);
+ else
+ select_column(edge, selected_index);
+ }
+}
+
+pbqp_node_t *get_node_with_max_degree(void)
+{
+ pbqp_node_t **bucket = node_buckets[3];
+ unsigned bucket_len = node_bucket_get_length(bucket);
+ unsigned bucket_index;
+ unsigned max_degree = 0;
+ pbqp_node_t *result = NULL;
+
+ for (bucket_index = 0; bucket_index < bucket_len; ++bucket_index) {
+ pbqp_node_t *candidate = bucket[bucket_index];
+ unsigned degree = pbqp_node_get_degree(candidate);
+
+ if (degree > max_degree) {
+ result = candidate;
+ max_degree = degree;
+ }
+ }
+
+ return result;
+}
+
+unsigned get_local_minimal_alternative(pbqp_t *pbqp, pbqp_node_t *node)
+{
+ pbqp_edge_t *edge;
+ vector_t *node_vec;
+ vector_t *vec;
+ pbqp_matrix_t *mat;
+ unsigned edge_index;
+ unsigned max_degree;
+ unsigned node_index;
+ unsigned node_len;
+ unsigned min_index = 0;
+ num min = INF_COSTS;
+ int is_src;
+
+ assert(pbqp);
+ assert(node);
+ node_vec = node->costs;
+ node_len = node_vec->len;
+ max_degree = pbqp_node_get_degree(node);
+
+ for (node_index = 0; node_index < node_len; ++node_index) {
+ num value = node_vec->entries[node_index].data;
+
+ for (edge_index = 0; edge_index < max_degree; ++edge_index) {
+ edge = node->edges[edge_index];
+ mat = edge->costs;
+ is_src = edge->src == node;
+
+ if (is_src) {
+ vec = vector_copy(pbqp, edge->tgt->costs);
+ vector_add_matrix_row(vec, mat, node_index);
+ } else {
+ vec = vector_copy(pbqp, edge->src->costs);
+ vector_add_matrix_col(vec, mat, node_index);
+ }
+
+ value = pbqp_add(value, vector_get_min(vec));
+
+ obstack_free(&pbqp->obstack, vec);
+ }
+
+ if (value < min) {
+ min = value;
+ min_index = node_index;
+ }
+ }
+
+ return min_index;
+}
+
+int node_is_reduced(pbqp_node_t *node)
+{
+ if (!reduced_bucket) return 0;
+
+ if (pbqp_node_get_degree(node) == 0) return 1;
+
+ return node_bucket_contains(reduced_bucket, node);
+}
diff --git a/ir/kaps/optimal.h b/ir/kaps/optimal.h
new file mode 100644
index 0000000..ec7b026
--- /dev/null
+++ b/ir/kaps/optimal.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief Heuristic PBQP solver.
+ * @date 28.12.2009
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_OPTIMAL_H
+#define KAPS_OPTIMAL_H
+
+#include "pbqp_t.h"
+
+extern pbqp_edge_t **edge_bucket;
+extern pbqp_node_t **node_buckets[4];
+extern pbqp_node_t **reduced_bucket;
+extern pbqp_node_t *merged_node;
+
+void apply_edge(pbqp_t *pbqp);
+
+void apply_RI(pbqp_t *pbqp);
+void apply_RII(pbqp_t *pbqp);
+void apply_RM(pbqp_t *pbqp, pbqp_node_t *node);
+
+void back_propagate(pbqp_t *pbqp);
+num determine_solution(pbqp_t *pbqp);
+void fill_node_buckets(pbqp_t *pbqp);
+void free_buckets(void);
+unsigned get_local_minimal_alternative(pbqp_t *pbqp, pbqp_node_t *node);
+pbqp_node_t *get_node_with_max_degree(void);
+void initial_simplify_edges(pbqp_t *pbqp);
+void select_alternative(pbqp_node_t *node, unsigned selected_index);
+void simplify_edge(pbqp_t *pbqp, pbqp_edge_t *edge);
+void reorder_node_after_edge_deletion(pbqp_node_t *node);
+void reorder_node_after_edge_insertion(pbqp_node_t *node);
+
+int node_is_reduced(pbqp_node_t *node);
+
+#endif /* KAPS_OPTIMAL_H */
diff --git a/ir/kaps/pbqp_edge.c b/ir/kaps/pbqp_edge.c
new file mode 100644
index 0000000..8a1d0c4
--- /dev/null
+++ b/ir/kaps/pbqp_edge.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief PBQP edges.
+ * @date 02.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "adt/array.h"
+#include "assert.h"
+
+#include "kaps.h"
+#include "matrix.h"
+#include "optimal.h"
+#include "pbqp_edge.h"
+#include "pbqp_edge_t.h"
+#include "pbqp_node.h"
+#include "pbqp_node_t.h"
+#include "pbqp_t.h"
+
+pbqp_edge_t *alloc_edge(pbqp_t *pbqp, int src_index, int tgt_index,
+ pbqp_matrix_t *costs)
+{
+ int transpose = 0;
+
+ if (tgt_index < src_index) {
+ int tmp = src_index;
+ src_index = tgt_index;
+ tgt_index = tmp;
+
+ transpose = 1;
+ }
+
+ pbqp_edge_t *edge = OALLOC(&pbqp->obstack, pbqp_edge_t);
+ assert(edge);
+
+ pbqp_node_t *src_node = get_node(pbqp, src_index);
+ assert(src_node);
+
+ pbqp_node_t *tgt_node = get_node(pbqp, tgt_index);
+ assert(tgt_node);
+
+ if (transpose) {
+ edge->costs = pbqp_matrix_copy_and_transpose(pbqp, costs);
+ } else {
+ edge->costs = pbqp_matrix_copy(pbqp, costs);
+ }
+
+ /*
+ * Connect edge with incident nodes. Since the edge is allocated, we know
+ * that it don't appear in the edge lists of the nodes.
+ */
+ ARR_APP1(pbqp_edge_t *, src_node->edges, edge);
+ edge->src = src_node;
+ ARR_APP1(pbqp_edge_t *, tgt_node->edges, edge);
+ edge->tgt = tgt_node;
+ edge->bucket_index = UINT_MAX;
+
+ return edge;
+}
+
+void delete_edge(pbqp_edge_t *edge)
+{
+ pbqp_node_t *src_node;
+ pbqp_node_t *tgt_node;
+
+ assert(edge);
+
+ src_node = edge->src;
+ tgt_node = edge->tgt;
+ assert(src_node);
+ assert(tgt_node);
+
+ disconnect_edge(src_node, edge);
+ disconnect_edge(tgt_node, edge);
+
+ edge->src = NULL;
+ edge->tgt = NULL;
+
+ reorder_node_after_edge_deletion(src_node);
+ reorder_node_after_edge_deletion(tgt_node);
+}
+
+unsigned is_deleted(pbqp_edge_t *edge)
+{
+ unsigned deleted;
+
+ assert(edge);
+
+ deleted = (edge->src == NULL) && (edge-> tgt == NULL);
+
+ return deleted;
+}
+
+pbqp_edge_t *pbqp_edge_deep_copy(pbqp_t *pbqp, pbqp_edge_t *edge,
+ pbqp_node_t *src_node, pbqp_node_t *tgt_node)
+{
+ pbqp_edge_t *copy = OALLOC(&pbqp->obstack, pbqp_edge_t);
+ assert(src_node);
+ assert(tgt_node);
+
+ copy->costs = pbqp_matrix_copy(pbqp, edge->costs);
+
+ /* Connect edge with incident nodes. */
+ copy->src = src_node;
+ copy->tgt = tgt_node;
+ copy->bucket_index = UINT_MAX;
+
+ return copy;
+}
diff --git a/ir/kaps/pbqp_edge.h b/ir/kaps/pbqp_edge.h
new file mode 100644
index 0000000..1e649a2
--- /dev/null
+++ b/ir/kaps/pbqp_edge.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief PBQP edges.
+ * @date 02.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_PBQP_EDGE_H
+#define KAPS_PBQP_EDGE_H
+
+#include "pbqp_t.h"
+
+pbqp_edge_t *alloc_edge(pbqp_t *pbqp, int src_index, int tgt_index,
+ pbqp_matrix_t *costs);
+
+pbqp_edge_t *pbqp_edge_deep_copy(pbqp_t *pbqp, pbqp_edge_t *edge,
+ pbqp_node_t *src_node, pbqp_node_t *tgt_node);
+
+void delete_edge(pbqp_edge_t *edge);
+unsigned is_deleted(pbqp_edge_t *edge);
+
+#endif /* KAPS_PBQP_EDGE_H */
diff --git a/ir/kaps/pbqp_edge_t.h b/ir/kaps/pbqp_edge_t.h
new file mode 100644
index 0000000..02f0248
--- /dev/null
+++ b/ir/kaps/pbqp_edge_t.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief PBQP edge data types.
+ * @date 02.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_PBQP_EDGE_T_H
+#define KAPS_PBQP_EDGE_T_H
+
+#include "pbqp_t.h"
+
+struct pbqp_edge_t {
+ pbqp_node_t *src; /* Source index. */
+ pbqp_node_t *tgt; /* Target index. */
+ pbqp_matrix_t *costs; /* Cost matrix. */
+ unsigned bucket_index; /* Index of edge bucket. */
+};
+
+#endif /* KAPS_PBQP_EDGE_T_H */
diff --git a/ir/kaps/pbqp_node.c b/ir/kaps/pbqp_node.c
new file mode 100644
index 0000000..bb8a352
--- /dev/null
+++ b/ir/kaps/pbqp_node.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief PBQP nodes.
+ * @date 02.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include "adt/array.h"
+
+#include "assert.h"
+
+#include "bucket.h"
+#include "pbqp_edge.h"
+#include "pbqp_edge_t.h"
+#include "pbqp_node.h"
+#include "pbqp_node_t.h"
+#include "vector.h"
+
+pbqp_node_t *alloc_node(pbqp_t *pbqp, unsigned node_index, vector_t *costs)
+{
+ pbqp_node_t *node = OALLOC(&pbqp->obstack, pbqp_node_t);
+ assert(node);
+
+ node->edges = NEW_ARR_F(pbqp_edge_t *, 0);
+ node->costs = vector_copy(pbqp, costs);
+ node->bucket_index = UINT_MAX;
+ node->solution = UINT_MAX;
+ node->index = node_index;
+
+ return node;
+}
+
+int is_connected(pbqp_node_t *node, pbqp_edge_t *edge)
+{
+ pbqp_edge_t **edges;
+ unsigned edge_index;
+ unsigned edge_len;
+
+ assert(node);
+ assert(edge);
+
+ if (edge->src != node && edge->tgt != node) return 0;
+
+ edges = node->edges;
+ edge_len = ARR_LEN(edges);
+
+ for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+ pbqp_edge_t *edge_candidate = edges[edge_index];
+ if (edge_candidate == edge) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+void disconnect_edge(pbqp_node_t *node, pbqp_edge_t *edge)
+{
+ pbqp_edge_t **edges;
+ unsigned edge_index;
+ unsigned edge_len;
+
+ edges = node->edges;
+ edge_len = ARR_LEN(edges);
+
+ for (edge_index = 0; edge_index < edge_len; ++edge_index) {
+ pbqp_edge_t *edge_candidate = edges[edge_index];
+ if (edge_candidate == edge) {
+ edges[edge_index] = edges[edge_len - 1];
+ ARR_SHRINKLEN(edges, (int)edge_len - 1);
+ break;
+ }
+ }
+}
+
+unsigned pbqp_node_get_degree(pbqp_node_t *node)
+{
+ assert(node);
+ return ARR_LEN(node->edges);
+}
+
+pbqp_node_t *pbqp_node_deep_copy(pbqp_t *pbqp, pbqp_node_bucket_t new_bucket,
+ pbqp_node_t *node)
+{
+ unsigned edge_index;
+ unsigned edge_length = pbqp_node_get_degree(node);
+ pbqp_node_t *copy = OALLOC(&pbqp->obstack, pbqp_node_t);
+
+ assert(copy);
+
+ copy->edges = NEW_ARR_F(pbqp_edge_t *, 0);
+ for (edge_index = 0; edge_index < edge_length; ++edge_index) {
+ pbqp_edge_t *edge_copy = NULL;
+ pbqp_edge_t *edge = node->edges[edge_index];
+ int is_src = edge->src == node;
+
+ if (is_src) {
+ unsigned other_index = edge->tgt->bucket_index;
+ unsigned is_copied = other_index < node->bucket_index;
+
+ if (is_copied) {
+ pbqp_node_t *other_copy = new_bucket[other_index];
+ unsigned degree = pbqp_node_get_degree(other_copy);
+ unsigned index;
+
+ for (index = 0; index < degree; ++index) {
+ if (other_copy->edges[index]->src == node) {
+ edge_copy = other_copy->edges[index];
+ edge_copy->src = copy;
+ break;
+ }
+ }
+ } else {
+ edge_copy = pbqp_edge_deep_copy(pbqp, edge, copy, edge->tgt);
+ }
+ } else {
+ unsigned other_index = edge->src->bucket_index;
+ unsigned is_copied = other_index < node->bucket_index;
+
+ if (is_copied) {
+ pbqp_node_t *other_copy = new_bucket[other_index];
+ unsigned degree = pbqp_node_get_degree(other_copy);
+ unsigned index;
+
+ for (index = 0; index < degree; ++index) {
+ if (other_copy->edges[index]->tgt == node) {
+ edge_copy = other_copy->edges[index];
+ edge_copy->tgt = copy;
+ break;
+ }
+ }
+ } else {
+ edge_copy = pbqp_edge_deep_copy(pbqp, edge, edge->src, copy);
+ }
+ }
+ ARR_APP1(pbqp_edge_t *, copy->edges, edge_copy);
+ }
+ copy->costs = vector_copy(pbqp, node->costs);
+ copy->bucket_index = node->bucket_index;
+ copy->solution = node->solution;
+ copy->index = node->index;
+
+ return copy;
+}
diff --git a/ir/kaps/pbqp_node.h b/ir/kaps/pbqp_node.h
new file mode 100644
index 0000000..a543907
--- /dev/null
+++ b/ir/kaps/pbqp_node.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief PBQP nodes.
+ * @date 02.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_PBQP_NODE_H
+#define KAPS_PBQP_NODE_H
+
+#include "bucket_t.h"
+#include "pbqp_t.h"
+
+pbqp_node_t *alloc_node(pbqp_t *pbqp, unsigned node_index, vector_t *costs);
+
+void disconnect_edge(pbqp_node_t *node, pbqp_edge_t *edge);
+
+int is_connected(pbqp_node_t *node, pbqp_edge_t *edge);
+
+unsigned pbqp_node_get_degree(pbqp_node_t *node);
+
+pbqp_node_t *pbqp_node_deep_copy(pbqp_t *pbqp, pbqp_node_bucket_t new_bucket,
+ pbqp_node_t *node);
+
+#endif /* KAPS_PBQP_NODE_H */
diff --git a/ir/kaps/pbqp_node_t.h b/ir/kaps/pbqp_node_t.h
new file mode 100644
index 0000000..4cd06fa
--- /dev/null
+++ b/ir/kaps/pbqp_node_t.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief PBQP node data types.
+ * @date 02.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_PBQP_NODE_T_H
+#define KAPS_PBQP_NODE_T_H
+
+#include "pbqp_t.h"
+
+struct pbqp_node_t {
+ pbqp_edge_t **edges;
+ vector_t *costs;
+ unsigned bucket_index;
+ unsigned solution;
+ unsigned index;
+};
+
+#endif /* KAPS_PBQP_NODE_T_H */
diff --git a/ir/kaps/pbqp_t.h b/ir/kaps/pbqp_t.h
new file mode 100644
index 0000000..11cb51c
--- /dev/null
+++ b/ir/kaps/pbqp_t.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief PBQP data types.
+ * @date 02.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_PBQP_T_H
+#define KAPS_PBQP_T_H
+
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "adt/obstack.h"
+
+#define KAPS_DUMP 0
+#define KAPS_ENABLE_VECTOR_NAMES 0
+#define KAPS_STATISTIC 0
+#define KAPS_TIMING 0
+#define KAPS_USE_UNSIGNED 1
+
+#if KAPS_USE_UNSIGNED
+ typedef unsigned num;
+ static const num INF_COSTS = UINT_MAX;
+#else
+ typedef intmax_t num;
+ static const num INF_COSTS = INTMAX_MAX;
+#endif
+
+#include "matrix_t.h"
+#include "vector_t.h"
+
+typedef struct pbqp_edge_t pbqp_edge_t;
+typedef struct pbqp_node_t pbqp_node_t;
+typedef struct pbqp_t pbqp_t;
+
+struct pbqp_t {
+ struct obstack obstack; /* Obstack. */
+ num solution; /* Computed solution. */
+ size_t num_nodes; /* Number of PBQP nodes. */
+ pbqp_node_t **nodes; /* Nodes of PBQP. */
+ FILE *dump_file; /* File to dump in. */
+#if KAPS_STATISTIC
+ unsigned num_bf; /* Number of brute force reductions. */
+ unsigned num_edges; /* Number of independent edges. */
+ unsigned num_r0; /* Number of trivial solved nodes. */
+ unsigned num_r1; /* Number of R1 reductions. */
+ unsigned num_r2; /* Number of R2 reductions. */
+ unsigned num_rm; /* Number of RM reductions. */
+ unsigned num_rn; /* Number of RN reductions. */
+#endif
+};
+
+#endif /* KAPS_PBQP_T_H */
diff --git a/ir/kaps/vector.c b/ir/kaps/vector.c
new file mode 100644
index 0000000..04d58e6
--- /dev/null
+++ b/ir/kaps/vector.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief PBQP vector.
+ * @date 02.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+
+#include <string.h>
+
+#include "adt/array.h"
+
+#include "vector.h"
+
+num pbqp_add(num x, num y)
+{
+ if (x == INF_COSTS || y == INF_COSTS) return INF_COSTS;
+
+ num res = x + y;
+
+#if !KAPS_USE_UNSIGNED
+ /* No positive overflow. */
+ assert(x < 0 || y < 0 || res >= x);
+ assert(x < 0 || y < 0 || res >= y);
+#endif
+
+ /* No negative overflow. */
+ assert(x > 0 || y > 0 || res <= x);
+ assert(x > 0 || y > 0 || res <= y);
+
+ /* Result is not infinity.*/
+ assert(res < INF_COSTS);
+
+ return res;
+}
+
+vector_t *vector_alloc(pbqp_t *pbqp, unsigned length)
+{
+ assert(length > 0);
+ vector_t *vec = (vector_t*)obstack_alloc(&pbqp->obstack, sizeof(*vec) + sizeof(*vec->entries) * length);
+ assert(vec);
+
+ vec->len = length;
+ memset(vec->entries, 0, sizeof(*vec->entries) * length);
+
+ return vec;
+}
+
+vector_t *vector_copy(pbqp_t *pbqp, vector_t *v)
+{
+ unsigned len = v->len;
+ vector_t *copy = (vector_t*)obstack_copy(&pbqp->obstack, v, sizeof(*copy) + sizeof(*copy->entries) * len);
+ assert(copy);
+
+ return copy;
+}
+
+void vector_add(vector_t *sum, vector_t *summand)
+{
+ int i;
+ int len;
+
+ assert(sum);
+ assert(summand);
+ assert(sum->len == summand->len);
+
+ len = sum->len;
+
+ for (i = 0; i < len; ++i) {
+ sum->entries[i].data = pbqp_add(sum->entries[i].data,
+ summand->entries[i].data);
+ }
+}
+
+void vector_set(vector_t *vec, unsigned index, num value)
+{
+ assert(index < vec->len);
+ vec->entries[index].data = value;
+}
+
+#if KAPS_ENABLE_VECTOR_NAMES
+void vector_set_description(vector_t *vec, unsigned index, const char *name)
+{
+ assert(index < vec->len);
+ vec->entries[index].name = name;
+}
+#endif
+
+void vector_add_value(vector_t *vec, num value)
+{
+ unsigned index;
+ unsigned len;
+
+ assert(vec);
+
+ len = vec->len;
+
+ for (index = 0; index < len; ++index) {
+ vec->entries[index].data = pbqp_add(vec->entries[index].data, value);
+ }
+}
+
+void vector_add_matrix_col(vector_t *vec, pbqp_matrix_t *mat, unsigned col_index)
+{
+ unsigned index;
+ unsigned len;
+
+ assert(vec);
+ assert(mat);
+ assert(vec->len == mat->rows);
+ assert(col_index < mat->cols);
+
+ len = vec->len;
+
+ for (index = 0; index < len; ++index) {
+ vec->entries[index].data = pbqp_add(vec->entries[index].data, mat->entries[index * mat->cols + col_index]);
+ }
+}
+
+void vector_add_matrix_row(vector_t *vec, pbqp_matrix_t *mat, unsigned row_index)
+{
+ unsigned index;
+ unsigned len;
+
+ assert(vec);
+ assert(mat);
+ assert(vec->len == mat->cols);
+ assert(row_index < mat->rows);
+
+ len = vec->len;
+
+ for (index = 0; index < len; ++index) {
+ vec->entries[index].data = pbqp_add(vec->entries[index].data,
+ mat->entries[row_index * mat->cols + index]);
+ }
+}
+
+num vector_get_min(vector_t *vec)
+{
+ unsigned index;
+ unsigned len;
+ num min = INF_COSTS;
+
+ assert(vec);
+
+ len = vec->len;
+ assert(len > 0);
+
+ for (index = 0; index < len; ++index) {
+ num elem = vec->entries[index].data;
+
+ if (elem < min) {
+ min = elem;
+ }
+ }
+
+ return min;
+}
+
+unsigned vector_get_min_index(vector_t *vec)
+{
+ unsigned index;
+ unsigned len;
+ unsigned min_index = 0;
+ num min = INF_COSTS;
+
+ assert(vec);
+
+ len = vec->len;
+ assert(len > 0);
+
+ for (index = 0; index < len; ++index) {
+ num elem = vec->entries[index].data;
+
+ if (elem < min) {
+ min = elem;
+ min_index = index;
+ }
+ }
+
+ return min_index;
+}
diff --git a/ir/kaps/vector.h b/ir/kaps/vector.h
new file mode 100644
index 0000000..d54aaea
--- /dev/null
+++ b/ir/kaps/vector.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief PBQP vector.
+ * @date 02.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#ifndef KAPS_VECTOR_H
+#define KAPS_VECTOR_H
+
+#include "vector_t.h"
+
+num pbqp_add(num x, num y);
+
+vector_t *vector_alloc(pbqp_t *pbqp, unsigned length);
+
+/* Copy the given vector. */
+vector_t *vector_copy(pbqp_t *pbqp, vector_t *v);
+
+/* sum += summand */
+void vector_add(vector_t *sum, vector_t *summand);
+
+void vector_set(vector_t *vec, unsigned index, num value);
+
+#if KAPS_ENABLE_VECTOR_NAMES
+void vector_set_description(vector_t *vec, unsigned index, const char *name);
+#endif
+
+void vector_add_value(vector_t *vec, num value);
+
+void vector_add_matrix_col(vector_t *vec, pbqp_matrix_t *mat, unsigned col_index);
+void vector_add_matrix_row(vector_t *vec, pbqp_matrix_t *mat, unsigned row_index);
+
+num vector_get_min(vector_t *vec);
+unsigned vector_get_min_index(vector_t *vec);
+
+#endif /* KAPS_VECTOR_H */
diff --git a/ir/kaps/vector_t.h b/ir/kaps/vector_t.h
new file mode 100644
index 0000000..03692d1
--- /dev/null
+++ b/ir/kaps/vector_t.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief PBQP vector data types.
+ * @date 02.10.2008
+ * @author Sebastian Buchwald
+ * @version $Id$
+ */
+#include "config.h"
+#ifndef KAPS_VECTOR_T_H
+#define KAPS_VECTOR_T_H
+
+#include "pbqp_t.h"
+
+typedef struct vec_elem_t vec_elem_t;
+
+struct vec_elem_t {
+ num data;
+#if KAPS_ENABLE_VECTOR_NAMES
+ const char *name;
+#endif
+};
+
+typedef struct vector_t vector_t;
+
+struct vector_t {
+ unsigned len;
+ vec_elem_t entries[];
+};
+
+#endif /* KAPS_VECTOR_T_H */