LLVM API Documentation
00001 //===-- HeuristcBase.h --- Heuristic base class for PBQP --------*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 00010 #ifndef LLVM_CODEGEN_PBQP_HEURISTICBASE_H 00011 #define LLVM_CODEGEN_PBQP_HEURISTICBASE_H 00012 00013 #include "HeuristicSolver.h" 00014 00015 namespace PBQP { 00016 00017 /// \brief Abstract base class for heuristic implementations. 00018 /// 00019 /// This class provides a handy base for heuristic implementations with common 00020 /// solver behaviour implemented for a number of methods. 00021 /// 00022 /// To implement your own heuristic using this class as a base you'll have to 00023 /// implement, as a minimum, the following methods: 00024 /// <ul> 00025 /// <li> void addToHeuristicList(Graph::NodeItr) : Add a node to the 00026 /// heuristic reduction list. 00027 /// <li> void heuristicReduce() : Perform a single heuristic reduction. 00028 /// <li> void preUpdateEdgeCosts(Graph::EdgeItr) : Handle the (imminent) 00029 /// change to the cost matrix on the given edge (by R2). 00030 /// <li> void postUpdateEdgeCostts(Graph::EdgeItr) : Handle the new 00031 /// costs on the given edge. 00032 /// <li> void handleAddEdge(Graph::EdgeItr) : Handle the addition of a new 00033 /// edge into the PBQP graph (by R2). 00034 /// <li> void handleRemoveEdge(Graph::EdgeItr, Graph::NodeItr) : Handle the 00035 /// disconnection of the given edge from the given node. 00036 /// <li> A constructor for your derived class : to pass back a reference to 00037 /// the solver which is using this heuristic. 00038 /// </ul> 00039 /// 00040 /// These methods are implemented in this class for documentation purposes, 00041 /// but will assert if called. 00042 /// 00043 /// Note that this class uses the curiously recursive template idiom to 00044 /// forward calls to the derived class. These methods need not be made 00045 /// virtual, and indeed probably shouldn't for performance reasons. 00046 /// 00047 /// You'll also need to provide NodeData and EdgeData structs in your class. 00048 /// These can be used to attach data relevant to your heuristic to each 00049 /// node/edge in the PBQP graph. 00050 00051 template <typename HImpl> 00052 class HeuristicBase { 00053 private: 00054 00055 typedef std::list<Graph::NodeItr> OptimalList; 00056 00057 HeuristicSolverImpl<HImpl> &s; 00058 Graph &g; 00059 OptimalList optimalList; 00060 00061 // Return a reference to the derived heuristic. 00062 HImpl& impl() { return static_cast<HImpl&>(*this); } 00063 00064 // Add the given node to the optimal reductions list. Keep an iterator to 00065 // its location for fast removal. 00066 void addToOptimalReductionList(Graph::NodeItr nItr) { 00067 optimalList.insert(optimalList.end(), nItr); 00068 } 00069 00070 public: 00071 00072 /// \brief Construct an instance with a reference to the given solver. 00073 /// @param solver The solver which is using this heuristic instance. 00074 HeuristicBase(HeuristicSolverImpl<HImpl> &solver) 00075 : s(solver), g(s.getGraph()) { } 00076 00077 /// \brief Get the solver which is using this heuristic instance. 00078 /// @return The solver which is using this heuristic instance. 00079 /// 00080 /// You can use this method to get access to the solver in your derived 00081 /// heuristic implementation. 00082 HeuristicSolverImpl<HImpl>& getSolver() { return s; } 00083 00084 /// \brief Get the graph representing the problem to be solved. 00085 /// @return The graph representing the problem to be solved. 00086 Graph& getGraph() { return g; } 00087 00088 /// \brief Tell the solver to simplify the graph before the reduction phase. 00089 /// @return Whether or not the solver should run a simplification phase 00090 /// prior to the main setup and reduction. 00091 /// 00092 /// HeuristicBase returns true from this method as it's a sensible default, 00093 /// however you can over-ride it in your derived class if you want different 00094 /// behaviour. 00095 bool solverRunSimplify() const { return true; } 00096 00097 /// \brief Decide whether a node should be optimally or heuristically 00098 /// reduced. 00099 /// @return Whether or not the given node should be listed for optimal 00100 /// reduction (via R0, R1 or R2). 00101 /// 00102 /// HeuristicBase returns true for any node with degree less than 3. This is 00103 /// sane and sensible for many situations, but not all. You can over-ride 00104 /// this method in your derived class if you want a different selection 00105 /// criteria. Note however that your criteria for selecting optimal nodes 00106 /// should be <i>at least</i> as strong as this. I.e. Nodes of degree 3 or 00107 /// higher should not be selected under any circumstances. 00108 bool shouldOptimallyReduce(Graph::NodeItr nItr) { 00109 if (g.getNodeDegree(nItr) < 3) 00110 return true; 00111 // else 00112 return false; 00113 } 00114 00115 /// \brief Add the given node to the list of nodes to be optimally reduced. 00116 /// @param nItr Node iterator to be added. 00117 /// 00118 /// You probably don't want to over-ride this, except perhaps to record 00119 /// statistics before calling this implementation. HeuristicBase relies on 00120 /// its behaviour. 00121 void addToOptimalReduceList(Graph::NodeItr nItr) { 00122 optimalList.push_back(nItr); 00123 } 00124 00125 /// \brief Initialise the heuristic. 00126 /// 00127 /// HeuristicBase iterates over all nodes in the problem and adds them to 00128 /// the appropriate list using addToOptimalReduceList or 00129 /// addToHeuristicReduceList based on the result of shouldOptimallyReduce. 00130 /// 00131 /// This behaviour should be fine for most situations. 00132 void setup() { 00133 for (Graph::NodeItr nItr = g.nodesBegin(), nEnd = g.nodesEnd(); 00134 nItr != nEnd; ++nItr) { 00135 if (impl().shouldOptimallyReduce(nItr)) { 00136 addToOptimalReduceList(nItr); 00137 } else { 00138 impl().addToHeuristicReduceList(nItr); 00139 } 00140 } 00141 } 00142 00143 /// \brief Optimally reduce one of the nodes in the optimal reduce list. 00144 /// @return True if a reduction takes place, false if the optimal reduce 00145 /// list is empty. 00146 /// 00147 /// Selects a node from the optimal reduce list and removes it, applying 00148 /// R0, R1 or R2 as appropriate based on the selected node's degree. 00149 bool optimalReduce() { 00150 if (optimalList.empty()) 00151 return false; 00152 00153 Graph::NodeItr nItr = optimalList.front(); 00154 optimalList.pop_front(); 00155 00156 switch (s.getSolverDegree(nItr)) { 00157 case 0: s.applyR0(nItr); break; 00158 case 1: s.applyR1(nItr); break; 00159 case 2: s.applyR2(nItr); break; 00160 default: llvm_unreachable( 00161 "Optimal reductions of degree > 2 nodes is invalid."); 00162 } 00163 00164 return true; 00165 } 00166 00167 /// \brief Perform the PBQP reduction process. 00168 /// 00169 /// Reduces the problem to the empty graph by repeated application of the 00170 /// reduction rules R0, R1, R2 and RN. 00171 /// R0, R1 or R2 are always applied if possible before RN is used. 00172 void reduce() { 00173 bool finished = false; 00174 00175 while (!finished) { 00176 if (!optimalReduce()) { 00177 if (impl().heuristicReduce()) { 00178 getSolver().recordRN(); 00179 } else { 00180 finished = true; 00181 } 00182 } 00183 } 00184 } 00185 00186 /// \brief Add a node to the heuristic reduce list. 00187 /// @param nItr Node iterator to add to the heuristic reduce list. 00188 void addToHeuristicList(Graph::NodeItr nItr) { 00189 llvm_unreachable("Must be implemented in derived class."); 00190 } 00191 00192 /// \brief Heuristically reduce one of the nodes in the heuristic 00193 /// reduce list. 00194 /// @return True if a reduction takes place, false if the heuristic reduce 00195 /// list is empty. 00196 bool heuristicReduce() { 00197 llvm_unreachable("Must be implemented in derived class."); 00198 return false; 00199 } 00200 00201 /// \brief Prepare a change in the costs on the given edge. 00202 /// @param eItr Edge iterator. 00203 void preUpdateEdgeCosts(Graph::EdgeItr eItr) { 00204 llvm_unreachable("Must be implemented in derived class."); 00205 } 00206 00207 /// \brief Handle the change in the costs on the given edge. 00208 /// @param eItr Edge iterator. 00209 void postUpdateEdgeCostts(Graph::EdgeItr eItr) { 00210 llvm_unreachable("Must be implemented in derived class."); 00211 } 00212 00213 /// \brief Handle the addition of a new edge into the PBQP graph. 00214 /// @param eItr Edge iterator for the added edge. 00215 void handleAddEdge(Graph::EdgeItr eItr) { 00216 llvm_unreachable("Must be implemented in derived class."); 00217 } 00218 00219 /// \brief Handle disconnection of an edge from a node. 00220 /// @param eItr Edge iterator for edge being disconnected. 00221 /// @param nItr Node iterator for the node being disconnected from. 00222 /// 00223 /// Edges are frequently removed due to the removal of a node. This 00224 /// method allows for the effect to be computed only for the remaining 00225 /// node in the graph. 00226 void handleRemoveEdge(Graph::EdgeItr eItr, Graph::NodeItr nItr) { 00227 llvm_unreachable("Must be implemented in derived class."); 00228 } 00229 00230 /// \brief Clean up any structures used by HeuristicBase. 00231 /// 00232 /// At present this just performs a sanity check: that the optimal reduce 00233 /// list is empty now that reduction has completed. 00234 /// 00235 /// If your derived class has more complex structures which need tearing 00236 /// down you should over-ride this method but include a call back to this 00237 /// implementation. 00238 void cleanup() { 00239 assert(optimalList.empty() && "Nodes left over in optimal reduce list?"); 00240 } 00241 00242 }; 00243 00244 } 00245 00246 00247 #endif // LLVM_CODEGEN_PBQP_HEURISTICBASE_H