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