2010-01-26 05:49:58 +01:00
|
|
|
//===-- HeuristicSolver.h - Heuristic PBQP Solver --------------*- C++ -*-===//
|
2009-08-07 02:25:12 +02:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Heuristic PBQP solver. This solver is able to perform optimal reductions for
|
|
|
|
// nodes of degree 0, 1 or 2. For nodes of degree >2 a plugable heuristic is
|
|
|
|
// used to to select a node for reduction.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2009-08-07 01:32:48 +02:00
|
|
|
#ifndef LLVM_CODEGEN_PBQP_HEURISTICSOLVER_H
|
|
|
|
#define LLVM_CODEGEN_PBQP_HEURISTICSOLVER_H
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
#include "Graph.h"
|
|
|
|
#include "Solution.h"
|
2009-08-16 00:28:08 +02:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2010-01-26 05:49:58 +01:00
|
|
|
#include <vector>
|
2009-08-07 01:32:48 +02:00
|
|
|
#include <limits>
|
|
|
|
|
|
|
|
namespace PBQP {
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
/// \brief Heuristic PBQP solver implementation.
|
|
|
|
///
|
|
|
|
/// This class should usually be created (and destroyed) indirectly via a call
|
|
|
|
/// to HeuristicSolver<HImpl>::solve(Graph&).
|
|
|
|
/// See the comments for HeuristicSolver.
|
|
|
|
///
|
|
|
|
/// HeuristicSolverImpl provides the R0, R1 and R2 reduction rules,
|
|
|
|
/// backpropagation phase, and maintains the internal copy of the graph on
|
|
|
|
/// which the reduction is carried out (the original being kept to facilitate
|
|
|
|
/// backpropagation).
|
|
|
|
template <typename HImpl>
|
|
|
|
class HeuristicSolverImpl {
|
2009-08-07 01:32:48 +02:00
|
|
|
private:
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
typedef typename HImpl::NodeData HeuristicNodeData;
|
|
|
|
typedef typename HImpl::EdgeData HeuristicEdgeData;
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
typedef std::list<Graph::EdgeItr> SolverEdges;
|
2009-08-07 01:32:48 +02:00
|
|
|
|
|
|
|
public:
|
2010-01-26 05:49:58 +01:00
|
|
|
|
|
|
|
/// \brief Iterator type for edges in the solver graph.
|
|
|
|
typedef SolverEdges::iterator SolverEdgeItr;
|
2009-08-07 01:32:48 +02:00
|
|
|
|
|
|
|
private:
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
class NodeData {
|
|
|
|
public:
|
|
|
|
NodeData() : solverDegree(0) {}
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
HeuristicNodeData& getHeuristicData() { return hData; }
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
SolverEdgeItr addSolverEdge(Graph::EdgeItr eItr) {
|
|
|
|
++solverDegree;
|
|
|
|
return solverEdges.insert(solverEdges.end(), eItr);
|
|
|
|
}
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
void removeSolverEdge(SolverEdgeItr seItr) {
|
|
|
|
--solverDegree;
|
|
|
|
solverEdges.erase(seItr);
|
|
|
|
}
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
SolverEdgeItr solverEdgesBegin() { return solverEdges.begin(); }
|
|
|
|
SolverEdgeItr solverEdgesEnd() { return solverEdges.end(); }
|
|
|
|
unsigned getSolverDegree() const { return solverDegree; }
|
|
|
|
void clearSolverEdges() {
|
|
|
|
solverDegree = 0;
|
|
|
|
solverEdges.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
HeuristicNodeData hData;
|
|
|
|
unsigned solverDegree;
|
|
|
|
SolverEdges solverEdges;
|
|
|
|
};
|
|
|
|
|
|
|
|
class EdgeData {
|
|
|
|
public:
|
|
|
|
HeuristicEdgeData& getHeuristicData() { return hData; }
|
|
|
|
|
|
|
|
void setN1SolverEdgeItr(SolverEdgeItr n1SolverEdgeItr) {
|
|
|
|
this->n1SolverEdgeItr = n1SolverEdgeItr;
|
|
|
|
}
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
SolverEdgeItr getN1SolverEdgeItr() { return n1SolverEdgeItr; }
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
void setN2SolverEdgeItr(SolverEdgeItr n2SolverEdgeItr){
|
|
|
|
this->n2SolverEdgeItr = n2SolverEdgeItr;
|
|
|
|
}
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
SolverEdgeItr getN2SolverEdgeItr() { return n2SolverEdgeItr; }
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
private:
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
HeuristicEdgeData hData;
|
|
|
|
SolverEdgeItr n1SolverEdgeItr, n2SolverEdgeItr;
|
|
|
|
};
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
Graph &g;
|
|
|
|
HImpl h;
|
|
|
|
Solution s;
|
|
|
|
std::vector<Graph::NodeItr> stack;
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-02-09 01:45:48 +01:00
|
|
|
typedef std::list<NodeData> NodeDataList;
|
|
|
|
NodeDataList nodeDataList;
|
|
|
|
|
|
|
|
typedef std::list<EdgeData> EdgeDataList;
|
|
|
|
EdgeDataList edgeDataList;
|
2009-08-07 01:32:48 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
/// \brief Construct a heuristic solver implementation to solve the given
|
|
|
|
/// graph.
|
|
|
|
/// @param g The graph representing the problem instance to be solved.
|
|
|
|
HeuristicSolverImpl(Graph &g) : g(g), h(*this) {}
|
|
|
|
|
|
|
|
/// \brief Get the graph being solved by this solver.
|
|
|
|
/// @return The graph representing the problem instance being solved by this
|
|
|
|
/// solver.
|
|
|
|
Graph& getGraph() { return g; }
|
|
|
|
|
|
|
|
/// \brief Get the heuristic data attached to the given node.
|
|
|
|
/// @param nItr Node iterator.
|
|
|
|
/// @return The heuristic data attached to the given node.
|
|
|
|
HeuristicNodeData& getHeuristicNodeData(Graph::NodeItr nItr) {
|
|
|
|
return getSolverNodeData(nItr).getHeuristicData();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Get the heuristic data attached to the given edge.
|
|
|
|
/// @param eItr Edge iterator.
|
|
|
|
/// @return The heuristic data attached to the given node.
|
|
|
|
HeuristicEdgeData& getHeuristicEdgeData(Graph::EdgeItr eItr) {
|
|
|
|
return getSolverEdgeData(eItr).getHeuristicData();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Begin iterator for the set of edges adjacent to the given node in
|
|
|
|
/// the solver graph.
|
|
|
|
/// @param nItr Node iterator.
|
|
|
|
/// @return Begin iterator for the set of edges adjacent to the given node
|
|
|
|
/// in the solver graph.
|
|
|
|
SolverEdgeItr solverEdgesBegin(Graph::NodeItr nItr) {
|
|
|
|
return getSolverNodeData(nItr).solverEdgesBegin();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief End iterator for the set of edges adjacent to the given node in
|
|
|
|
/// the solver graph.
|
|
|
|
/// @param nItr Node iterator.
|
|
|
|
/// @return End iterator for the set of edges adjacent to the given node in
|
|
|
|
/// the solver graph.
|
|
|
|
SolverEdgeItr solverEdgesEnd(Graph::NodeItr nItr) {
|
|
|
|
return getSolverNodeData(nItr).solverEdgesEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Remove a node from the solver graph.
|
|
|
|
/// @param eItr Edge iterator for edge to be removed.
|
|
|
|
///
|
|
|
|
/// Does <i>not</i> notify the heuristic of the removal. That should be
|
|
|
|
/// done manually if necessary.
|
|
|
|
void removeSolverEdge(Graph::EdgeItr eItr) {
|
|
|
|
EdgeData &eData = getSolverEdgeData(eItr);
|
|
|
|
NodeData &n1Data = getSolverNodeData(g.getEdgeNode1(eItr)),
|
|
|
|
&n2Data = getSolverNodeData(g.getEdgeNode2(eItr));
|
|
|
|
|
|
|
|
n1Data.removeSolverEdge(eData.getN1SolverEdgeItr());
|
|
|
|
n2Data.removeSolverEdge(eData.getN2SolverEdgeItr());
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Compute a solution to the PBQP problem instance with which this
|
|
|
|
/// heuristic solver was constructed.
|
|
|
|
/// @return A solution to the PBQP problem.
|
|
|
|
///
|
|
|
|
/// Performs the full PBQP heuristic solver algorithm, including setup,
|
|
|
|
/// calls to the heuristic (which will call back to the reduction rules in
|
|
|
|
/// this class), and cleanup.
|
|
|
|
Solution computeSolution() {
|
|
|
|
setup();
|
|
|
|
h.setup();
|
|
|
|
h.reduce();
|
|
|
|
backpropagate();
|
|
|
|
h.cleanup();
|
|
|
|
cleanup();
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Add to the end of the stack.
|
|
|
|
/// @param nItr Node iterator to add to the reduction stack.
|
|
|
|
void pushToStack(Graph::NodeItr nItr) {
|
|
|
|
getSolverNodeData(nItr).clearSolverEdges();
|
|
|
|
stack.push_back(nItr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Returns the solver degree of the given node.
|
|
|
|
/// @param nItr Node iterator for which degree is requested.
|
|
|
|
/// @return Node degree in the <i>solver</i> graph (not the original graph).
|
|
|
|
unsigned getSolverDegree(Graph::NodeItr nItr) {
|
|
|
|
return getSolverNodeData(nItr).getSolverDegree();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Set the solution of the given node.
|
|
|
|
/// @param nItr Node iterator to set solution for.
|
|
|
|
/// @param selection Selection for node.
|
|
|
|
void setSolution(const Graph::NodeItr &nItr, unsigned selection) {
|
|
|
|
s.setSelection(nItr, selection);
|
|
|
|
|
|
|
|
for (Graph::AdjEdgeItr aeItr = g.adjEdgesBegin(nItr),
|
|
|
|
aeEnd = g.adjEdgesEnd(nItr);
|
|
|
|
aeItr != aeEnd; ++aeItr) {
|
|
|
|
Graph::EdgeItr eItr(*aeItr);
|
|
|
|
Graph::NodeItr anItr(g.getEdgeOtherNode(eItr, nItr));
|
|
|
|
getSolverNodeData(anItr).addSolverEdge(eItr);
|
|
|
|
}
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
/// \brief Apply rule R0.
|
|
|
|
/// @param nItr Node iterator for node to apply R0 to.
|
|
|
|
///
|
|
|
|
/// Node will be automatically pushed to the solver stack.
|
|
|
|
void applyR0(Graph::NodeItr nItr) {
|
|
|
|
assert(getSolverNodeData(nItr).getSolverDegree() == 0 &&
|
|
|
|
"R0 applied to node with degree != 0.");
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
// Nothing to do. Just push the node onto the reduction stack.
|
|
|
|
pushToStack(nItr);
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
/// \brief Apply rule R1.
|
|
|
|
/// @param nItr Node iterator for node to apply R1 to.
|
|
|
|
///
|
|
|
|
/// Node will be automatically pushed to the solver stack.
|
|
|
|
void applyR1(Graph::NodeItr xnItr) {
|
|
|
|
NodeData &nd = getSolverNodeData(xnItr);
|
|
|
|
assert(nd.getSolverDegree() == 1 &&
|
|
|
|
"R1 applied to node with degree != 1.");
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
Graph::EdgeItr eItr = *nd.solverEdgesBegin();
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
const Matrix &eCosts = g.getEdgeCosts(eItr);
|
|
|
|
const Vector &xCosts = g.getNodeCosts(xnItr);
|
|
|
|
|
|
|
|
// Duplicate a little to avoid transposing matrices.
|
|
|
|
if (xnItr == g.getEdgeNode1(eItr)) {
|
|
|
|
Graph::NodeItr ynItr = g.getEdgeNode2(eItr);
|
|
|
|
Vector &yCosts = g.getNodeCosts(ynItr);
|
|
|
|
for (unsigned j = 0; j < yCosts.getLength(); ++j) {
|
|
|
|
PBQPNum min = eCosts[0][j] + xCosts[0];
|
|
|
|
for (unsigned i = 1; i < xCosts.getLength(); ++i) {
|
|
|
|
PBQPNum c = eCosts[i][j] + xCosts[i];
|
|
|
|
if (c < min)
|
|
|
|
min = c;
|
|
|
|
}
|
|
|
|
yCosts[j] += min;
|
|
|
|
}
|
|
|
|
h.handleRemoveEdge(eItr, ynItr);
|
|
|
|
} else {
|
|
|
|
Graph::NodeItr ynItr = g.getEdgeNode1(eItr);
|
|
|
|
Vector &yCosts = g.getNodeCosts(ynItr);
|
|
|
|
for (unsigned i = 0; i < yCosts.getLength(); ++i) {
|
|
|
|
PBQPNum min = eCosts[i][0] + xCosts[0];
|
|
|
|
for (unsigned j = 1; j < xCosts.getLength(); ++j) {
|
|
|
|
PBQPNum c = eCosts[i][j] + xCosts[j];
|
|
|
|
if (c < min)
|
|
|
|
min = c;
|
|
|
|
}
|
|
|
|
yCosts[i] += min;
|
|
|
|
}
|
|
|
|
h.handleRemoveEdge(eItr, ynItr);
|
|
|
|
}
|
|
|
|
removeSolverEdge(eItr);
|
|
|
|
assert(nd.getSolverDegree() == 0 &&
|
|
|
|
"Degree 1 with edge removed should be 0.");
|
|
|
|
pushToStack(xnItr);
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
/// \brief Apply rule R2.
|
|
|
|
/// @param nItr Node iterator for node to apply R2 to.
|
|
|
|
///
|
|
|
|
/// Node will be automatically pushed to the solver stack.
|
|
|
|
void applyR2(Graph::NodeItr xnItr) {
|
|
|
|
assert(getSolverNodeData(xnItr).getSolverDegree() == 2 &&
|
|
|
|
"R2 applied to node with degree != 2.");
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
NodeData &nd = getSolverNodeData(xnItr);
|
|
|
|
const Vector &xCosts = g.getNodeCosts(xnItr);
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
SolverEdgeItr aeItr = nd.solverEdgesBegin();
|
|
|
|
Graph::EdgeItr yxeItr = *aeItr,
|
|
|
|
zxeItr = *(++aeItr);
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
Graph::NodeItr ynItr = g.getEdgeOtherNode(yxeItr, xnItr),
|
|
|
|
znItr = g.getEdgeOtherNode(zxeItr, xnItr);
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
bool flipEdge1 = (g.getEdgeNode1(yxeItr) == xnItr),
|
|
|
|
flipEdge2 = (g.getEdgeNode1(zxeItr) == xnItr);
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
const Matrix *yxeCosts = flipEdge1 ?
|
|
|
|
new Matrix(g.getEdgeCosts(yxeItr).transpose()) :
|
|
|
|
&g.getEdgeCosts(yxeItr);
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
const Matrix *zxeCosts = flipEdge2 ?
|
|
|
|
new Matrix(g.getEdgeCosts(zxeItr).transpose()) :
|
|
|
|
&g.getEdgeCosts(zxeItr);
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
unsigned xLen = xCosts.getLength(),
|
|
|
|
yLen = yxeCosts->getRows(),
|
|
|
|
zLen = zxeCosts->getRows();
|
|
|
|
|
|
|
|
Matrix delta(yLen, zLen);
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
for (unsigned i = 0; i < yLen; ++i) {
|
|
|
|
for (unsigned j = 0; j < zLen; ++j) {
|
|
|
|
PBQPNum min = (*yxeCosts)[i][0] + (*zxeCosts)[j][0] + xCosts[0];
|
|
|
|
for (unsigned k = 1; k < xLen; ++k) {
|
|
|
|
PBQPNum c = (*yxeCosts)[i][k] + (*zxeCosts)[j][k] + xCosts[k];
|
|
|
|
if (c < min) {
|
|
|
|
min = c;
|
|
|
|
}
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
2010-01-26 05:49:58 +01:00
|
|
|
delta[i][j] = min;
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
2010-01-26 05:49:58 +01:00
|
|
|
}
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
if (flipEdge1)
|
|
|
|
delete yxeCosts;
|
|
|
|
|
|
|
|
if (flipEdge2)
|
|
|
|
delete zxeCosts;
|
|
|
|
|
|
|
|
Graph::EdgeItr yzeItr = g.findEdge(ynItr, znItr);
|
|
|
|
bool addedEdge = false;
|
|
|
|
|
|
|
|
if (yzeItr == g.edgesEnd()) {
|
|
|
|
yzeItr = g.addEdge(ynItr, znItr, delta);
|
|
|
|
addedEdge = true;
|
|
|
|
} else {
|
|
|
|
Matrix &yzeCosts = g.getEdgeCosts(yzeItr);
|
|
|
|
h.preUpdateEdgeCosts(yzeItr);
|
|
|
|
if (ynItr == g.getEdgeNode1(yzeItr)) {
|
|
|
|
yzeCosts += delta;
|
|
|
|
} else {
|
|
|
|
yzeCosts += delta.transpose();
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
bool nullCostEdge = tryNormaliseEdgeMatrix(yzeItr);
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
if (!addedEdge) {
|
|
|
|
// If we modified the edge costs let the heuristic know.
|
|
|
|
h.postUpdateEdgeCosts(yzeItr);
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
2010-01-26 05:49:58 +01:00
|
|
|
|
|
|
|
if (nullCostEdge) {
|
|
|
|
// If this edge ended up null remove it.
|
|
|
|
if (!addedEdge) {
|
|
|
|
// We didn't just add it, so we need to notify the heuristic
|
|
|
|
// and remove it from the solver.
|
|
|
|
h.handleRemoveEdge(yzeItr, ynItr);
|
|
|
|
h.handleRemoveEdge(yzeItr, znItr);
|
|
|
|
removeSolverEdge(yzeItr);
|
|
|
|
}
|
|
|
|
g.removeEdge(yzeItr);
|
|
|
|
} else if (addedEdge) {
|
|
|
|
// If the edge was added, and non-null, finish setting it up, add it to
|
|
|
|
// the solver & notify heuristic.
|
2010-02-09 01:45:48 +01:00
|
|
|
edgeDataList.push_back(EdgeData());
|
|
|
|
g.setEdgeData(yzeItr, &edgeDataList.back());
|
2010-01-26 05:49:58 +01:00
|
|
|
addSolverEdge(yzeItr);
|
|
|
|
h.handleAddEdge(yzeItr);
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
h.handleRemoveEdge(yxeItr, ynItr);
|
|
|
|
removeSolverEdge(yxeItr);
|
|
|
|
h.handleRemoveEdge(zxeItr, znItr);
|
|
|
|
removeSolverEdge(zxeItr);
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
pushToStack(xnItr);
|
|
|
|
}
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
private:
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
NodeData& getSolverNodeData(Graph::NodeItr nItr) {
|
|
|
|
return *static_cast<NodeData*>(g.getNodeData(nItr));
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
EdgeData& getSolverEdgeData(Graph::EdgeItr eItr) {
|
|
|
|
return *static_cast<EdgeData*>(g.getEdgeData(eItr));
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
void addSolverEdge(Graph::EdgeItr eItr) {
|
|
|
|
EdgeData &eData = getSolverEdgeData(eItr);
|
|
|
|
NodeData &n1Data = getSolverNodeData(g.getEdgeNode1(eItr)),
|
|
|
|
&n2Data = getSolverNodeData(g.getEdgeNode2(eItr));
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
eData.setN1SolverEdgeItr(n1Data.addSolverEdge(eItr));
|
|
|
|
eData.setN2SolverEdgeItr(n2Data.addSolverEdge(eItr));
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
void setup() {
|
|
|
|
if (h.solverRunSimplify()) {
|
|
|
|
simplify();
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
// Create node data objects.
|
|
|
|
for (Graph::NodeItr nItr = g.nodesBegin(), nEnd = g.nodesEnd();
|
2010-02-09 01:45:48 +01:00
|
|
|
nItr != nEnd; ++nItr) {
|
|
|
|
nodeDataList.push_back(NodeData());
|
|
|
|
g.setNodeData(nItr, &nodeDataList.back());
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
// Create edge data objects.
|
|
|
|
for (Graph::EdgeItr eItr = g.edgesBegin(), eEnd = g.edgesEnd();
|
2010-02-09 01:45:48 +01:00
|
|
|
eItr != eEnd; ++eItr) {
|
|
|
|
edgeDataList.push_back(EdgeData());
|
|
|
|
g.setEdgeData(eItr, &edgeDataList.back());
|
2010-01-26 05:49:58 +01:00
|
|
|
addSolverEdge(eItr);
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
void simplify() {
|
|
|
|
disconnectTrivialNodes();
|
|
|
|
eliminateIndependentEdges();
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
// Eliminate trivial nodes.
|
|
|
|
void disconnectTrivialNodes() {
|
|
|
|
unsigned numDisconnected = 0;
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
for (Graph::NodeItr nItr = g.nodesBegin(), nEnd = g.nodesEnd();
|
|
|
|
nItr != nEnd; ++nItr) {
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
if (g.getNodeCosts(nItr).getLength() == 1) {
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
std::vector<Graph::EdgeItr> edgesToRemove;
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
for (Graph::AdjEdgeItr aeItr = g.adjEdgesBegin(nItr),
|
|
|
|
aeEnd = g.adjEdgesEnd(nItr);
|
|
|
|
aeItr != aeEnd; ++aeItr) {
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
Graph::EdgeItr eItr = *aeItr;
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
if (g.getEdgeNode1(eItr) == nItr) {
|
|
|
|
Graph::NodeItr otherNodeItr = g.getEdgeNode2(eItr);
|
|
|
|
g.getNodeCosts(otherNodeItr) +=
|
|
|
|
g.getEdgeCosts(eItr).getRowAsVector(0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Graph::NodeItr otherNodeItr = g.getEdgeNode1(eItr);
|
|
|
|
g.getNodeCosts(otherNodeItr) +=
|
|
|
|
g.getEdgeCosts(eItr).getColAsVector(0);
|
|
|
|
}
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
edgesToRemove.push_back(eItr);
|
|
|
|
}
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
if (!edgesToRemove.empty())
|
|
|
|
++numDisconnected;
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
while (!edgesToRemove.empty()) {
|
|
|
|
g.removeEdge(edgesToRemove.back());
|
|
|
|
edgesToRemove.pop_back();
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
void eliminateIndependentEdges() {
|
|
|
|
std::vector<Graph::EdgeItr> edgesToProcess;
|
|
|
|
unsigned numEliminated = 0;
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
for (Graph::EdgeItr eItr = g.edgesBegin(), eEnd = g.edgesEnd();
|
|
|
|
eItr != eEnd; ++eItr) {
|
|
|
|
edgesToProcess.push_back(eItr);
|
|
|
|
}
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
while (!edgesToProcess.empty()) {
|
|
|
|
if (tryToEliminateEdge(edgesToProcess.back()))
|
|
|
|
++numEliminated;
|
|
|
|
edgesToProcess.pop_back();
|
|
|
|
}
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
bool tryToEliminateEdge(Graph::EdgeItr eItr) {
|
|
|
|
if (tryNormaliseEdgeMatrix(eItr)) {
|
|
|
|
g.removeEdge(eItr);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
bool tryNormaliseEdgeMatrix(Graph::EdgeItr &eItr) {
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
Matrix &edgeCosts = g.getEdgeCosts(eItr);
|
|
|
|
Vector &uCosts = g.getNodeCosts(g.getEdgeNode1(eItr)),
|
|
|
|
&vCosts = g.getNodeCosts(g.getEdgeNode2(eItr));
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
for (unsigned r = 0; r < edgeCosts.getRows(); ++r) {
|
|
|
|
PBQPNum rowMin = edgeCosts.getRowMin(r);
|
|
|
|
uCosts[r] += rowMin;
|
|
|
|
if (rowMin != std::numeric_limits<PBQPNum>::infinity()) {
|
|
|
|
edgeCosts.subFromRow(r, rowMin);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
edgeCosts.setRow(r, 0);
|
|
|
|
}
|
|
|
|
}
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
for (unsigned c = 0; c < edgeCosts.getCols(); ++c) {
|
|
|
|
PBQPNum colMin = edgeCosts.getColMin(c);
|
|
|
|
vCosts[c] += colMin;
|
|
|
|
if (colMin != std::numeric_limits<PBQPNum>::infinity()) {
|
|
|
|
edgeCosts.subFromCol(c, colMin);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
edgeCosts.setCol(c, 0);
|
|
|
|
}
|
|
|
|
}
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
return edgeCosts.isZero();
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
void backpropagate() {
|
|
|
|
while (!stack.empty()) {
|
|
|
|
computeSolution(stack.back());
|
|
|
|
stack.pop_back();
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
void computeSolution(Graph::NodeItr nItr) {
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
NodeData &nodeData = getSolverNodeData(nItr);
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
Vector v(g.getNodeCosts(nItr));
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
// Solve based on existing solved edges.
|
|
|
|
for (SolverEdgeItr solvedEdgeItr = nodeData.solverEdgesBegin(),
|
|
|
|
solvedEdgeEnd = nodeData.solverEdgesEnd();
|
|
|
|
solvedEdgeItr != solvedEdgeEnd; ++solvedEdgeItr) {
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
Graph::EdgeItr eItr(*solvedEdgeItr);
|
|
|
|
Matrix &edgeCosts = g.getEdgeCosts(eItr);
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
if (nItr == g.getEdgeNode1(eItr)) {
|
|
|
|
Graph::NodeItr adjNode(g.getEdgeNode2(eItr));
|
|
|
|
unsigned adjSolution = s.getSelection(adjNode);
|
|
|
|
v += edgeCosts.getColAsVector(adjSolution);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Graph::NodeItr adjNode(g.getEdgeNode1(eItr));
|
|
|
|
unsigned adjSolution = s.getSelection(adjNode);
|
|
|
|
v += edgeCosts.getRowAsVector(adjSolution);
|
|
|
|
}
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
}
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
setSolution(nItr, v.minIndex());
|
2009-08-07 01:32:48 +02:00
|
|
|
}
|
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
void cleanup() {
|
|
|
|
h.cleanup();
|
2010-02-09 01:45:48 +01:00
|
|
|
nodeDataList.clear();
|
|
|
|
edgeDataList.clear();
|
2010-01-26 05:49:58 +01:00
|
|
|
}
|
|
|
|
};
|
2009-08-07 01:32:48 +02:00
|
|
|
|
2010-01-26 05:49:58 +01:00
|
|
|
/// \brief PBQP heuristic solver class.
|
|
|
|
///
|
|
|
|
/// Given a PBQP Graph g representing a PBQP problem, you can find a solution
|
|
|
|
/// by calling
|
|
|
|
/// <tt>Solution s = HeuristicSolver<H>::solve(g);</tt>
|
|
|
|
///
|
|
|
|
/// The choice of heuristic for the H parameter will affect both the solver
|
|
|
|
/// speed and solution quality. The heuristic should be chosen based on the
|
|
|
|
/// nature of the problem being solved.
|
|
|
|
/// Currently the only solver included with LLVM is the Briggs heuristic for
|
|
|
|
/// register allocation.
|
|
|
|
template <typename HImpl>
|
|
|
|
class HeuristicSolver {
|
|
|
|
public:
|
|
|
|
static Solution solve(Graph &g) {
|
|
|
|
HeuristicSolverImpl<HImpl> hs(g);
|
|
|
|
return hs.computeSolution();
|
|
|
|
}
|
|
|
|
};
|
2009-08-07 01:32:48 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // LLVM_CODEGEN_PBQP_HEURISTICSOLVER_H
|