2010-01-26 05:49:58 +01:00
|
|
|
//===-- HeuristcBase.h --- Heuristic base class for PBQP --------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef LLVM_CODEGEN_PBQP_HEURISTICBASE_H
|
|
|
|
#define LLVM_CODEGEN_PBQP_HEURISTICBASE_H
|
|
|
|
|
|
|
|
#include "HeuristicSolver.h"
|
|
|
|
|
|
|
|
namespace PBQP {
|
|
|
|
|
|
|
|
/// \brief Abstract base class for heuristic implementations.
|
|
|
|
///
|
|
|
|
/// This class provides a handy base for heuristic implementations with common
|
|
|
|
/// solver behaviour implemented for a number of methods.
|
|
|
|
///
|
|
|
|
/// To implement your own heuristic using this class as a base you'll have to
|
|
|
|
/// implement, as a minimum, the following methods:
|
|
|
|
/// <ul>
|
|
|
|
/// <li> void addToHeuristicList(Graph::NodeItr) : Add a node to the
|
|
|
|
/// heuristic reduction list.
|
|
|
|
/// <li> void heuristicReduce() : Perform a single heuristic reduction.
|
|
|
|
/// <li> void preUpdateEdgeCosts(Graph::EdgeItr) : Handle the (imminent)
|
|
|
|
/// change to the cost matrix on the given edge (by R2).
|
|
|
|
/// <li> void postUpdateEdgeCostts(Graph::EdgeItr) : Handle the new
|
|
|
|
/// costs on the given edge.
|
|
|
|
/// <li> void handleAddEdge(Graph::EdgeItr) : Handle the addition of a new
|
|
|
|
/// edge into the PBQP graph (by R2).
|
|
|
|
/// <li> void handleRemoveEdge(Graph::EdgeItr, Graph::NodeItr) : Handle the
|
|
|
|
/// disconnection of the given edge from the given node.
|
|
|
|
/// <li> A constructor for your derived class : to pass back a reference to
|
|
|
|
/// the solver which is using this heuristic.
|
|
|
|
/// </ul>
|
|
|
|
///
|
|
|
|
/// These methods are implemented in this class for documentation purposes,
|
|
|
|
/// but will assert if called.
|
|
|
|
///
|
|
|
|
/// Note that this class uses the curiously recursive template idiom to
|
|
|
|
/// forward calls to the derived class. These methods need not be made
|
|
|
|
/// virtual, and indeed probably shouldn't for performance reasons.
|
|
|
|
///
|
|
|
|
/// You'll also need to provide NodeData and EdgeData structs in your class.
|
|
|
|
/// These can be used to attach data relevant to your heuristic to each
|
|
|
|
/// node/edge in the PBQP graph.
|
|
|
|
|
|
|
|
template <typename HImpl>
|
|
|
|
class HeuristicBase {
|
|
|
|
private:
|
|
|
|
|
|
|
|
typedef std::list<Graph::NodeItr> OptimalList;
|
|
|
|
|
|
|
|
HeuristicSolverImpl<HImpl> &s;
|
|
|
|
Graph &g;
|
|
|
|
OptimalList optimalList;
|
|
|
|
|
|
|
|
// Return a reference to the derived heuristic.
|
|
|
|
HImpl& impl() { return static_cast<HImpl&>(*this); }
|
|
|
|
|
|
|
|
// Add the given node to the optimal reductions list. Keep an iterator to
|
|
|
|
// its location for fast removal.
|
|
|
|
void addToOptimalReductionList(Graph::NodeItr nItr) {
|
|
|
|
optimalList.insert(optimalList.end(), nItr);
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
/// \brief Construct an instance with a reference to the given solver.
|
|
|
|
/// @param solver The solver which is using this heuristic instance.
|
|
|
|
HeuristicBase(HeuristicSolverImpl<HImpl> &solver)
|
|
|
|
: s(solver), g(s.getGraph()) { }
|
|
|
|
|
|
|
|
/// \brief Get the solver which is using this heuristic instance.
|
|
|
|
/// @return The solver which is using this heuristic instance.
|
|
|
|
///
|
|
|
|
/// You can use this method to get access to the solver in your derived
|
|
|
|
/// heuristic implementation.
|
|
|
|
HeuristicSolverImpl<HImpl>& getSolver() { return s; }
|
|
|
|
|
|
|
|
/// \brief Get the graph representing the problem to be solved.
|
|
|
|
/// @return The graph representing the problem to be solved.
|
|
|
|
Graph& getGraph() { return g; }
|
|
|
|
|
|
|
|
/// \brief Tell the solver to simplify the graph before the reduction phase.
|
|
|
|
/// @return Whether or not the solver should run a simplification phase
|
|
|
|
/// prior to the main setup and reduction.
|
|
|
|
///
|
|
|
|
/// HeuristicBase returns true from this method as it's a sensible default,
|
|
|
|
/// however you can over-ride it in your derived class if you want different
|
|
|
|
/// behaviour.
|
|
|
|
bool solverRunSimplify() const { return true; }
|
|
|
|
|
|
|
|
/// \brief Decide whether a node should be optimally or heuristically
|
|
|
|
/// reduced.
|
|
|
|
/// @return Whether or not the given node should be listed for optimal
|
|
|
|
/// reduction (via R0, R1 or R2).
|
|
|
|
///
|
|
|
|
/// HeuristicBase returns true for any node with degree less than 3. This is
|
|
|
|
/// sane and sensible for many situations, but not all. You can over-ride
|
|
|
|
/// this method in your derived class if you want a different selection
|
|
|
|
/// criteria. Note however that your criteria for selecting optimal nodes
|
|
|
|
/// should be <i>at least</i> as strong as this. I.e. Nodes of degree 3 or
|
|
|
|
/// higher should not be selected under any circumstances.
|
|
|
|
bool shouldOptimallyReduce(Graph::NodeItr nItr) {
|
|
|
|
if (g.getNodeDegree(nItr) < 3)
|
|
|
|
return true;
|
|
|
|
// else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Add the given node to the list of nodes to be optimally reduced.
|
|
|
|
/// @return nItr Node iterator to be added.
|
|
|
|
///
|
|
|
|
/// You probably don't want to over-ride this, except perhaps to record
|
|
|
|
/// statistics before calling this implementation. HeuristicBase relies on
|
|
|
|
/// its behaviour.
|
|
|
|
void addToOptimalReduceList(Graph::NodeItr nItr) {
|
|
|
|
optimalList.push_back(nItr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Initialise the heuristic.
|
|
|
|
///
|
|
|
|
/// HeuristicBase iterates over all nodes in the problem and adds them to
|
|
|
|
/// the appropriate list using addToOptimalReduceList or
|
|
|
|
/// addToHeuristicReduceList based on the result of shouldOptimallyReduce.
|
|
|
|
///
|
|
|
|
/// This behaviour should be fine for most situations.
|
|
|
|
void setup() {
|
|
|
|
for (Graph::NodeItr nItr = g.nodesBegin(), nEnd = g.nodesEnd();
|
|
|
|
nItr != nEnd; ++nItr) {
|
|
|
|
if (impl().shouldOptimallyReduce(nItr)) {
|
|
|
|
addToOptimalReduceList(nItr);
|
|
|
|
} else {
|
|
|
|
impl().addToHeuristicReduceList(nItr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Optimally reduce one of the nodes in the optimal reduce list.
|
|
|
|
/// @return True if a reduction takes place, false if the optimal reduce
|
|
|
|
/// list is empty.
|
|
|
|
///
|
|
|
|
/// Selects a node from the optimal reduce list and removes it, applying
|
|
|
|
/// R0, R1 or R2 as appropriate based on the selected node's degree.
|
|
|
|
bool optimalReduce() {
|
|
|
|
if (optimalList.empty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Graph::NodeItr nItr = optimalList.front();
|
|
|
|
optimalList.pop_front();
|
|
|
|
|
|
|
|
switch (s.getSolverDegree(nItr)) {
|
|
|
|
case 0: s.applyR0(nItr); break;
|
|
|
|
case 1: s.applyR1(nItr); break;
|
|
|
|
case 2: s.applyR2(nItr); break;
|
|
|
|
default: assert(false &&
|
|
|
|
"Optimal reductions of degree > 2 nodes is invalid.");
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Perform the PBQP reduction process.
|
|
|
|
///
|
|
|
|
/// Reduces the problem to the empty graph by repeated application of the
|
|
|
|
/// reduction rules R0, R1, R2 and RN.
|
|
|
|
/// R0, R1 or R2 are always applied if possible before RN is used.
|
|
|
|
void reduce() {
|
|
|
|
bool finished = false;
|
|
|
|
|
|
|
|
while (!finished) {
|
2010-09-02 09:08:05 +02:00
|
|
|
if (!optimalReduce()) {
|
2010-09-02 07:37:52 +02:00
|
|
|
if (impl().heuristicReduce()) {
|
|
|
|
getSolver().recordRN();
|
|
|
|
} else {
|
2010-01-26 05:49:58 +01:00
|
|
|
finished = true;
|
2010-09-02 07:37:52 +02:00
|
|
|
}
|
2010-09-02 09:08:05 +02:00
|
|
|
}
|
2010-01-26 05:49:58 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Add a node to the heuristic reduce list.
|
|
|
|
/// @param nItr Node iterator to add to the heuristic reduce list.
|
|
|
|
void addToHeuristicList(Graph::NodeItr nItr) {
|
|
|
|
assert(false && "Must be implemented in derived class.");
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Heuristically reduce one of the nodes in the heuristic
|
|
|
|
/// reduce list.
|
|
|
|
/// @return True if a reduction takes place, false if the heuristic reduce
|
|
|
|
/// list is empty.
|
|
|
|
void heuristicReduce() {
|
|
|
|
assert(false && "Must be implemented in derived class.");
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Prepare a change in the costs on the given edge.
|
|
|
|
/// @param eItr Edge iterator.
|
|
|
|
void preUpdateEdgeCosts(Graph::EdgeItr eItr) {
|
|
|
|
assert(false && "Must be implemented in derived class.");
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Handle the change in the costs on the given edge.
|
|
|
|
/// @param eItr Edge iterator.
|
|
|
|
void postUpdateEdgeCostts(Graph::EdgeItr eItr) {
|
|
|
|
assert(false && "Must be implemented in derived class.");
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Handle the addition of a new edge into the PBQP graph.
|
|
|
|
/// @param eItr Edge iterator for the added edge.
|
|
|
|
void handleAddEdge(Graph::EdgeItr eItr) {
|
|
|
|
assert(false && "Must be implemented in derived class.");
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Handle disconnection of an edge from a node.
|
|
|
|
/// @param eItr Edge iterator for edge being disconnected.
|
|
|
|
/// @param nItr Node iterator for the node being disconnected from.
|
|
|
|
///
|
|
|
|
/// Edges are frequently removed due to the removal of a node. This
|
|
|
|
/// method allows for the effect to be computed only for the remaining
|
|
|
|
/// node in the graph.
|
|
|
|
void handleRemoveEdge(Graph::EdgeItr eItr, Graph::NodeItr nItr) {
|
|
|
|
assert(false && "Must be implemented in derived class.");
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Clean up any structures used by HeuristicBase.
|
|
|
|
///
|
|
|
|
/// At present this just performs a sanity check: that the optimal reduce
|
|
|
|
/// list is empty now that reduction has completed.
|
|
|
|
///
|
|
|
|
/// If your derived class has more complex structures which need tearing
|
|
|
|
/// down you should over-ride this method but include a call back to this
|
|
|
|
/// implementation.
|
|
|
|
void cleanup() {
|
|
|
|
assert(optimalList.empty() && "Nodes left over in optimal reduce list?");
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endif // LLVM_CODEGEN_PBQP_HEURISTICBASE_H
|