Null Move recommendations
Null Move recommendations
Making good progress on my engine thanks to these discussions. Have implemented iterative deepening, PVS, killer moves, and ordering of root moves based on previous iteration node counts. I am now working on null move pruning before I look at LMR and futility pruning. My first cut at null move looks something like this with R = 2:
generate root moves (no null move here) and call alphaBeta(depth - 1, ...., true) // doNullMove = true
then in alphaBeta before generating moves:
if (doNullMove && !inCheck && depth > R) {
nullValue = alphaBeta(depth - R - 1,..., false) // using zero window around beta
if (nullValue >= beta) { return beta }
}
this has sped up the search considerably but as depth goes higher i'm curious what people do to in terms of changing R (adaptive NMR) or other techniques.
I have noticed that some people do not include the restriction depth > R when deciding when to do null move. They just reduce depth and then at the beginning of alphaBeta just add:
if (depth <= 0) { return quiescence() }
so we fall immediately into quiescence search. (fyi i do allow checks in the first two plies of qSearch so this is still a possibility for me)
So are people restricting null move to depth > R or not?
And in terms of making R a function of remaining depth, I know some people use much higher Rs when depth remaining is high. But what is high depth is different for each engine.
Assuming i strive to achieve a 12 ply search. What are people using for R at various depths. If it does change do you use a formula or just an array indexed by depth.
Depth R
12 root (no null move)
11 ?
10 ?
9 ?
8 ?
7 ?
6 ?
5 ?
4 ?
3 ?
2 ?
1 ?
also does anyone try to estimate wether null move is worth doing by restricting null move to lazyEval >= beta ? where lazyEval is material value + pieceSquare (which i update incrementally - so not expensive for me to get)
thanks in advance
generate root moves (no null move here) and call alphaBeta(depth - 1, ...., true) // doNullMove = true
then in alphaBeta before generating moves:
if (doNullMove && !inCheck && depth > R) {
nullValue = alphaBeta(depth - R - 1,..., false) // using zero window around beta
if (nullValue >= beta) { return beta }
}
this has sped up the search considerably but as depth goes higher i'm curious what people do to in terms of changing R (adaptive NMR) or other techniques.
I have noticed that some people do not include the restriction depth > R when deciding when to do null move. They just reduce depth and then at the beginning of alphaBeta just add:
if (depth <= 0) { return quiescence() }
so we fall immediately into quiescence search. (fyi i do allow checks in the first two plies of qSearch so this is still a possibility for me)
So are people restricting null move to depth > R or not?
And in terms of making R a function of remaining depth, I know some people use much higher Rs when depth remaining is high. But what is high depth is different for each engine.
Assuming i strive to achieve a 12 ply search. What are people using for R at various depths. If it does change do you use a formula or just an array indexed by depth.
Depth R
12 root (no null move)
11 ?
10 ?
9 ?
8 ?
7 ?
6 ?
5 ?
4 ?
3 ?
2 ?
1 ?
also does anyone try to estimate wether null move is worth doing by restricting null move to lazyEval >= beta ? where lazyEval is material value + pieceSquare (which i update incrementally - so not expensive for me to get)
thanks in advance
-
- Posts: 616
- Joined: Thu May 19, 2011 1:35 am
Re: Null Move recommendations
Here is the Stockfish Null move search step:
Code: Select all
// Step 8. Null move search with verification search (is omitted in PV nodes)
if ( !PvNode
&& eval >= beta
&& (ss->staticEval >= beta - 35 * (depth / ONE_PLY - 6) || depth >= 13 * ONE_PLY)
&& pos.non_pawn_material(pos.side_to_move()))
{
ss->currentMove = MOVE_NULL;
ss->counterMoves = nullptr;
assert(eval - beta >= 0);
// Null move dynamic reduction based on depth and value
Depth R = ((823 + 67 * depth) / 256 + std::min((eval - beta) / PawnValueMg, 3)) * ONE_PLY;
pos.do_null_move(st);
(ss+1)->skipEarlyPruning = true;
nullValue = depth-R < ONE_PLY ? -qsearch<NonPV, false>(pos, ss+1, -beta, -beta+1, DEPTH_ZERO)
: - search<NonPV>(pos, ss+1, -beta, -beta+1, depth-R, !cutNode);
(ss+1)->skipEarlyPruning = false;
pos.undo_null_move();
if (nullValue >= beta)
{
// Do not return unproven mate scores
if (nullValue >= VALUE_MATE_IN_MAX_PLY)
nullValue = beta;
if (depth < verification_depth * ONE_PLY && abs(beta) < VALUE_KNOWN_WIN)
return nullValue;
// Do verification search at high depths
ss->skipEarlyPruning = true;
Value v = depth-R < ONE_PLY ? qsearch<NonPV, false>(pos, ss, beta-1, beta, DEPTH_ZERO)
: search<NonPV>(pos, ss, beta-1, beta, depth-R, false);
ss->skipEarlyPruning = false;
if (v >= beta)
return nullValue;
}
}
-
- Posts: 190
- Joined: Sun Jul 14, 2013 10:00 am
- Real Name: H.G. Muller
Re: Null Move recommendations
Using R > 2 at any depth has never worked for me. But I can imagine it also depends on how much you reduce late moves (which I only reduce by 1).
I also do null move at d=2, and even at d=1, where there is nothing to reduce. I don't see aproblem with dropping directly into QS.
I also do null move at d=2, and even at d=1, where there is nothing to reduce. I don't see aproblem with dropping directly into QS.
-
- Posts: 7
- Joined: Mon Mar 07, 2016 5:01 pm
- Real Name: David Simalista
Re: Null Move recommendations
I just add the condition that the depth has to be at least 4 in order to try null move. You look at so few nodes at the lower depths that it's not worth doing null move in my opinion.
Re: Null Move recommendations
Thanks...after some extremely limited testing this seems to work for my engine:
bool PVNode = alpha != beta - 1;
I do a null move if (doNullMove && !PVNode && depth > 2 && lazyEval >= beta - 50)
then if depth > 6 i use R = 3 otherwise R = 2.
again lazyEval is just material + piece square values.
Originally i ignored the lazyEval condition completely which was faster than restricting it to lazyEval >= beta. But adding the 50 centipawn margin didn't really slow the search that much so anytime i can decrease the chance of a bad reduction i guess thats good. After a null move I don't allow any other null moves in its subtree. Speed is much better than i imagined.
Anything i'm missing?
bool PVNode = alpha != beta - 1;
I do a null move if (doNullMove && !PVNode && depth > 2 && lazyEval >= beta - 50)
then if depth > 6 i use R = 3 otherwise R = 2.
again lazyEval is just material + piece square values.
Originally i ignored the lazyEval condition completely which was faster than restricting it to lazyEval >= beta. But adding the 50 centipawn margin didn't really slow the search that much so anytime i can decrease the chance of a bad reduction i guess thats good. After a null move I don't allow any other null moves in its subtree. Speed is much better than i imagined.
Anything i'm missing?
Re: Null Move recommendations
You're right, it makes sense to do it that way.theturk1234 wrote:I just add the condition that the depth has to be at least 4 in order to try null move. You look at so few nodes at the lower depths that it's not worth doing null move in my opinion.