00001
00002
00003
00004
00005
00006
00007
00008 #include "SgSystem.h"
00009
00010 #include "Hex.hpp"
00011 #include "VCSet.hpp"
00012 #include "HexProp.hpp"
00013 #include "HexBoard.hpp"
00014 #include "GraphUtils.hpp"
00015 #include "Resistance.hpp"
00016 #include "DfsSolver.hpp"
00017 #include "Time.hpp"
00018 #include "VCUtils.hpp"
00019 #include "BoardUtils.hpp"
00020 #include "BitsetIterator.hpp"
00021 #include "EndgameUtils.hpp"
00022 #include "ProofUtil.hpp"
00023
00024 #include <cmath>
00025 #include <algorithm>
00026 #include <boost/scoped_ptr.hpp>
00027
00028 using namespace benzene;
00029
00030
00031
00032
00033
00034
00035 const std::string DfsDB::DFS_DB_VERSION("BENZENE_DFS_DB_VER_0001");
00036
00037
00038
00039 DfsSolver::DfsSolver()
00040 : m_positions(0),
00041 m_use_decompositions(true),
00042 m_update_depth(4),
00043 m_shrink_proofs(true),
00044 m_backup_ice_info(true),
00045 m_use_guifx(false),
00046 m_move_ordering(DfsMoveOrderFlags::WITH_MUSTPLAY
00047 | DfsMoveOrderFlags::WITH_RESIST
00048 | DfsMoveOrderFlags::FROM_CENTER)
00049 {
00050 }
00051
00052 DfsSolver::~DfsSolver()
00053 {
00054 }
00055
00056
00057
00058 HexColor DfsSolver::Solve(const HexState& state, HexBoard& brd,
00059 DfsSolutionSet& solution, DfsStates& positions,
00060 int depthLimit, double timeLimit)
00061 {
00062 m_positions = &positions;
00063 m_depthLimit = depthLimit;
00064 m_timeLimit = timeLimit;
00065
00066 m_aborted = false;
00067 m_start_time = Time::Get();
00068 m_histogram = DfsHistogram();
00069 m_last_histogram_dump = 0;
00070 m_statistics = GlobalStatistics();
00071 m_state.reset(new HexState(state));
00072 m_workBrd = &brd;
00073
00074
00075 if (m_workBrd->ICE().FindPermanentlyInferior())
00076 throw BenzeneException("Permanently Inferior not supported "
00077 "in DfsSolver!");
00078
00079 DfsData data;
00080 bool win = false;
00081 HexColor toPlay = state.ToPlay();
00082 if (CheckTransposition(data))
00083 {
00084 LogInfo() << "DfsSolver: Found cached result!\n";
00085 win = data.m_win;
00086 solution.m_numMoves = data.m_numMoves;
00087 solution.pv.clear();
00088 SolverDBUtil::GetVariation(*m_state, positions, solution.pv);
00089 solution.proof = ProofUtil::MaximumProofSet(brd, data.m_win ?
00090 toPlay : !toPlay);
00091 }
00092 else
00093 {
00094 m_workBrd->ComputeAll(toPlay);
00095 m_completed.resize(BITSETSIZE);
00096 PointSequence variation;
00097 win = SolveState(variation, solution);
00098 }
00099 solution.proof &= m_state->Position().GetEmpty();
00100 m_end_time = Time::Get();
00101 if (m_aborted)
00102 return EMPTY;
00103 return win ? toPlay : !toPlay;
00104 }
00105
00106
00107
00108 bool DfsSolver::CheckTransposition(DfsData& data) const
00109 {
00110 return m_positions->Get(*m_state, data);
00111 }
00112
00113 void DfsSolver::StoreState(const DfsData& data, const bitset_t& proof)
00114 {
00115 m_positions->Put(*m_state, data);
00116 const SolverDBParameters& param = m_positions->Parameters();
00117 if (m_state->Position().NumStones() <= param.m_transStones)
00118 {
00119 HexColor toPlay = m_state->ToPlay();
00120 if (param.m_useProofTranspositions)
00121 ProofUtil::StoreTranspositions(*m_positions, data,
00122 *m_state, proof,
00123 data.m_win ? toPlay : !toPlay);
00124 if (param.m_useFlippedStates)
00125 ProofUtil::StoreFlippedStates(*m_positions, data,
00126 *m_state, proof,
00127 data.m_win ? toPlay : !toPlay);
00128 }
00129 }
00130
00131
00132
00133
00134
00135
00136 bool DfsSolver::CheckAbort()
00137 {
00138 if (!m_aborted)
00139 {
00140 if (SgUserAbort())
00141 {
00142 m_aborted = true;
00143 LogInfo() << "DfsSolver::CheckAbort(): Abort flag!\n";
00144 }
00145 else if ((m_timeLimit > 0) &&
00146 ((Time::Get() - m_start_time) > m_timeLimit))
00147 {
00148 m_aborted = true;
00149 LogInfo() << "DfsSolver::CheckAbort(): Timelimit!\n";
00150 }
00151 }
00152 return m_aborted;
00153 }
00154
00155
00156
00157
00158 bool DfsSolver::HandleTerminalNode(DfsData& data, bitset_t& proof) const
00159 {
00160 int numstones = m_state->Position().NumStones();
00161 if (EndgameUtils::IsWonGame(*m_workBrd, m_state->ToPlay(), proof))
00162 {
00163 data.m_win = true;
00164 data.m_numMoves = 0;
00165 data.m_numStates = 1;
00166 m_histogram.terminal[numstones]++;
00167 return true;
00168 }
00169 else if (EndgameUtils::IsLostGame(*m_workBrd, m_state->ToPlay(), proof))
00170 {
00171 data.m_win = false;
00172 data.m_numMoves = 0;
00173 data.m_numStates = 1;
00174 m_histogram.terminal[numstones]++;
00175 return true;
00176 }
00177 return false;
00178 }
00179
00180
00181
00182 bool DfsSolver::HandleLeafNode(DfsData& data, bitset_t& proof) const
00183 {
00184 if (HandleTerminalNode(data, proof))
00185 return true;
00186 if (CheckTransposition(data))
00187 {
00188 HexColor color = m_state->ToPlay();
00189 proof = ProofUtil::MaximumProofSet(*m_workBrd,
00190 data.m_win ? color : !color);
00191 }
00192 return false;
00193 }
00194
00195
00196
00197
00198
00199 bool DfsSolver::SolveState(PointSequence& variation, DfsSolutionSet& solution)
00200 {
00201 if (CheckAbort())
00202 return false;
00203
00204
00205 {
00206 DfsData data;
00207 bitset_t proof;
00208 if (HandleLeafNode(data, proof))
00209 {
00210 solution.pv.clear();
00211 solution.m_numMoves = data.m_numMoves;
00212 solution.proof = proof;
00213 solution.stats.explored_states = 1;
00214 solution.stats.minimal_explored = 1;
00215 solution.stats.total_states += data.m_numStates;
00216 return data.m_win;
00217 }
00218 }
00219
00220
00221
00222 bool winning_state = false;
00223 {
00224 HexColor color = m_state->ToPlay();
00225 HexPoint group;
00226 if (m_use_decompositions
00227 && BoardUtils::FindSplittingDecomposition(*m_workBrd, !color, group))
00228 {
00229 winning_state = SolveDecomposition(variation, solution, group);
00230 }
00231 else
00232 {
00233 winning_state = SolveInteriorState(variation, solution);
00234 }
00235 }
00236
00237
00238 HandleProof(variation, winning_state, solution);
00239
00240
00241 if ((m_statistics.played / 1000000) > (m_last_histogram_dump))
00242 {
00243 LogInfo() << m_histogram.Write() << '\n';
00244 m_last_histogram_dump = m_statistics.played / 1000000;
00245 }
00246 return winning_state;
00247 }
00248
00249
00250
00251 bool DfsSolver::SolveDecomposition(PointSequence& variation,
00252 DfsSolutionSet& solution, HexPoint group)
00253 {
00254 HexColor color = m_state->ToPlay();
00255 solution.stats.decompositions++;
00256
00257
00258 PointToBitset nbs;
00259 GraphUtils::ComputeDigraph(m_workBrd->GetGroups(), !color, nbs);
00260 bitset_t stopset = nbs[group];
00261
00262 bitset_t carrier[2];
00263 carrier[0] =
00264 GraphUtils::BFS(HexPointUtil::colorEdge1(!color), nbs, stopset);
00265 carrier[1] =
00266 GraphUtils::BFS(HexPointUtil::colorEdge2(!color), nbs, stopset);
00267
00268 if ((carrier[0] & carrier[1]).any())
00269 throw BenzeneException()
00270 << "DfsSolver::SolveDecomposition:\n"
00271 << "Side0:" << m_workBrd->Write(carrier[0]) << '\n'
00272 << "Side1:" << m_workBrd->Write(carrier[1]) << '\n';
00273
00274 DfsData data;
00275 DfsSolutionSet dsolution[2];
00276 for (int s = 0; s < 2; ++s)
00277 {
00278 bool win = false;
00279 m_workBrd->PlayStones(!color,
00280 carrier[s^1] & m_workBrd->Const().GetCells(),
00281 color);
00282
00283 bitset_t proof;
00284 if (HandleTerminalNode(data, proof))
00285 {
00286 win = data.m_win;
00287 dsolution[s].proof = proof;
00288 dsolution[s].m_numMoves = data.m_numMoves;
00289 dsolution[s].pv.clear();
00290 dsolution[s].stats.expanded_states = 0;
00291 dsolution[s].stats.explored_states = 1;
00292 dsolution[s].stats.minimal_explored = 1;
00293 dsolution[s].stats.total_states = 1;
00294 }
00295 else
00296 win = SolveInteriorState(variation, dsolution[s]);
00297
00298 m_workBrd->UndoMove();
00299
00300 if (win)
00301 {
00302 solution.pv = dsolution[s].pv;
00303 solution.proof = dsolution[s].proof;
00304 solution.m_numMoves = dsolution[s].m_numMoves;
00305 solution.stats += dsolution[s].stats;
00306 solution.stats.decompositions_won++;
00307 return true;
00308 }
00309 }
00310
00311
00312 solution.pv = dsolution[0].pv;
00313 solution.m_numMoves = dsolution[0].m_numMoves + dsolution[1].m_numMoves;
00314 solution.pv.insert(solution.pv.end(), dsolution[1].pv.begin(),
00315 dsolution[1].pv.end());
00316
00317 solution.proof = (dsolution[0].proof & carrier[0])
00318 | (dsolution[1].proof & carrier[1])
00319 | m_workBrd->GetPosition().GetColor(!color);
00320 solution.proof = solution.proof - m_workBrd->GetDead();
00321 return false;
00322 }
00323
00324
00325 bool DfsSolver::SolveInteriorState(PointSequence& variation,
00326 DfsSolutionSet& solution)
00327 {
00328 HexColor color = m_state->ToPlay();
00329 int numstones = m_state->Position().NumStones();
00330
00331
00332
00333
00334
00335
00336
00337
00338 solution.proof = ProofUtil::InitialProofForOpponent(*m_workBrd, color);
00339 bitset_t mustplay = EndgameUtils::MovesToConsider(*m_workBrd, color);
00340 HexAssert(mustplay.any());
00341
00342 int depth = variation.size();
00343 if (m_use_guifx && depth == m_update_depth)
00344 {
00345 std::ostringstream os;
00346 os << "gogui-gfx:\n";
00347 os << "solver\n";
00348 os << "VAR";
00349 HexColor toplay = (variation.size() & 1) ? !color : color;
00350 for (std::size_t i = 0; i < variation.size(); ++i)
00351 {
00352 os << ' ' << (toplay == BLACK ? 'B' : 'W');
00353 os << ' ' << variation[i];
00354 toplay = !toplay;
00355 }
00356 os << '\n';
00357 os << "LABEL ";
00358 const InferiorCells& inf = m_workBrd->GetInferiorCells();
00359 os << inf.GuiOutput();
00360 os << BoardUtils::GuiDumpOutsideConsiderSet(m_workBrd->GetPosition(),
00361 mustplay, inf.All());
00362 os << '\n';
00363 os << "TEXT";
00364 for (int i = 0; i < depth; ++i)
00365 os << ' ' << m_completed[i].first << '/' << m_completed[i].second;
00366 os << '\n';
00367 os << '\n';
00368 std::cout << os.str();
00369 std::cout.flush();
00370 }
00371
00372 bitset_t original_mustplay = mustplay;
00373 solution.stats.total_states = 1;
00374 solution.stats.explored_states = 1;
00375 solution.stats.minimal_explored = 1;
00376 solution.stats.expanded_states = 1;
00377 solution.stats.moves_to_consider = mustplay.count();
00378 m_histogram.states[numstones]++;
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389 solution.m_numMoves = -1;
00390 std::vector<HexMoveValue> moves;
00391 bool winning_state = OrderMoves(mustplay, solution, moves);
00392
00393
00394
00395
00396 std::size_t states_under_losing = 0;
00397
00398 for (unsigned index = 0;
00399 !winning_state && index < moves.size();
00400 ++index)
00401 {
00402 HexPoint cell = moves[index].point();
00403 m_completed[depth] = std::make_pair(index, moves.size());
00404 if (!mustplay.test(cell))
00405 {
00406 solution.stats.pruned++;
00407 continue;
00408 }
00409
00410 DfsSolutionSet child;
00411 PlayMove(cell);
00412 variation.push_back(cell);
00413 bool win = !SolveState(variation, child);
00414 variation.pop_back();
00415 UndoMove(cell);
00416 solution.stats += child.stats;
00417
00418 if (win)
00419 {
00420
00421 winning_state = true;
00422 solution.proof = child.proof;
00423 solution.SetPV(cell, child.pv);
00424 solution.m_numMoves = child.m_numMoves + 1;
00425 solution.stats.winning_expanded++;
00426 solution.stats.minimal_explored = child.stats.minimal_explored + 1;
00427 solution.stats.branches_to_win += index + 1;
00428
00429 m_histogram.winning[numstones]++;
00430 m_histogram.size_of_winning_states[numstones]
00431 += child.stats.explored_states;
00432 m_histogram.branches[numstones] += index + 1;
00433 m_histogram.states_under_losing[numstones] += states_under_losing;
00434 m_histogram.mustplay[numstones] += original_mustplay.count();
00435
00436 HexAssert(solution.m_numMoves != -1);
00437 }
00438 else
00439 {
00440
00441
00442 mustplay &= child.proof;
00443 solution.proof |= child.proof;
00444 states_under_losing += child.stats.explored_states;
00445
00446 m_histogram.size_of_losing_states[numstones]
00447 += child.stats.explored_states;
00448
00449 if (child.m_numMoves + 1 > solution.m_numMoves)
00450 {
00451 solution.m_numMoves = child.m_numMoves + 1;
00452 solution.SetPV(cell, child.pv);
00453 }
00454 HexAssert(solution.m_numMoves != -1);
00455 }
00456 }
00457 HexAssert(solution.m_numMoves != -1);
00458 return winning_state;
00459 }
00460
00461
00462 void DfsSolver::HandleProof(const PointSequence& variation,
00463 bool winning_state, DfsSolutionSet& solution)
00464 {
00465 if (m_aborted)
00466 return;
00467 HexColor color = m_state->ToPlay();
00468 HexColor winner = (winning_state) ? color : !color;
00469 HexColor loser = !winner;
00470
00471 if ((m_workBrd->GetPosition().GetColor(loser) & solution.proof).any())
00472 throw BenzeneException()
00473 << "DfsSolver::HandleProof:\n"
00474 << color << " to play.\n"
00475 << loser << " loses.\n"
00476 << "Losing stones hit proof:\n"
00477 << m_workBrd->Write(solution.proof) << '\n'
00478 << *m_workBrd << '\n'
00479 << "PV: " << HexPointUtil::ToString(variation) << '\n';
00480
00481 if ((m_workBrd->GetDead() & solution.proof).any())
00482 throw BenzeneException()
00483 << "DfsSolver::HandleProof:\n"
00484 << color << " to play.\n"
00485 << loser << " loses.\n"
00486 << "Dead cells hit proof:\n"
00487 << m_workBrd->Write(solution.proof) << '\n'
00488 << *m_workBrd << '\n'
00489 << "PV: " << HexPointUtil::ToString(variation) << '\n';
00490
00491 bitset_t old_proof = solution.proof;
00492 if (m_shrink_proofs)
00493 {
00494 ProofUtil::ShrinkProof(solution.proof, m_state->Position(), loser,
00495 m_workBrd->ICE());
00496 bitset_t pruned;
00497 pruned = BoardUtils::ReachableOnBitset(m_workBrd->Const(),
00498 solution.proof,
00499 EMPTY_BITSET,
00500 HexPointUtil::colorEdge1(winner));
00501 pruned &= BoardUtils::ReachableOnBitset(m_workBrd->Const(),
00502 solution.proof,
00503 EMPTY_BITSET,
00504 HexPointUtil::colorEdge2(winner));
00505 solution.proof = pruned;
00506
00507 if (solution.proof.count() < old_proof.count())
00508 {
00509 solution.stats.shrunk++;
00510 solution.stats.cells_removed
00511 += old_proof.count() - solution.proof.count();
00512 }
00513 }
00514
00515 if (!BoardUtils::ConnectedOnBitset(m_workBrd->Const(), solution.proof,
00516 HexPointUtil::colorEdge1(winner),
00517 HexPointUtil::colorEdge2(winner)))
00518 throw BenzeneException()
00519 << "DfsSolver::HandleProof:\n"
00520 << "Proof does not touch both edges!\n"
00521 << m_workBrd->Write(solution.proof) << '\n'
00522 << "Original proof:\n"
00523 << m_workBrd->Write(old_proof) << '\n'
00524 << *m_workBrd << '\n'
00525 << color << " to play.\n"
00526 << "PV: " << HexPointUtil::ToString(variation) << '\n';
00527
00528
00529
00530
00531
00532
00533 if (solution.pv.empty())
00534 solution.pv.push_back(INVALID_POINT);
00535
00536 StoreState(DfsData(winning_state, solution.stats.total_states,
00537 solution.m_numMoves, solution.pv[0]),
00538 solution.proof);
00539 }
00540
00541
00542
00543
00544 void DfsSolver::PlayMove(HexPoint cell)
00545 {
00546 m_statistics.played++;
00547 m_workBrd->PlayMove(m_state->ToPlay(), cell);
00548 m_state->PlayMove(cell);
00549
00550 }
00551
00552
00553 void DfsSolver::UndoMove(HexPoint cell)
00554 {
00555 m_state->UndoMove(cell);
00556 m_workBrd->UndoMove();
00557 }
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570 bool DfsSolver::OrderMoves(bitset_t& mustplay, DfsSolutionSet& solution,
00571 std::vector<HexMoveValue>& moves)
00572 {
00573 LogFine() << "OrderMoves\n";
00574 HexColor color = m_state->ToPlay();
00575 HexColor other = !color;
00576
00577
00578 bitset_t proof_union;
00579 bitset_t proof_intersection;
00580 proof_intersection.set();
00581
00582
00583
00584
00585
00586 bool found_win = false;
00587 bitset_t losingMoves;
00588 for (BitsetIterator it(mustplay); !found_win && it; ++it)
00589 {
00590 m_workBrd->GetPosition().PlayMove(color, *it);
00591 m_state->PlayMove(*it);
00592
00593 DfsData data;
00594 if (CheckTransposition(data))
00595 {
00596 solution.stats.explored_states += 1;
00597 solution.stats.minimal_explored++;
00598 solution.stats.total_states += data.m_numStates;
00599
00600 if (!data.m_win)
00601 {
00602 found_win = true;
00603 moves.clear();
00604 moves.push_back(HexMoveValue(*it, 0));
00605
00606
00607 solution.stats.minimal_explored = 2;
00608 solution.proof = ProofUtil::MaximumProofSet(*m_workBrd, color);
00609 solution.m_numMoves = data.m_numMoves + 1;
00610 solution.SetPV(*it);
00611 }
00612 else
00613 {
00614
00615 losingMoves.set(*it);
00616 if (data.m_numMoves + 1 > solution.m_numMoves)
00617 {
00618 solution.m_numMoves = data.m_numMoves + 1;
00619 solution.SetPV(*it);
00620 }
00621
00622 bitset_t proof = ProofUtil::MaximumProofSet(*m_workBrd, !color);
00623 proof_intersection &= proof;
00624 proof_union |= proof;
00625 }
00626 }
00627 m_workBrd->GetPosition().UndoMove(*it);
00628 m_state->UndoMove(*it);
00629 }
00630
00631 if (found_win)
00632 {
00633 HexAssert(moves.size() == 1);
00634 LogFine() << "Found winning move; aborted ordering.\n";
00635 return true;
00636 }
00637
00638
00639 boost::scoped_ptr<Resistance> resist;
00640 bool with_ordering = m_move_ordering;
00641 bool with_resist = m_move_ordering & DfsMoveOrderFlags::WITH_RESIST;
00642 bool with_center = m_move_ordering & DfsMoveOrderFlags::FROM_CENTER;
00643 bool with_mustplay = m_move_ordering & DfsMoveOrderFlags::WITH_MUSTPLAY;
00644
00645 if (with_resist && with_ordering)
00646 {
00647 resist.reset(new Resistance());
00648 resist->Evaluate(*m_workBrd);
00649 }
00650
00651 moves.clear();
00652 for (BitsetIterator it(mustplay); !found_win && it; ++it)
00653 {
00654 bool skip_this_move = false;
00655 double score = 0.0;
00656
00657
00658 if (losingMoves.test(*it))
00659 continue;
00660
00661 if (with_ordering)
00662 {
00663 double mustplay_size = 0.0;
00664 double fromcenter = 0.0;
00665 double rscore = 0.0;
00666 double tiebreaker = 0.0;
00667 bool exact_score = false;
00668 bool winning_semi_exists = false;
00669
00670
00671
00672
00673
00674
00675 if (with_mustplay)
00676 {
00677 PlayMove(*it);
00678
00679 DfsData data;
00680 bitset_t proof;
00681
00682 if (HandleTerminalNode(data, proof))
00683 {
00684 exact_score = true;
00685 solution.stats.minimal_explored++;
00686 solution.stats.explored_states++;
00687 solution.stats.total_states += data.m_numStates;
00688 if (!data.m_win)
00689 {
00690 found_win = true;
00691 moves.clear();
00692
00693
00694
00695 solution.stats.minimal_explored = 2;
00696 solution.proof = proof;
00697 solution.m_numMoves = data.m_numMoves + 1;
00698 solution.SetPV(*it);
00699 }
00700 else
00701 {
00702 skip_this_move = true;
00703 if (data.m_numMoves + 1 > solution.m_numMoves)
00704 {
00705 solution.m_numMoves = data.m_numMoves + 1;
00706 solution.SetPV(*it);
00707 }
00708
00709 proof_intersection &= proof;
00710 proof_union |= proof;
00711 }
00712 }
00713 else
00714 {
00715
00716
00717 HexPoint edge1 = HexPointUtil::colorEdge1(color);
00718 HexPoint edge2 = HexPointUtil::colorEdge2(color);
00719 if (m_workBrd->Cons(color).Exists(edge1, edge2, VC::SEMI))
00720 winning_semi_exists = true;
00721 bitset_t mp = VCUtils::GetMustplay(*m_workBrd, other);
00722 mustplay_size = mp.count();
00723 }
00724
00725 UndoMove(*it);
00726 }
00727
00728
00729 if (!exact_score)
00730 {
00731 if (with_center)
00732 {
00733 fromcenter
00734 += DfsSolverUtil::DistanceFromCenter(m_workBrd->Const(), *it);
00735 }
00736 if (with_resist)
00737 {
00738 rscore = resist->Score(*it);
00739 HexAssert(rscore < 100.0);
00740 }
00741 tiebreaker = (with_resist) ? 100.0 - rscore : fromcenter;
00742
00743 if (winning_semi_exists)
00744 score = 1000.0 * mustplay_size + tiebreaker;
00745 else
00746 score = 1000000.0 * tiebreaker;
00747 }
00748 }
00749 if (!skip_this_move)
00750 moves.push_back(HexMoveValue(*it, score));
00751 }
00752 HexAssert(!found_win || moves.size() == 1);
00753
00754
00755
00756 stable_sort(moves.begin(), moves.end());
00757
00758
00759 if (found_win)
00760 LogFine() << "Found winning move; aborted ordering.\n";
00761
00762
00763
00764
00765 else
00766 {
00767 if (m_backup_ice_info)
00768 {
00769 bitset_t new_initial_proof
00770 = ProofUtil::InitialProofForOpponent(*m_workBrd, color);
00771 bitset_t new_mustplay
00772 = EndgameUtils::MovesToConsider(*m_workBrd, color);
00773 HexAssert(BitsetUtil::IsSubsetOf(new_mustplay, mustplay));
00774
00775 if (new_mustplay.count() < mustplay.count())
00776 {
00777 LogFine() << "Pruned mustplay with backing-up info."
00778 << m_workBrd->Write(mustplay)
00779 << m_workBrd->Write(new_mustplay) << '\n';
00780 mustplay = new_mustplay;
00781 solution.proof = new_initial_proof;
00782 }
00783 }
00784 mustplay &= proof_intersection;
00785 solution.proof |= proof_union;
00786 }
00787 return found_win;
00788 }
00789
00790
00791
00792 std::string DfsHistogram::Write()
00793 {
00794 std::ostringstream os;
00795 os << '\n'
00796 << "Histogram\n"
00797 << " States "
00798 << " Branch Info "
00799 << " TT/DB "
00800 << '\n'
00801 << std::setw(3) << "#" << " "
00802 << std::setw(12) << "Terminal"
00803 << std::setw(12) << "Internal"
00804 << std::setw(12) << "Int. Win"
00805 << std::setw(12) << "Win Pct"
00806 << std::setw(12) << "Sz Winning"
00807 << std::setw(12) << "Sz Losing"
00808 << std::setw(12) << "To Win"
00809 << std::setw(12) << "Mustplay"
00810 << std::setw(12) << "U/Losing"
00811 << std::setw(12) << "Cost"
00812 << std::setw(12) << "Hits"
00813 << std::setw(12) << "Pct"
00814 << '\n';
00815
00816 for (int p = 0; p < FIRST_INVALID; ++p)
00817 {
00818 if (!states[p] && !terminal[p])
00819 continue;
00820 double moves_to_find_winning = winning[p]
00821 ? (double)branches[p] / winning[p] : 0;
00822 double avg_states_under_losing = (branches[p] - winning[p])
00823 ?((double)states_under_losing[p] / (branches[p] - winning[p])):0;
00824 os << std::setw(3) << p << ":"
00825 << std::setw(12) << terminal[p]
00826 << std::setw(12) << states[p]
00827 << std::setw(12) << winning[p]
00828 << std::setw(12) << std::fixed << std::setprecision(3)
00829 << ((states[p])?((double)winning[p]*100.0/states[p]):0)
00830 << std::setw(12) << std::fixed << std::setprecision(1)
00831 << ((winning[p])
00832 ? ((double)size_of_winning_states[p] / winning[p])
00833 : 0)
00834 << std::setw(12) << std::fixed << std::setprecision(1)
00835 << ((states[p] - winning[p])
00836 ? ((double)(size_of_losing_states[p]
00837 / (states[p] - winning[p])))
00838 :0)
00839 << std::setw(12) << std::fixed << std::setprecision(4)
00840 << moves_to_find_winning
00841 << std::setw(12) << std::fixed << std::setprecision(2)
00842 << ((winning[p]) ? ((double)mustplay[p] / winning[p]) : 0)
00843 << std::setw(12) << std::fixed << std::setprecision(1)
00844 << avg_states_under_losing
00845 << std::setw(12) << std::fixed << std::setprecision(1)
00846 << fabs((moves_to_find_winning - 1.0)
00847 * avg_states_under_losing * winning[p])
00848 << std::setw(12) << tthits[p]
00849 << std::setw(12) << std::fixed << std::setprecision(3)
00850 << ((states[p]) ? ((double)tthits[p] * 100.0 / states[p]) : 0)
00851 << '\n';
00852 }
00853 return os.str();
00854 }
00855
00856 void DfsSolver::DumpStats(const DfsSolutionSet& solution) const
00857 {
00858 const double total_time = m_end_time - m_start_time;
00859 std::ostringstream os;
00860 os << '\n'
00861 << "Played " << m_statistics.played << '\n'
00862 << "Pruned " << solution.stats.pruned << '\n'
00863 << "Total States " << solution.stats.total_states << '\n'
00864 << "Explored States " << solution.stats.explored_states
00865 << " (" << solution.stats.minimal_explored << ")" << '\n'
00866 << "Expanded States " << solution.stats.expanded_states << '\n'
00867 << "Decompositions " << solution.stats.decompositions << '\n'
00868 << "Decomps won " << solution.stats.decompositions_won << '\n'
00869 << "Shrunk Proofs " << solution.stats.shrunk << '\n'
00870 << "Avg. Shrink " << ((double)solution.stats.cells_removed
00871 / solution.stats.shrunk) << '\n'
00872 << "Branch Factor " << ((double)solution.stats.moves_to_consider
00873 / solution.stats.expanded_states) << '\n'
00874 << "To Find Win " << ((double)solution.stats.branches_to_win
00875 / solution.stats.winning_expanded) << '\n'
00876 << "States/sec " << (solution.stats.explored_states
00877 / total_time) << '\n'
00878 << "Played/sec " << (m_statistics.played/total_time) << '\n'
00879 << "Total Time " << Time::Formatted(total_time) << '\n'
00880 << "Moves to W/L " << solution.m_numMoves << " moves\n"
00881 << "PV " << HexPointUtil::ToString(solution.pv) << '\n';
00882 if (m_positions->Database())
00883 os << '\n' << m_positions->Database()->GetStatistics().Write() << '\n';
00884 if (m_positions->HashTable())
00885 os << '\n' << m_positions->HashTable()->Stats();
00886 LogInfo() << os.str();
00887 }
00888
00889
00890
00891 int DfsSolverUtil::DistanceFromCenter(const ConstBoard& brd, HexPoint cell)
00892 {
00893
00894 if ((brd.Width() & 1) && (brd.Height() & 1))
00895 return brd.Distance(BoardUtils::CenterPoint(brd), cell);
00896
00897
00898
00899
00900 return brd.Distance(BoardUtils::CenterPointRight(brd), cell)
00901 + brd.Distance(BoardUtils::CenterPointLeft(brd), cell);
00902 }
00903
00904