LLVM API Documentation

HeuristicBase.h
Go to the documentation of this file.
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