LLVM API Documentation
00001 //===-- HeuristicSolver.h - Heuristic PBQP Solver --------------*- 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 // Heuristic PBQP solver. This solver is able to perform optimal reductions for 00011 // nodes of degree 0, 1 or 2. For nodes of degree >2 a plugable heuristic is 00012 // used to select a node for reduction. 00013 // 00014 //===----------------------------------------------------------------------===// 00015 00016 #ifndef LLVM_CODEGEN_PBQP_HEURISTICSOLVER_H 00017 #define LLVM_CODEGEN_PBQP_HEURISTICSOLVER_H 00018 00019 #include "Graph.h" 00020 #include "Solution.h" 00021 #include <limits> 00022 #include <vector> 00023 00024 namespace PBQP { 00025 00026 /// \brief Heuristic PBQP solver implementation. 00027 /// 00028 /// This class should usually be created (and destroyed) indirectly via a call 00029 /// to HeuristicSolver<HImpl>::solve(Graph&). 00030 /// See the comments for HeuristicSolver. 00031 /// 00032 /// HeuristicSolverImpl provides the R0, R1 and R2 reduction rules, 00033 /// backpropagation phase, and maintains the internal copy of the graph on 00034 /// which the reduction is carried out (the original being kept to facilitate 00035 /// backpropagation). 00036 template <typename HImpl> 00037 class HeuristicSolverImpl { 00038 private: 00039 00040 typedef typename HImpl::NodeData HeuristicNodeData; 00041 typedef typename HImpl::EdgeData HeuristicEdgeData; 00042 00043 typedef std::list<Graph::EdgeItr> SolverEdges; 00044 00045 public: 00046 00047 /// \brief Iterator type for edges in the solver graph. 00048 typedef SolverEdges::iterator SolverEdgeItr; 00049 00050 private: 00051 00052 class NodeData { 00053 public: 00054 NodeData() : solverDegree(0) {} 00055 00056 HeuristicNodeData& getHeuristicData() { return hData; } 00057 00058 SolverEdgeItr addSolverEdge(Graph::EdgeItr eItr) { 00059 ++solverDegree; 00060 return solverEdges.insert(solverEdges.end(), eItr); 00061 } 00062 00063 void removeSolverEdge(SolverEdgeItr seItr) { 00064 --solverDegree; 00065 solverEdges.erase(seItr); 00066 } 00067 00068 SolverEdgeItr solverEdgesBegin() { return solverEdges.begin(); } 00069 SolverEdgeItr solverEdgesEnd() { return solverEdges.end(); } 00070 unsigned getSolverDegree() const { return solverDegree; } 00071 void clearSolverEdges() { 00072 solverDegree = 0; 00073 solverEdges.clear(); 00074 } 00075 00076 private: 00077 HeuristicNodeData hData; 00078 unsigned solverDegree; 00079 SolverEdges solverEdges; 00080 }; 00081 00082 class EdgeData { 00083 public: 00084 HeuristicEdgeData& getHeuristicData() { return hData; } 00085 00086 void setN1SolverEdgeItr(SolverEdgeItr n1SolverEdgeItr) { 00087 this->n1SolverEdgeItr = n1SolverEdgeItr; 00088 } 00089 00090 SolverEdgeItr getN1SolverEdgeItr() { return n1SolverEdgeItr; } 00091 00092 void setN2SolverEdgeItr(SolverEdgeItr n2SolverEdgeItr){ 00093 this->n2SolverEdgeItr = n2SolverEdgeItr; 00094 } 00095 00096 SolverEdgeItr getN2SolverEdgeItr() { return n2SolverEdgeItr; } 00097 00098 private: 00099 00100 HeuristicEdgeData hData; 00101 SolverEdgeItr n1SolverEdgeItr, n2SolverEdgeItr; 00102 }; 00103 00104 Graph &g; 00105 HImpl h; 00106 Solution s; 00107 std::vector<Graph::NodeItr> stack; 00108 00109 typedef std::list<NodeData> NodeDataList; 00110 NodeDataList nodeDataList; 00111 00112 typedef std::list<EdgeData> EdgeDataList; 00113 EdgeDataList edgeDataList; 00114 00115 public: 00116 00117 /// \brief Construct a heuristic solver implementation to solve the given 00118 /// graph. 00119 /// @param g The graph representing the problem instance to be solved. 00120 HeuristicSolverImpl(Graph &g) : g(g), h(*this) {} 00121 00122 /// \brief Get the graph being solved by this solver. 00123 /// @return The graph representing the problem instance being solved by this 00124 /// solver. 00125 Graph& getGraph() { return g; } 00126 00127 /// \brief Get the heuristic data attached to the given node. 00128 /// @param nItr Node iterator. 00129 /// @return The heuristic data attached to the given node. 00130 HeuristicNodeData& getHeuristicNodeData(Graph::NodeItr nItr) { 00131 return getSolverNodeData(nItr).getHeuristicData(); 00132 } 00133 00134 /// \brief Get the heuristic data attached to the given edge. 00135 /// @param eItr Edge iterator. 00136 /// @return The heuristic data attached to the given node. 00137 HeuristicEdgeData& getHeuristicEdgeData(Graph::EdgeItr eItr) { 00138 return getSolverEdgeData(eItr).getHeuristicData(); 00139 } 00140 00141 /// \brief Begin iterator for the set of edges adjacent to the given node in 00142 /// the solver graph. 00143 /// @param nItr Node iterator. 00144 /// @return Begin iterator for the set of edges adjacent to the given node 00145 /// in the solver graph. 00146 SolverEdgeItr solverEdgesBegin(Graph::NodeItr nItr) { 00147 return getSolverNodeData(nItr).solverEdgesBegin(); 00148 } 00149 00150 /// \brief End iterator for the set of edges adjacent to the given node in 00151 /// the solver graph. 00152 /// @param nItr Node iterator. 00153 /// @return End iterator for the set of edges adjacent to the given node in 00154 /// the solver graph. 00155 SolverEdgeItr solverEdgesEnd(Graph::NodeItr nItr) { 00156 return getSolverNodeData(nItr).solverEdgesEnd(); 00157 } 00158 00159 /// \brief Remove a node from the solver graph. 00160 /// @param eItr Edge iterator for edge to be removed. 00161 /// 00162 /// Does <i>not</i> notify the heuristic of the removal. That should be 00163 /// done manually if necessary. 00164 void removeSolverEdge(Graph::EdgeItr eItr) { 00165 EdgeData &eData = getSolverEdgeData(eItr); 00166 NodeData &n1Data = getSolverNodeData(g.getEdgeNode1(eItr)), 00167 &n2Data = getSolverNodeData(g.getEdgeNode2(eItr)); 00168 00169 n1Data.removeSolverEdge(eData.getN1SolverEdgeItr()); 00170 n2Data.removeSolverEdge(eData.getN2SolverEdgeItr()); 00171 } 00172 00173 /// \brief Compute a solution to the PBQP problem instance with which this 00174 /// heuristic solver was constructed. 00175 /// @return A solution to the PBQP problem. 00176 /// 00177 /// Performs the full PBQP heuristic solver algorithm, including setup, 00178 /// calls to the heuristic (which will call back to the reduction rules in 00179 /// this class), and cleanup. 00180 Solution computeSolution() { 00181 setup(); 00182 h.setup(); 00183 h.reduce(); 00184 backpropagate(); 00185 h.cleanup(); 00186 cleanup(); 00187 return s; 00188 } 00189 00190 /// \brief Add to the end of the stack. 00191 /// @param nItr Node iterator to add to the reduction stack. 00192 void pushToStack(Graph::NodeItr nItr) { 00193 getSolverNodeData(nItr).clearSolverEdges(); 00194 stack.push_back(nItr); 00195 } 00196 00197 /// \brief Returns the solver degree of the given node. 00198 /// @param nItr Node iterator for which degree is requested. 00199 /// @return Node degree in the <i>solver</i> graph (not the original graph). 00200 unsigned getSolverDegree(Graph::NodeItr nItr) { 00201 return getSolverNodeData(nItr).getSolverDegree(); 00202 } 00203 00204 /// \brief Set the solution of the given node. 00205 /// @param nItr Node iterator to set solution for. 00206 /// @param selection Selection for node. 00207 void setSolution(const Graph::NodeItr &nItr, unsigned selection) { 00208 s.setSelection(nItr, selection); 00209 00210 for (Graph::AdjEdgeItr aeItr = g.adjEdgesBegin(nItr), 00211 aeEnd = g.adjEdgesEnd(nItr); 00212 aeItr != aeEnd; ++aeItr) { 00213 Graph::EdgeItr eItr(*aeItr); 00214 Graph::NodeItr anItr(g.getEdgeOtherNode(eItr, nItr)); 00215 getSolverNodeData(anItr).addSolverEdge(eItr); 00216 } 00217 } 00218 00219 /// \brief Apply rule R0. 00220 /// @param nItr Node iterator for node to apply R0 to. 00221 /// 00222 /// Node will be automatically pushed to the solver stack. 00223 void applyR0(Graph::NodeItr nItr) { 00224 assert(getSolverNodeData(nItr).getSolverDegree() == 0 && 00225 "R0 applied to node with degree != 0."); 00226 00227 // Nothing to do. Just push the node onto the reduction stack. 00228 pushToStack(nItr); 00229 00230 s.recordR0(); 00231 } 00232 00233 /// \brief Apply rule R1. 00234 /// @param xnItr Node iterator for node to apply R1 to. 00235 /// 00236 /// Node will be automatically pushed to the solver stack. 00237 void applyR1(Graph::NodeItr xnItr) { 00238 NodeData &nd = getSolverNodeData(xnItr); 00239 assert(nd.getSolverDegree() == 1 && 00240 "R1 applied to node with degree != 1."); 00241 00242 Graph::EdgeItr eItr = *nd.solverEdgesBegin(); 00243 00244 const Matrix &eCosts = g.getEdgeCosts(eItr); 00245 const Vector &xCosts = g.getNodeCosts(xnItr); 00246 00247 // Duplicate a little to avoid transposing matrices. 00248 if (xnItr == g.getEdgeNode1(eItr)) { 00249 Graph::NodeItr ynItr = g.getEdgeNode2(eItr); 00250 Vector &yCosts = g.getNodeCosts(ynItr); 00251 for (unsigned j = 0; j < yCosts.getLength(); ++j) { 00252 PBQPNum min = eCosts[0][j] + xCosts[0]; 00253 for (unsigned i = 1; i < xCosts.getLength(); ++i) { 00254 PBQPNum c = eCosts[i][j] + xCosts[i]; 00255 if (c < min) 00256 min = c; 00257 } 00258 yCosts[j] += min; 00259 } 00260 h.handleRemoveEdge(eItr, ynItr); 00261 } else { 00262 Graph::NodeItr ynItr = g.getEdgeNode1(eItr); 00263 Vector &yCosts = g.getNodeCosts(ynItr); 00264 for (unsigned i = 0; i < yCosts.getLength(); ++i) { 00265 PBQPNum min = eCosts[i][0] + xCosts[0]; 00266 for (unsigned j = 1; j < xCosts.getLength(); ++j) { 00267 PBQPNum c = eCosts[i][j] + xCosts[j]; 00268 if (c < min) 00269 min = c; 00270 } 00271 yCosts[i] += min; 00272 } 00273 h.handleRemoveEdge(eItr, ynItr); 00274 } 00275 removeSolverEdge(eItr); 00276 assert(nd.getSolverDegree() == 0 && 00277 "Degree 1 with edge removed should be 0."); 00278 pushToStack(xnItr); 00279 s.recordR1(); 00280 } 00281 00282 /// \brief Apply rule R2. 00283 /// @param xnItr Node iterator for node to apply R2 to. 00284 /// 00285 /// Node will be automatically pushed to the solver stack. 00286 void applyR2(Graph::NodeItr xnItr) { 00287 assert(getSolverNodeData(xnItr).getSolverDegree() == 2 && 00288 "R2 applied to node with degree != 2."); 00289 00290 NodeData &nd = getSolverNodeData(xnItr); 00291 const Vector &xCosts = g.getNodeCosts(xnItr); 00292 00293 SolverEdgeItr aeItr = nd.solverEdgesBegin(); 00294 Graph::EdgeItr yxeItr = *aeItr, 00295 zxeItr = *(++aeItr); 00296 00297 Graph::NodeItr ynItr = g.getEdgeOtherNode(yxeItr, xnItr), 00298 znItr = g.getEdgeOtherNode(zxeItr, xnItr); 00299 00300 bool flipEdge1 = (g.getEdgeNode1(yxeItr) == xnItr), 00301 flipEdge2 = (g.getEdgeNode1(zxeItr) == xnItr); 00302 00303 const Matrix *yxeCosts = flipEdge1 ? 00304 new Matrix(g.getEdgeCosts(yxeItr).transpose()) : 00305 &g.getEdgeCosts(yxeItr); 00306 00307 const Matrix *zxeCosts = flipEdge2 ? 00308 new Matrix(g.getEdgeCosts(zxeItr).transpose()) : 00309 &g.getEdgeCosts(zxeItr); 00310 00311 unsigned xLen = xCosts.getLength(), 00312 yLen = yxeCosts->getRows(), 00313 zLen = zxeCosts->getRows(); 00314 00315 Matrix delta(yLen, zLen); 00316 00317 for (unsigned i = 0; i < yLen; ++i) { 00318 for (unsigned j = 0; j < zLen; ++j) { 00319 PBQPNum min = (*yxeCosts)[i][0] + (*zxeCosts)[j][0] + xCosts[0]; 00320 for (unsigned k = 1; k < xLen; ++k) { 00321 PBQPNum c = (*yxeCosts)[i][k] + (*zxeCosts)[j][k] + xCosts[k]; 00322 if (c < min) { 00323 min = c; 00324 } 00325 } 00326 delta[i][j] = min; 00327 } 00328 } 00329 00330 if (flipEdge1) 00331 delete yxeCosts; 00332 00333 if (flipEdge2) 00334 delete zxeCosts; 00335 00336 Graph::EdgeItr yzeItr = g.findEdge(ynItr, znItr); 00337 bool addedEdge = false; 00338 00339 if (yzeItr == g.edgesEnd()) { 00340 yzeItr = g.addEdge(ynItr, znItr, delta); 00341 addedEdge = true; 00342 } else { 00343 Matrix &yzeCosts = g.getEdgeCosts(yzeItr); 00344 h.preUpdateEdgeCosts(yzeItr); 00345 if (ynItr == g.getEdgeNode1(yzeItr)) { 00346 yzeCosts += delta; 00347 } else { 00348 yzeCosts += delta.transpose(); 00349 } 00350 } 00351 00352 bool nullCostEdge = tryNormaliseEdgeMatrix(yzeItr); 00353 00354 if (!addedEdge) { 00355 // If we modified the edge costs let the heuristic know. 00356 h.postUpdateEdgeCosts(yzeItr); 00357 } 00358 00359 if (nullCostEdge) { 00360 // If this edge ended up null remove it. 00361 if (!addedEdge) { 00362 // We didn't just add it, so we need to notify the heuristic 00363 // and remove it from the solver. 00364 h.handleRemoveEdge(yzeItr, ynItr); 00365 h.handleRemoveEdge(yzeItr, znItr); 00366 removeSolverEdge(yzeItr); 00367 } 00368 g.removeEdge(yzeItr); 00369 } else if (addedEdge) { 00370 // If the edge was added, and non-null, finish setting it up, add it to 00371 // the solver & notify heuristic. 00372 edgeDataList.push_back(EdgeData()); 00373 g.setEdgeData(yzeItr, &edgeDataList.back()); 00374 addSolverEdge(yzeItr); 00375 h.handleAddEdge(yzeItr); 00376 } 00377 00378 h.handleRemoveEdge(yxeItr, ynItr); 00379 removeSolverEdge(yxeItr); 00380 h.handleRemoveEdge(zxeItr, znItr); 00381 removeSolverEdge(zxeItr); 00382 00383 pushToStack(xnItr); 00384 s.recordR2(); 00385 } 00386 00387 /// \brief Record an application of the RN rule. 00388 /// 00389 /// For use by the HeuristicBase. 00390 void recordRN() { s.recordRN(); } 00391 00392 private: 00393 00394 NodeData& getSolverNodeData(Graph::NodeItr nItr) { 00395 return *static_cast<NodeData*>(g.getNodeData(nItr)); 00396 } 00397 00398 EdgeData& getSolverEdgeData(Graph::EdgeItr eItr) { 00399 return *static_cast<EdgeData*>(g.getEdgeData(eItr)); 00400 } 00401 00402 void addSolverEdge(Graph::EdgeItr eItr) { 00403 EdgeData &eData = getSolverEdgeData(eItr); 00404 NodeData &n1Data = getSolverNodeData(g.getEdgeNode1(eItr)), 00405 &n2Data = getSolverNodeData(g.getEdgeNode2(eItr)); 00406 00407 eData.setN1SolverEdgeItr(n1Data.addSolverEdge(eItr)); 00408 eData.setN2SolverEdgeItr(n2Data.addSolverEdge(eItr)); 00409 } 00410 00411 void setup() { 00412 if (h.solverRunSimplify()) { 00413 simplify(); 00414 } 00415 00416 // Create node data objects. 00417 for (Graph::NodeItr nItr = g.nodesBegin(), nEnd = g.nodesEnd(); 00418 nItr != nEnd; ++nItr) { 00419 nodeDataList.push_back(NodeData()); 00420 g.setNodeData(nItr, &nodeDataList.back()); 00421 } 00422 00423 // Create edge data objects. 00424 for (Graph::EdgeItr eItr = g.edgesBegin(), eEnd = g.edgesEnd(); 00425 eItr != eEnd; ++eItr) { 00426 edgeDataList.push_back(EdgeData()); 00427 g.setEdgeData(eItr, &edgeDataList.back()); 00428 addSolverEdge(eItr); 00429 } 00430 } 00431 00432 void simplify() { 00433 disconnectTrivialNodes(); 00434 eliminateIndependentEdges(); 00435 } 00436 00437 // Eliminate trivial nodes. 00438 void disconnectTrivialNodes() { 00439 unsigned numDisconnected = 0; 00440 00441 for (Graph::NodeItr nItr = g.nodesBegin(), nEnd = g.nodesEnd(); 00442 nItr != nEnd; ++nItr) { 00443 00444 if (g.getNodeCosts(nItr).getLength() == 1) { 00445 00446 std::vector<Graph::EdgeItr> edgesToRemove; 00447 00448 for (Graph::AdjEdgeItr aeItr = g.adjEdgesBegin(nItr), 00449 aeEnd = g.adjEdgesEnd(nItr); 00450 aeItr != aeEnd; ++aeItr) { 00451 00452 Graph::EdgeItr eItr = *aeItr; 00453 00454 if (g.getEdgeNode1(eItr) == nItr) { 00455 Graph::NodeItr otherNodeItr = g.getEdgeNode2(eItr); 00456 g.getNodeCosts(otherNodeItr) += 00457 g.getEdgeCosts(eItr).getRowAsVector(0); 00458 } 00459 else { 00460 Graph::NodeItr otherNodeItr = g.getEdgeNode1(eItr); 00461 g.getNodeCosts(otherNodeItr) += 00462 g.getEdgeCosts(eItr).getColAsVector(0); 00463 } 00464 00465 edgesToRemove.push_back(eItr); 00466 } 00467 00468 if (!edgesToRemove.empty()) 00469 ++numDisconnected; 00470 00471 while (!edgesToRemove.empty()) { 00472 g.removeEdge(edgesToRemove.back()); 00473 edgesToRemove.pop_back(); 00474 } 00475 } 00476 } 00477 } 00478 00479 void eliminateIndependentEdges() { 00480 std::vector<Graph::EdgeItr> edgesToProcess; 00481 unsigned numEliminated = 0; 00482 00483 for (Graph::EdgeItr eItr = g.edgesBegin(), eEnd = g.edgesEnd(); 00484 eItr != eEnd; ++eItr) { 00485 edgesToProcess.push_back(eItr); 00486 } 00487 00488 while (!edgesToProcess.empty()) { 00489 if (tryToEliminateEdge(edgesToProcess.back())) 00490 ++numEliminated; 00491 edgesToProcess.pop_back(); 00492 } 00493 } 00494 00495 bool tryToEliminateEdge(Graph::EdgeItr eItr) { 00496 if (tryNormaliseEdgeMatrix(eItr)) { 00497 g.removeEdge(eItr); 00498 return true; 00499 } 00500 return false; 00501 } 00502 00503 bool tryNormaliseEdgeMatrix(Graph::EdgeItr &eItr) { 00504 00505 const PBQPNum infinity = std::numeric_limits<PBQPNum>::infinity(); 00506 00507 Matrix &edgeCosts = g.getEdgeCosts(eItr); 00508 Vector &uCosts = g.getNodeCosts(g.getEdgeNode1(eItr)), 00509 &vCosts = g.getNodeCosts(g.getEdgeNode2(eItr)); 00510 00511 for (unsigned r = 0; r < edgeCosts.getRows(); ++r) { 00512 PBQPNum rowMin = infinity; 00513 00514 for (unsigned c = 0; c < edgeCosts.getCols(); ++c) { 00515 if (vCosts[c] != infinity && edgeCosts[r][c] < rowMin) 00516 rowMin = edgeCosts[r][c]; 00517 } 00518 00519 uCosts[r] += rowMin; 00520 00521 if (rowMin != infinity) { 00522 edgeCosts.subFromRow(r, rowMin); 00523 } 00524 else { 00525 edgeCosts.setRow(r, 0); 00526 } 00527 } 00528 00529 for (unsigned c = 0; c < edgeCosts.getCols(); ++c) { 00530 PBQPNum colMin = infinity; 00531 00532 for (unsigned r = 0; r < edgeCosts.getRows(); ++r) { 00533 if (uCosts[r] != infinity && edgeCosts[r][c] < colMin) 00534 colMin = edgeCosts[r][c]; 00535 } 00536 00537 vCosts[c] += colMin; 00538 00539 if (colMin != infinity) { 00540 edgeCosts.subFromCol(c, colMin); 00541 } 00542 else { 00543 edgeCosts.setCol(c, 0); 00544 } 00545 } 00546 00547 return edgeCosts.isZero(); 00548 } 00549 00550 void backpropagate() { 00551 while (!stack.empty()) { 00552 computeSolution(stack.back()); 00553 stack.pop_back(); 00554 } 00555 } 00556 00557 void computeSolution(Graph::NodeItr nItr) { 00558 00559 NodeData &nodeData = getSolverNodeData(nItr); 00560 00561 Vector v(g.getNodeCosts(nItr)); 00562 00563 // Solve based on existing solved edges. 00564 for (SolverEdgeItr solvedEdgeItr = nodeData.solverEdgesBegin(), 00565 solvedEdgeEnd = nodeData.solverEdgesEnd(); 00566 solvedEdgeItr != solvedEdgeEnd; ++solvedEdgeItr) { 00567 00568 Graph::EdgeItr eItr(*solvedEdgeItr); 00569 Matrix &edgeCosts = g.getEdgeCosts(eItr); 00570 00571 if (nItr == g.getEdgeNode1(eItr)) { 00572 Graph::NodeItr adjNode(g.getEdgeNode2(eItr)); 00573 unsigned adjSolution = s.getSelection(adjNode); 00574 v += edgeCosts.getColAsVector(adjSolution); 00575 } 00576 else { 00577 Graph::NodeItr adjNode(g.getEdgeNode1(eItr)); 00578 unsigned adjSolution = s.getSelection(adjNode); 00579 v += edgeCosts.getRowAsVector(adjSolution); 00580 } 00581 00582 } 00583 00584 setSolution(nItr, v.minIndex()); 00585 } 00586 00587 void cleanup() { 00588 h.cleanup(); 00589 nodeDataList.clear(); 00590 edgeDataList.clear(); 00591 } 00592 }; 00593 00594 /// \brief PBQP heuristic solver class. 00595 /// 00596 /// Given a PBQP Graph g representing a PBQP problem, you can find a solution 00597 /// by calling 00598 /// <tt>Solution s = HeuristicSolver<H>::solve(g);</tt> 00599 /// 00600 /// The choice of heuristic for the H parameter will affect both the solver 00601 /// speed and solution quality. The heuristic should be chosen based on the 00602 /// nature of the problem being solved. 00603 /// Currently the only solver included with LLVM is the Briggs heuristic for 00604 /// register allocation. 00605 template <typename HImpl> 00606 class HeuristicSolver { 00607 public: 00608 static Solution solve(Graph &g) { 00609 HeuristicSolverImpl<HImpl> hs(g); 00610 return hs.computeSolution(); 00611 } 00612 }; 00613 00614 } 00615 00616 #endif // LLVM_CODEGEN_PBQP_HEURISTICSOLVER_H