--- /dev/null
--- /dev/null
++/*
++ * 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();
++}
--- /dev/null
--- /dev/null
++/*
++ * 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 */
--- /dev/null
--- /dev/null
++/*
++ * 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]));
++ }
++}
--- /dev/null
--- /dev/null
++/*
++ * 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 */
--- /dev/null
--- /dev/null
++/*
++ * 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 */
--- /dev/null
--- /dev/null
++/*
++ * 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();
++}
--- /dev/null
--- /dev/null
++/*
++ * 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 */
--- /dev/null
--- /dev/null
++/*
++ * 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();
++}
--- /dev/null
--- /dev/null
++/*
++ * 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 */
--- /dev/null
--- /dev/null
++/*
++ * 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();
++}
--- /dev/null
--- /dev/null
++/*
++ * 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_ */
--- /dev/null
--- /dev/null
++/*
++ * 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);
++}
--- /dev/null
--- /dev/null
++/*
++ * 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 */
--- /dev/null
--- /dev/null
++/*
++ * 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
--- /dev/null
--- /dev/null
++/*
++ * 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 */
--- /dev/null
--- /dev/null
++/*
++ * 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);
++ }
++ }
++}
--- /dev/null
--- /dev/null
++/*
++ * 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 */
--- /dev/null
--- /dev/null
++/*
++ * 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 */
--- /dev/null
--- /dev/null
++/*
++ * 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);
++}
--- /dev/null
--- /dev/null
++/*
++ * 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 */
--- /dev/null
--- /dev/null
++/*
++ * 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;
++}
--- /dev/null
--- /dev/null
++/*
++ * 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 */
--- /dev/null
--- /dev/null
++/*
++ * 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 */
--- /dev/null
--- /dev/null
++/*
++ * 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;
++}
--- /dev/null
--- /dev/null
++/*
++ * 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 */
--- /dev/null
--- /dev/null
++/*
++ * 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 */
--- /dev/null
--- /dev/null
++/*
++ * 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 */
--- /dev/null
--- /dev/null
++/*
++ * 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;
++}
--- /dev/null
--- /dev/null
++/*
++ * 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 */
--- /dev/null
--- /dev/null
++/*
++ * 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 */