// Step 14. Reduced search
+ int ReductionLevel; // 0 = most aggressive reductions, 7 = minimum reductions
+
// Reduction lookup tables (initialized at startup) and their getter functions
- int8_t PVReductionMatrix[64][64]; // [depth][moveNumber]
- int8_t NonPVReductionMatrix[64][64]; // [depth][moveNumber]
+ int8_t PVReductionMatrix[8][64][64]; // [depth][moveNumber]
+ int8_t NonPVReductionMatrix[8][64][64]; // [depth][moveNumber]
- inline Depth pv_reduction(Depth d, int mn) { return (Depth) PVReductionMatrix[Min(d / 2, 63)][Min(mn, 63)]; }
- inline Depth nonpv_reduction(Depth d, int mn) { return (Depth) NonPVReductionMatrix[Min(d / 2, 63)][Min(mn, 63)]; }
+ inline Depth pv_reduction(Depth d, int mn) { return (Depth) PVReductionMatrix[ReductionLevel][Min(d / 2, 63)][Min(mn, 63)]; }
+ inline Depth nonpv_reduction(Depth d, int mn) { return (Depth) NonPVReductionMatrix[ReductionLevel][Min(d / 2, 63)][Min(mn, 63)]; }
// Common adjustments
return !Quit;
}
+// init_reduction_tables() is called by init_search() and initializes
+// the tables used by LMR.
+static void init_reduction_tables(int8_t pvTable[64][64], int8_t nonPvTable[64][64], int pvInhib, int nonPvInhib)
+{
+ double pvBase = 1.001 - log(3.0) * log(16.0) / pvInhib;
+ double nonPvBase = 1.001 - log(3.0) * log(4.0) / nonPvInhib;
-/// init_search() is called during startup. It initializes various lookup tables
-
-void init_search() {
-
- // Init our reduction lookup tables
for (int i = 1; i < 64; i++) // i == depth (OnePly = 1)
for (int j = 1; j < 64; j++) // j == moveNumber
{
- double pvRed = 0.5 + log(double(i)) * log(double(j)) / 6.0;
- double nonPVRed = 0.5 + log(double(i)) * log(double(j)) / 3.0;
- PVReductionMatrix[i][j] = (int8_t) ( pvRed >= 1.0 ? floor( pvRed * int(OnePly)) : 0);
- NonPVReductionMatrix[i][j] = (int8_t) (nonPVRed >= 1.0 ? floor(nonPVRed * int(OnePly)) : 0);
+ double pvRed = pvBase + log(double(i)) * log(double(j)) / pvInhib;
+ double nonPVRed = nonPvBase + log(double(i)) * log(double(j)) / nonPvInhib;
+
+ pvTable[i][j] = (int8_t) ( pvRed >= 1.0 ? floor( pvRed * int(OnePly)) : 0);
+ nonPvTable[i][j] = (int8_t) (nonPVRed >= 1.0 ? floor(nonPVRed * int(OnePly)) : 0);
}
+}
+
+// init_search() is called during startup. It initializes various lookup tables
+void init_search() {
+
+ // Init reduction lookup tables
+ for (int i = 0; i < 8; i++)
+ init_reduction_tables(PVReductionMatrix[i], NonPVReductionMatrix[i], int(4 * pow(1.3, i)), int(2 * pow(1.3, i)));
// Init futility margins array
for (int i = 0; i < 16; i++) // i == depth (OnePly = 2)
beta = Min(ValueByIteration[Iteration - 1] + AspirationDelta, VALUE_INFINITE);
}
+ // Choose optimum reduction level
+ ReductionLevel = 2;
+
+ if (UseTimeManagement)
+ {
+ int level = int(floor(log(float(MaxSearchTime) / current_search_time()) / log(2.0) + 1.0));
+ ReductionLevel = Min(Max(level, 0), 7);
+ }
+ else
+ {
+ //FIXME
+ }
+
// Search to the current depth, rml is updated and sorted, alpha and beta could change
value = root_search(p, ss, rml, &alpha, &beta);
tte = TT.retrieve(pos.get_key());
}
- // Step 10. Loop through moves
- // Loop through all legal moves until no moves remain or a beta cutoff occurs
-
// Initialize a MovePicker object for the current position
mateThreat = pos.has_mate_threat(opposite_color(pos.side_to_move()));
MovePicker mp = MovePicker(pos, ttMove, depth, H, &ss[ply]);
CheckInfo ci(pos);
+ // Step 10. Loop through moves
+ // Loop through all legal moves until no moves remain or a beta cutoff occurs
while ( alpha < beta
&& (move = mp.get_next_move()) != MOVE_NONE
&& !TM.thread_should_stop(threadID))
}
// Step 6. Razoring
- if ( !value_is_mate(beta)
+ if ( refinedValue < beta - razor_margin(depth)
+ && ttMove == MOVE_NONE
+ && ss[ply - 1].currentMove != MOVE_NULL
+ && depth < RazorDepth
&& !isCheck
- && depth < RazorDepth
- && refinedValue < beta - razor_margin(depth)
- && ss[ply - 1].currentMove != MOVE_NULL
- && ttMove == MOVE_NONE
+ && !value_is_mate(beta)
&& !pos.has_pawn_on_7th(pos.side_to_move()))
{
Value rbeta = beta - razor_margin(depth);
// Step 7. Static null move pruning
// We're betting that the opponent doesn't have a move that will reduce
- // the score by more than fuility_margin(depth) if we do a null move.
- if ( !isCheck
- && allowNullmove
- && depth < RazorDepth
- && refinedValue - futility_margin(depth, 0) >= beta)
+ // the score by more than futility_margin(depth) if we do a null move.
+ if ( allowNullmove
+ && depth < RazorDepth
+ && !isCheck
+ && !value_is_mate(beta)
+ && ok_to_do_nullmove(pos)
+ && refinedValue >= beta + futility_margin(depth, 0))
return refinedValue - futility_margin(depth, 0);
// Step 8. Null move search with verification search
{
ss[ply].currentMove = MOVE_NULL;
- pos.do_null_move(st);
-
// Null move dynamic reduction based on depth
int R = 3 + (depth >= 5 * OnePly ? depth / 8 : 0);
if (refinedValue - beta > PawnValueMidgame)
R++;
+ pos.do_null_move(st);
+
nullValue = -search(pos, ss, -(beta-1), depth-R*OnePly, ply+1, false, threadID);
pos.undo_null_move();
if (nullValue >= beta)
{
+ // Do not return unproven mate scores
+ if (nullValue >= value_mate_in(PLY_MAX))
+ nullValue = beta;
+
if (depth < 6 * OnePly)
- return beta;
+ return nullValue;
// Do zugzwang verification search
Value v = search(pos, ss, beta, depth-5*OnePly, ply, false, threadID);
if (v >= beta)
- return beta;
+ return nullValue;
} else {
// The null move failed low, which means that we may be faced with
// some kind of threat. If the previous move was reduced, check if
tte = TT.retrieve(posKey);
}
- // Step 10. Loop through moves
- // Loop through all legal moves until no moves remain or a beta cutoff occurs
-
// Initialize a MovePicker object for the current position
MovePicker mp = MovePicker(pos, ttMove, depth, H, &ss[ply], beta);
CheckInfo ci(pos);
+ // Step 10. Loop through moves
+ // Loop through all legal moves until no moves remain or a beta cutoff occurs
while ( bestValue < beta
&& (move = mp.get_next_move()) != MOVE_NONE
&& !TM.thread_should_stop(threadID))
if ( depth >= SingularExtensionDepthAtNonPVNodes
&& tte
&& move == tte->move()
- && !excludedMove // Do not allow recursive single-reply search
+ && !excludedMove // Do not allow recursive singular extension search
&& ext < OnePly
&& is_lower_bound(tte->type())
&& tte->depth() >= depth - 3 * OnePly)
// Step 13. Make the move
pos.do_move(move, st, ci, moveIsCheck);
- // Step 14. Reduced search
- // if the move fails high will be re-searched at full depth.
+ // Step 14. Reduced search, if the move fails high
+ // will be re-searched at full depth.
bool doFullDepthSearch = true;
if ( depth >= 3*OnePly
}
// Step 19. Check for mate and stalemate
- // All legal moves have been searched and if there were
+ // All legal moves have been searched and if there are
// no legal moves, it must be mate or stalemate.
- // If one move was excluded return fail low.
+ // If one move was excluded return fail low score.
if (!moveCount)
- return excludedMove ? beta - 1 : (pos.is_check() ? value_mated_in(ply) : VALUE_DRAW);
+ return excludedMove ? beta - 1 : (isCheck ? value_mated_in(ply) : VALUE_DRAW);
// Step 20. Update tables
// If the search is not aborted, update the transposition table,
enoughMaterial = pos.non_pawn_material(pos.side_to_move()) > RookValueMidgame;
futilityBase = staticValue + FutilityMarginQS + ei.futilityMargin[pos.side_to_move()];
- // Loop through the moves until no moves remain or a beta cutoff
- // occurs.
+ // Loop through the moves until no moves remain or a beta cutoff occurs
while ( alpha < beta
&& (move = mp.get_next_move()) != MOVE_NONE)
{
// All legal moves have been searched. A special case: If we're in check
// and no legal moves were found, it is checkmate.
- if (!moveCount && pos.is_check()) // Mate!
+ if (!moveCount && isCheck) // Mate!
return value_mated_in(ply);
// Update transposition table