Go to the documentation of this file.00001
00002
00003
00004
00005 #include "SgSystem.h"
00006 #include "SgBookBuilder.h"
00007
00008 #include <sstream>
00009 #include <boost/numeric/conversion/bounds.hpp>
00010 #include "SgDebug.h"
00011 #include "SgPoint.h"
00012 #include "SgTimer.h"
00013
00014
00015
00016 const float SgBookNode::LEAF_PRIORITY = 0.0;
00017
00018 bool SgBookNode::IsTerminal() const
00019 {
00020 if (m_value < -100 || m_value > 100)
00021 return true;
00022 return false;
00023 }
00024
00025 bool SgBookNode::IsLeaf() const
00026 {
00027 return m_count == 0;
00028 }
00029
00030 std::string SgBookNode::ToString() const
00031 {
00032 std::ostringstream os;
00033 os << std::showpos << std::fixed << std::setprecision(6);
00034 os << "Val " << m_value;
00035 os << std::noshowpos << " ExpP " << m_priority;
00036 os << std::showpos << " Heur " << m_heurValue << " Cnt " << m_count;
00037 return os.str();
00038 }
00039
00040 void SgBookNode::FromString(const std::string& str)
00041 {
00042 std::istringstream is(str);
00043 std::string dummy;
00044 is >> dummy;
00045 is >> m_value;
00046 is >> dummy;
00047 is >> m_priority;
00048 is >> dummy;
00049 is >> m_heurValue;
00050 is >> dummy;
00051 is >> m_count;
00052 }
00053
00054
00055
00056 SgBookBuilder::SgBookBuilder()
00057 : m_alpha(50),
00058 m_useWidening(true),
00059 m_expandWidth(16),
00060 m_expandThreshold(1000),
00061 m_flushIterations(100)
00062 {
00063 }
00064
00065 SgBookBuilder::~SgBookBuilder()
00066 {
00067 }
00068
00069
00070
00071 void SgBookBuilder::StartIteration()
00072 {
00073
00074 }
00075
00076 void SgBookBuilder::EndIteration()
00077 {
00078
00079 }
00080
00081 void SgBookBuilder::BeforeEvaluateChildren()
00082 {
00083
00084 }
00085
00086 void SgBookBuilder::AfterEvaluateChildren()
00087 {
00088
00089 }
00090
00091 void SgBookBuilder::Init()
00092 {
00093
00094 }
00095
00096 void SgBookBuilder::Fini()
00097 {
00098
00099 }
00100
00101 void SgBookBuilder::Expand(int numExpansions)
00102 {
00103 m_numEvals = 0;
00104 m_numWidenings = 0;
00105
00106 SgTimer timer;
00107 Init();
00108 EnsureRootExists();
00109 int num = 0;
00110 for (; num < numExpansions; ++num)
00111 {
00112 {
00113 std::ostringstream os;
00114 os << "\n--Iteration " << num << "--\n";
00115 PrintMessage(os.str());
00116 }
00117 {
00118 SgBookNode root;
00119 GetNode(root);
00120 if (root.IsTerminal())
00121 {
00122 PrintMessage("Root is terminal!\n");
00123 break;
00124 }
00125 }
00126 StartIteration();
00127 std::vector<SgMove> pv;
00128 DoExpansion(pv);
00129 EndIteration();
00130
00131 if (num && (num % m_flushIterations) == 0)
00132 FlushBook();
00133 }
00134 FlushBook();
00135 Fini();
00136 timer.Stop();
00137 double elapsed = timer.GetTime();
00138 std::ostringstream os;
00139 os << '\n'
00140 << "Statistics\n"
00141 << "Total Time " << elapsed << '\n'
00142 << "Expansions " << num
00143 << std::fixed << std::setprecision(2)
00144 << " (" << (num / elapsed) << "/s)\n"
00145 << "Evaluations " << m_numEvals
00146 << std::fixed << std::setprecision(2)
00147 << " (" << (double(m_numEvals) / elapsed) << "/s)\n"
00148 << "Widenings " << m_numWidenings << '\n';
00149 PrintMessage(os.str());
00150 }
00151
00152 void SgBookBuilder::Cover(int requiredExpansions, bool additive,
00153 const std::vector< std::vector<SgMove> >& lines)
00154 {
00155 m_numEvals = 0;
00156 m_numWidenings = 0;
00157 std::size_t newLines = 0;
00158 SgTimer timer;
00159 Init();
00160 int num = 0;
00161 for (std::size_t i = 0; i < lines.size(); ++i)
00162 {
00163 const std::size_t size = lines[i].size();
00164 std::vector<SgMove> played;
00165 for (std::size_t j = 0; j <= size; ++j)
00166 {
00167 int expansionsToDo = requiredExpansions;
00168 SgBookNode node;
00169 if (GetNode(node))
00170 {
00171 if (!additive)
00172 expansionsToDo = requiredExpansions - node.m_count;
00173 }
00174 else
00175 {
00176 EnsureRootExists();
00177 GetNode(node);
00178 newLines++;
00179 }
00180 if (node.IsTerminal())
00181 break;
00182 for (int k = 0; k < expansionsToDo; ++k)
00183 {
00184 {
00185 std::ostringstream os;
00186 os << "\n--Iteration " << num << ": "
00187 << (i + 1) << '/' << lines.size() << ' '
00188 << (j + 1) << '/' << (size + 1) << ' '
00189 << (k + 1) << '/' << expansionsToDo << "--\n";
00190 PrintMessage(os.str());
00191 }
00192
00193 StartIteration();
00194 std::vector<SgMove> pv;
00195 DoExpansion(pv);
00196 EndIteration();
00197
00198 num++;
00199 if (num % m_flushIterations == 0)
00200 FlushBook();
00201 }
00202 if (j < lines[i].size())
00203 {
00204 PlayMove(lines[i][j]);
00205 played.push_back(lines[i][j]);
00206 }
00207 }
00208 for (std::size_t j = 0; j < played.size(); ++j)
00209 {
00210 UndoMove(played[played.size() - 1 - j]);
00211 SgBookNode node;
00212 GetNode(node);
00213 UpdateValue(node);
00214 UpdatePriority(node);
00215 }
00216 }
00217 FlushBook();
00218 Fini();
00219 timer.Stop();
00220 double elapsed = timer.GetTime();
00221 std::ostringstream os;
00222 os << '\n'
00223 << "Statistics\n"
00224 << "Total Time " << elapsed << '\n'
00225 << "Expansions " << num
00226 << std::fixed << std::setprecision(2)
00227 << " (" << (num / elapsed) << "/s)\n"
00228 << "Evaluations " << m_numEvals
00229 << std::fixed << std::setprecision(2)
00230 << " (" << (double(m_numEvals) / elapsed) << "/s)\n"
00231 << "Widenings " << m_numWidenings << '\n'
00232 << "New Lines " << newLines << '\n';
00233 PrintMessage(os.str());
00234 }
00235
00236 void SgBookBuilder::Refresh()
00237 {
00238 m_numEvals = 0;
00239 m_numWidenings = 0;
00240 m_valueUpdates = 0;
00241 m_priorityUpdates = 0;
00242 m_internalNodes = 0;
00243 m_leafNodes = 0;
00244 m_terminalNodes = 0;
00245
00246 SgTimer timer;
00247 Init();
00248 ClearAllVisited();
00249 Refresh(true);
00250 FlushBook();
00251 Fini();
00252 timer.Stop();
00253
00254 double elapsed = timer.GetTime();
00255 std::ostringstream os;
00256 os << '\n'
00257 << "Statistics\n"
00258 << "Total Time " << elapsed << '\n'
00259 << "Value Updates " << m_valueUpdates << '\n'
00260 << "Priority Updates " << m_priorityUpdates << '\n'
00261 << "Internal Nodes " << m_internalNodes << '\n'
00262 << "Terminal Nodes " << m_terminalNodes << '\n'
00263 << "Leaf Nodes " << m_leafNodes << '\n'
00264 << "Evaluations " << m_numEvals
00265 << std::fixed << std::setprecision(2)
00266 << " (" << (double(m_numEvals) / elapsed) << "/s)\n"
00267 << "Widenings " << m_numWidenings << '\n';
00268 PrintMessage(os.str());
00269 }
00270
00271 void SgBookBuilder::IncreaseWidth()
00272 {
00273 if (!m_useWidening)
00274 {
00275 PrintMessage("Widening not enabled!\n");
00276 return;
00277 }
00278
00279 m_numEvals = 0;
00280 m_numWidenings = 0;
00281
00282 SgTimer timer;
00283 Init();
00284 ClearAllVisited();
00285 IncreaseWidth(true);
00286 FlushBook();
00287 Fini();
00288 timer.Stop();
00289 double elapsed = timer.GetTime();
00290
00291 std::ostringstream os;
00292 os << '\n'
00293 << "Statistics\n"
00294 << "Total Time " << elapsed << '\n'
00295 << "Widenings " << m_numWidenings << '\n'
00296 << "Evaluations " << m_numEvals
00297 << std::fixed << std::setprecision(2)
00298 << " (" << (double(m_numEvals) / elapsed) << "/s)\n";
00299 PrintMessage(os.str());
00300 }
00301
00302
00303
00304
00305
00306
00307 bool SgBookBuilder::ExpandChildren(std::size_t count)
00308 {
00309
00310
00311
00312
00313
00314 float value = 0;
00315 std::vector<SgMove> children;
00316 if (GenerateMoves(children, value))
00317 {
00318 PrintMessage("ExpandChildren: State is determined!\n");
00319 WriteNode(SgBookNode(value));
00320 return false;
00321 }
00322 std::size_t limit = std::min(count, children.size());
00323 std::vector<SgMove> childrenToDo;
00324 for (std::size_t i = 0; i < limit; ++i)
00325 {
00326 PlayMove(children[i]);
00327 SgBookNode child;
00328 if (!GetNode(child))
00329 childrenToDo.push_back(children[i]);
00330 UndoMove(children[i]);
00331 }
00332 if (!childrenToDo.empty())
00333 {
00334 BeforeEvaluateChildren();
00335 std::vector<std::pair<SgMove, float> > scores;
00336 EvaluateChildren(childrenToDo, scores);
00337 AfterEvaluateChildren();
00338 for (std::size_t i = 0; i < scores.size(); ++i)
00339 {
00340 PlayMove(scores[i].first);
00341 WriteNode(scores[i].second);
00342 UndoMove(scores[i].first);
00343 }
00344 m_numEvals += childrenToDo.size();
00345 return true;
00346 }
00347 else
00348 PrintMessage("Children already evaluated.\n");
00349 return false;
00350 }
00351
00352 std::size_t SgBookBuilder::NumChildren(const std::vector<SgMove>& legal)
00353 {
00354 std::size_t num = 0;
00355 for (size_t i = 0; i < legal.size(); ++i)
00356 {
00357 PlayMove(legal[i]);
00358 SgBookNode child;
00359 if (GetNode(child))
00360 ++num;
00361 UndoMove(legal[i]);
00362 }
00363 return num;
00364 }
00365
00366 void SgBookBuilder::UpdateValue(SgBookNode& node,
00367 const std::vector<SgMove>& legal)
00368 {
00369 bool hasChild = false;
00370 float bestValue = boost::numeric::bounds<float>::lowest();
00371 for (std::size_t i = 0; i < legal.size(); ++i)
00372 {
00373 PlayMove(legal[i]);
00374 SgBookNode child;
00375 if (GetNode(child))
00376 {
00377 hasChild = true;
00378 float value = InverseEval(Value(child));
00379 if (value > bestValue)
00380 bestValue = value;
00381 }
00382 UndoMove(legal[i]);
00383 }
00384 if (hasChild)
00385 node.m_value = bestValue;
00386 }
00387
00388
00389
00390
00391
00392 void SgBookBuilder::UpdateValue(SgBookNode& node)
00393 {
00394 while (true)
00395 {
00396 std::vector<SgMove> legal;
00397 GetAllLegalMoves(legal);
00398 UpdateValue(node, legal);
00399 if (!IsLoss(Value(node)))
00400 break;
00401
00402
00403 std::size_t numChildren = NumChildren(legal);
00404 std::size_t width = (numChildren / m_expandWidth + 1)
00405 * m_expandWidth;
00406 {
00407 std::ostringstream os;
00408 os << "Forced Widening[" << numChildren << "->" << width << "]\n";
00409 PrintMessage(os.str());
00410 }
00411 if (!ExpandChildren(width))
00412 break;
00413 ++m_numWidenings;
00414 }
00415 }
00416
00417 float SgBookBuilder::ComputePriority(const SgBookNode& parent,
00418 const float childValue,
00419 const float childPriority) const
00420 {
00421 float delta = parent.m_value - InverseEval(childValue);
00422 SG_ASSERT(delta >= 0.0);
00423 return m_alpha * delta + childPriority + 1;
00424 }
00425
00426
00427
00428
00429 SgMove SgBookBuilder::UpdatePriority(SgBookNode& node)
00430 {
00431 bool hasChild = false;
00432 float bestPriority = boost::numeric::bounds<float>::highest();
00433 SgMove bestChild = SG_NULLMOVE;
00434 std::vector<SgMove> legal;
00435 GetAllLegalMoves(legal);
00436 for (std::size_t i = 0; i < legal.size(); ++i)
00437 {
00438 PlayMove(legal[i]);
00439 SgBookNode child;
00440 if (GetNode(child))
00441 {
00442 hasChild = true;
00443
00444
00445
00446 float childValue = Value(child);
00447 float childPriority = child.m_priority;
00448 float priority = ComputePriority(node, childValue, childPriority);
00449 if (priority < bestPriority)
00450 {
00451 bestPriority = priority;
00452 bestChild = legal[i];
00453 }
00454 }
00455 UndoMove(legal[i]);
00456 }
00457 if (hasChild)
00458 node.m_priority = bestPriority;
00459 return bestChild;
00460 }
00461
00462 void SgBookBuilder::DoExpansion(std::vector<SgMove>& pv)
00463 {
00464 SgBookNode node;
00465 if (!GetNode(node))
00466 SG_ASSERT(false);
00467 if (node.IsTerminal())
00468 return;
00469 if (node.IsLeaf())
00470 {
00471 ExpandChildren(m_expandWidth);
00472 }
00473 else
00474 {
00475
00476 if (m_useWidening && (node.m_count % m_expandThreshold == 0))
00477 {
00478 std::size_t width = (node.m_count / m_expandThreshold + 1)
00479 * m_expandWidth;
00480 ++m_numWidenings;
00481 ExpandChildren(width);
00482 }
00483
00484
00485 GetNode(node);
00486 UpdateValue(node);
00487 SgMove mostUrgent = UpdatePriority(node);
00488 WriteNode(node);
00489
00490
00491 if (!node.IsTerminal())
00492 {
00493 PlayMove(mostUrgent);
00494 pv.push_back(mostUrgent);
00495 DoExpansion(pv);
00496 pv.pop_back();
00497 UndoMove(mostUrgent);
00498 }
00499 }
00500 GetNode(node);
00501 UpdateValue(node);
00502 UpdatePriority(node);
00503 node.IncrementCount();
00504 WriteNode(node);
00505 }
00506
00507
00508
00509
00510
00511
00512
00513 bool SgBookBuilder::Refresh(bool root)
00514 {
00515 if (HasBeenVisited())
00516 return true;
00517 MarkAsVisited();
00518 SgBookNode node;
00519 if (!GetNode(node))
00520 return false;
00521 if (node.IsLeaf())
00522 {
00523 m_leafNodes++;
00524 if (node.IsTerminal())
00525 m_terminalNodes++;
00526 return true;
00527 }
00528 double oldValue = Value(node);
00529 double oldPriority = node.m_priority;
00530 std::vector<SgMove> legal;
00531 GetAllLegalMoves(legal);
00532 for (std::size_t i = 0; i < legal.size(); ++i)
00533 {
00534 PlayMove(legal[i]);
00535 Refresh(false);
00536 if (root)
00537 {
00538 std::ostringstream os;
00539 os << "Finished " << MoveString(legal[i]) << '\n';
00540 PrintMessage(os.str());
00541 }
00542 UndoMove(legal[i]);
00543 }
00544 UpdateValue(node);
00545 UpdatePriority(node);
00546 if (fabs(oldValue - Value(node)) > 0.0001)
00547 m_valueUpdates++;
00548 if (fabs(oldPriority - node.m_priority) > 0.0001)
00549 m_priorityUpdates++;
00550 WriteNode(node);
00551 if (node.IsTerminal())
00552 m_terminalNodes++;
00553 else
00554 m_internalNodes++;
00555 return true;
00556 }
00557
00558
00559
00560 void SgBookBuilder::IncreaseWidth(bool root)
00561 {
00562 if (HasBeenVisited())
00563 return;
00564 MarkAsVisited();
00565 SgBookNode node;
00566 if (!GetNode(node))
00567 return;
00568 if (node.IsTerminal() || node.IsLeaf())
00569 return;
00570 std::vector<SgMove> legal;
00571 GetAllLegalMoves(legal);
00572 for (std::size_t i = 0; i < legal.size(); ++i)
00573 {
00574 PlayMove(legal[i]);
00575 IncreaseWidth(false);
00576 if (root)
00577 {
00578 std::ostringstream os;
00579 os << "Finished " << MoveString(legal[i]) << '\n';
00580 PrintMessage(os.str());
00581 }
00582 UndoMove(legal[i]);
00583 }
00584 std::size_t width = (node.m_count / m_expandThreshold + 1)
00585 * m_expandWidth;
00586 if (ExpandChildren(width))
00587 ++m_numWidenings;
00588 }
00589
00590