+ // Start with a small aspiration window and, in case of fail high/low,
+ // research with bigger window until not failing high/low anymore.
+ do {
+ // Search starts from ss+1 to allow referencing (ss-1). This is
+ // needed by update gains and ss copy when splitting at Root.
+ bestValue = search<Root>(pos, ss+1, alpha, beta, depth * ONE_PLY);
+
+ // Bring to front the best move. It is critical that sorting is
+ // done with a stable algorithm because all the values but the first
+ // and eventually the new best one are set to -VALUE_INFINITE and
+ // we want to keep the same order for all the moves but the new
+ // PV that goes to the front. Note that in case of MultiPV search
+ // the already searched PV lines are preserved.
+ sort<RootMove>(Rml.begin() + MultiPVIdx, Rml.end());
+
+ // In case we have found an exact score and we are going to leave
+ // the fail high/low loop then reorder the PV moves, otherwise
+ // leave the last PV move in its position so to be searched again.
+ // Of course this is needed only in MultiPV search.
+ if (MultiPVIdx && bestValue > alpha && bestValue < beta)
+ sort<RootMove>(Rml.begin(), Rml.begin() + MultiPVIdx);
+
+ // Write PV back to transposition table in case the relevant entries
+ // have been overwritten during the search.
+ for (int i = 0; i <= MultiPVIdx; i++)
+ Rml[i].insert_pv_in_tt(pos);
+
+ // If search has been stopped exit the aspiration window loop,
+ // note that sorting and writing PV back to TT is safe becuase
+ // Rml is still valid, although refers to the previous iteration.
+ if (Signals.stop)
+ break;
+
+ // Send full PV info to GUI if we are going to leave the loop or
+ // if we have a fail high/low and we are deep in the search. UCI
+ // protocol requires to send all the PV lines also if are still
+ // to be searched and so refer to the previous search's score.
+ if ((bestValue > alpha && bestValue < beta) || elapsed_time() > 2000)
+ for (int i = 0; i < std::min(UCIMultiPV, (int)Rml.size()); i++)
+ {
+ bool updated = (i <= MultiPVIdx);
+
+ if (depth == 1 && !updated)
+ continue;
+
+ Depth d = (updated ? depth : depth - 1) * ONE_PLY;
+ Value s = (updated ? Rml[i].score : Rml[i].prevScore);
+
+ cout << "info"
+ << depth_to_uci(d)
+ << (i == MultiPVIdx ? score_to_uci(s, alpha, beta) : score_to_uci(s))
+ << speed_to_uci(pos.nodes_searched())
+ << pv_to_uci(&Rml[i].pv[0], i + 1, pos.is_chess960())
+ << endl;
+ }
+
+ // In case of failing high/low increase aspiration window and
+ // research, otherwise exit the fail high/low loop.
+ if (bestValue >= beta)
+ {
+ beta = std::min(beta + aspirationDelta, VALUE_INFINITE);
+ aspirationDelta += aspirationDelta / 2;
+ }
+ else if (bestValue <= alpha)
+ {
+ Signals.failedLowAtRoot = true;
+ Signals.stopOnPonderhit = false;
+
+ alpha = std::max(alpha - aspirationDelta, -VALUE_INFINITE);
+ aspirationDelta += aspirationDelta / 2;
+ }
+ else
+ break;
+
+ } while (abs(bestValue) < VALUE_KNOWN_WIN);
+ }