Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

247 lines
9.3 KiB

  1. //===-- HeuristcBase.h --- Heuristic base class for PBQP --------*- C++ -*-===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #ifndef LLVM_CODEGEN_PBQP_HEURISTICBASE_H
  10. #define LLVM_CODEGEN_PBQP_HEURISTICBASE_H
  11. #include "HeuristicSolver.h"
  12. namespace PBQP {
  13. /// \brief Abstract base class for heuristic implementations.
  14. ///
  15. /// This class provides a handy base for heuristic implementations with common
  16. /// solver behaviour implemented for a number of methods.
  17. ///
  18. /// To implement your own heuristic using this class as a base you'll have to
  19. /// implement, as a minimum, the following methods:
  20. /// <ul>
  21. /// <li> void addToHeuristicList(Graph::NodeItr) : Add a node to the
  22. /// heuristic reduction list.
  23. /// <li> void heuristicReduce() : Perform a single heuristic reduction.
  24. /// <li> void preUpdateEdgeCosts(Graph::EdgeItr) : Handle the (imminent)
  25. /// change to the cost matrix on the given edge (by R2).
  26. /// <li> void postUpdateEdgeCostts(Graph::EdgeItr) : Handle the new
  27. /// costs on the given edge.
  28. /// <li> void handleAddEdge(Graph::EdgeItr) : Handle the addition of a new
  29. /// edge into the PBQP graph (by R2).
  30. /// <li> void handleRemoveEdge(Graph::EdgeItr, Graph::NodeItr) : Handle the
  31. /// disconnection of the given edge from the given node.
  32. /// <li> A constructor for your derived class : to pass back a reference to
  33. /// the solver which is using this heuristic.
  34. /// </ul>
  35. ///
  36. /// These methods are implemented in this class for documentation purposes,
  37. /// but will assert if called.
  38. ///
  39. /// Note that this class uses the curiously recursive template idiom to
  40. /// forward calls to the derived class. These methods need not be made
  41. /// virtual, and indeed probably shouldn't for performance reasons.
  42. ///
  43. /// You'll also need to provide NodeData and EdgeData structs in your class.
  44. /// These can be used to attach data relevant to your heuristic to each
  45. /// node/edge in the PBQP graph.
  46. template <typename HImpl>
  47. class HeuristicBase {
  48. private:
  49. typedef std::list<Graph::NodeItr> OptimalList;
  50. HeuristicSolverImpl<HImpl> &s;
  51. Graph &g;
  52. OptimalList optimalList;
  53. // Return a reference to the derived heuristic.
  54. HImpl& impl() { return static_cast<HImpl&>(*this); }
  55. // Add the given node to the optimal reductions list. Keep an iterator to
  56. // its location for fast removal.
  57. void addToOptimalReductionList(Graph::NodeItr nItr) {
  58. optimalList.insert(optimalList.end(), nItr);
  59. }
  60. public:
  61. /// \brief Construct an instance with a reference to the given solver.
  62. /// @param solver The solver which is using this heuristic instance.
  63. HeuristicBase(HeuristicSolverImpl<HImpl> &solver)
  64. : s(solver), g(s.getGraph()) { }
  65. /// \brief Get the solver which is using this heuristic instance.
  66. /// @return The solver which is using this heuristic instance.
  67. ///
  68. /// You can use this method to get access to the solver in your derived
  69. /// heuristic implementation.
  70. HeuristicSolverImpl<HImpl>& getSolver() { return s; }
  71. /// \brief Get the graph representing the problem to be solved.
  72. /// @return The graph representing the problem to be solved.
  73. Graph& getGraph() { return g; }
  74. /// \brief Tell the solver to simplify the graph before the reduction phase.
  75. /// @return Whether or not the solver should run a simplification phase
  76. /// prior to the main setup and reduction.
  77. ///
  78. /// HeuristicBase returns true from this method as it's a sensible default,
  79. /// however you can over-ride it in your derived class if you want different
  80. /// behaviour.
  81. bool solverRunSimplify() const { return true; }
  82. /// \brief Decide whether a node should be optimally or heuristically
  83. /// reduced.
  84. /// @return Whether or not the given node should be listed for optimal
  85. /// reduction (via R0, R1 or R2).
  86. ///
  87. /// HeuristicBase returns true for any node with degree less than 3. This is
  88. /// sane and sensible for many situations, but not all. You can over-ride
  89. /// this method in your derived class if you want a different selection
  90. /// criteria. Note however that your criteria for selecting optimal nodes
  91. /// should be <i>at least</i> as strong as this. I.e. Nodes of degree 3 or
  92. /// higher should not be selected under any circumstances.
  93. bool shouldOptimallyReduce(Graph::NodeItr nItr) {
  94. if (g.getNodeDegree(nItr) < 3)
  95. return true;
  96. // else
  97. return false;
  98. }
  99. /// \brief Add the given node to the list of nodes to be optimally reduced.
  100. /// @param nItr Node iterator to be added.
  101. ///
  102. /// You probably don't want to over-ride this, except perhaps to record
  103. /// statistics before calling this implementation. HeuristicBase relies on
  104. /// its behaviour.
  105. void addToOptimalReduceList(Graph::NodeItr nItr) {
  106. optimalList.push_back(nItr);
  107. }
  108. /// \brief Initialise the heuristic.
  109. ///
  110. /// HeuristicBase iterates over all nodes in the problem and adds them to
  111. /// the appropriate list using addToOptimalReduceList or
  112. /// addToHeuristicReduceList based on the result of shouldOptimallyReduce.
  113. ///
  114. /// This behaviour should be fine for most situations.
  115. void setup() {
  116. for (Graph::NodeItr nItr = g.nodesBegin(), nEnd = g.nodesEnd();
  117. nItr != nEnd; ++nItr) {
  118. if (impl().shouldOptimallyReduce(nItr)) {
  119. addToOptimalReduceList(nItr);
  120. } else {
  121. impl().addToHeuristicReduceList(nItr);
  122. }
  123. }
  124. }
  125. /// \brief Optimally reduce one of the nodes in the optimal reduce list.
  126. /// @return True if a reduction takes place, false if the optimal reduce
  127. /// list is empty.
  128. ///
  129. /// Selects a node from the optimal reduce list and removes it, applying
  130. /// R0, R1 or R2 as appropriate based on the selected node's degree.
  131. bool optimalReduce() {
  132. if (optimalList.empty())
  133. return false;
  134. Graph::NodeItr nItr = optimalList.front();
  135. optimalList.pop_front();
  136. switch (s.getSolverDegree(nItr)) {
  137. case 0: s.applyR0(nItr); break;
  138. case 1: s.applyR1(nItr); break;
  139. case 2: s.applyR2(nItr); break;
  140. default: llvm_unreachable(
  141. "Optimal reductions of degree > 2 nodes is invalid.");
  142. }
  143. return true;
  144. }
  145. /// \brief Perform the PBQP reduction process.
  146. ///
  147. /// Reduces the problem to the empty graph by repeated application of the
  148. /// reduction rules R0, R1, R2 and RN.
  149. /// R0, R1 or R2 are always applied if possible before RN is used.
  150. void reduce() {
  151. bool finished = false;
  152. while (!finished) {
  153. if (!optimalReduce()) {
  154. if (impl().heuristicReduce()) {
  155. getSolver().recordRN();
  156. } else {
  157. finished = true;
  158. }
  159. }
  160. }
  161. }
  162. /// \brief Add a node to the heuristic reduce list.
  163. /// @param nItr Node iterator to add to the heuristic reduce list.
  164. void addToHeuristicList(Graph::NodeItr nItr) {
  165. llvm_unreachable("Must be implemented in derived class.");
  166. }
  167. /// \brief Heuristically reduce one of the nodes in the heuristic
  168. /// reduce list.
  169. /// @return True if a reduction takes place, false if the heuristic reduce
  170. /// list is empty.
  171. bool heuristicReduce() {
  172. llvm_unreachable("Must be implemented in derived class.");
  173. return false;
  174. }
  175. /// \brief Prepare a change in the costs on the given edge.
  176. /// @param eItr Edge iterator.
  177. void preUpdateEdgeCosts(Graph::EdgeItr eItr) {
  178. llvm_unreachable("Must be implemented in derived class.");
  179. }
  180. /// \brief Handle the change in the costs on the given edge.
  181. /// @param eItr Edge iterator.
  182. void postUpdateEdgeCostts(Graph::EdgeItr eItr) {
  183. llvm_unreachable("Must be implemented in derived class.");
  184. }
  185. /// \brief Handle the addition of a new edge into the PBQP graph.
  186. /// @param eItr Edge iterator for the added edge.
  187. void handleAddEdge(Graph::EdgeItr eItr) {
  188. llvm_unreachable("Must be implemented in derived class.");
  189. }
  190. /// \brief Handle disconnection of an edge from a node.
  191. /// @param eItr Edge iterator for edge being disconnected.
  192. /// @param nItr Node iterator for the node being disconnected from.
  193. ///
  194. /// Edges are frequently removed due to the removal of a node. This
  195. /// method allows for the effect to be computed only for the remaining
  196. /// node in the graph.
  197. void handleRemoveEdge(Graph::EdgeItr eItr, Graph::NodeItr nItr) {
  198. llvm_unreachable("Must be implemented in derived class.");
  199. }
  200. /// \brief Clean up any structures used by HeuristicBase.
  201. ///
  202. /// At present this just performs a sanity check: that the optimal reduce
  203. /// list is empty now that reduction has completed.
  204. ///
  205. /// If your derived class has more complex structures which need tearing
  206. /// down you should over-ride this method but include a call back to this
  207. /// implementation.
  208. void cleanup() {
  209. assert(optimalList.empty() && "Nodes left over in optimal reduce list?");
  210. }
  211. };
  212. }
  213. #endif // LLVM_CODEGEN_PBQP_HEURISTICBASE_H