Restarting iterative deepening

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Restarting iterative deepening

Post by bob »

hgm wrote:How about this algorithm?

Code: Select all

int Search(int realAlpha, int realBeta, int aspirationWidth)
{
  int alpha = realAlpha, beta = realBeta;
  ProbeHash();
  if(beta - alpha > 1) { // PV node
    alpha = hash.score - aspirationWidth;
    if&#40;alpha < realAlpha&#41; alpha = realAlpha;
  &#125;
  do &#123;
    int startAlpha = alpha;
    for&#40;ALL_MOVES&#41; &#123;
      MakeMove&#40;);
      score = -Search&#40;-beta, -alpha, aspirationWidth*0.95&#41;;
      UnMake&#40;);
      if&#40;score > alpha&#41; &#123;
        alpha = score;
        ...
      &#125;
    &#125;
    retry = &#40;alpha <= startAlpha && alpha < realAlpha&#41;;
    alpha = realAlpha;
  &#125; while&#40;retry&#41;;
  return alpha;
&#125;

// Root call&#58;
Search&#40;-MATE, +MATE, 100*centiPawn&#41;;
This would try to solve a fail low that just fails a little bit low in the current node, but on a drastic score drop would prefer to hand the fail low down to the parent.
Will keep it on my list. I have a version with no fail lows at the root now (window=(-inf, +inf)). Testing and tweaking as this affected several places in the code.

First thing I noticed is a massive reduction in those fail high followed by a fail low (at the root) circumstances that were always annoying... But I have to first confirm I haven't broken anything, then test thoroughly...
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Restarting iterative deepening

Post by bob »

bob wrote:
hgm wrote:How about this algorithm?

Code: Select all

int Search&#40;int realAlpha, int realBeta, int aspirationWidth&#41;
&#123;
  int alpha = realAlpha, beta = realBeta;
  ProbeHash&#40;);
  if&#40;beta - alpha > 1&#41; &#123; // PV node
    alpha = hash.score - aspirationWidth;
    if&#40;alpha < realAlpha&#41; alpha = realAlpha;
  &#125;
  do &#123;
    int startAlpha = alpha;
    for&#40;ALL_MOVES&#41; &#123;
      MakeMove&#40;);
      score = -Search&#40;-beta, -alpha, aspirationWidth*0.95&#41;;
      UnMake&#40;);
      if&#40;score > alpha&#41; &#123;
        alpha = score;
        ...
      &#125;
    &#125;
    retry = &#40;alpha <= startAlpha && alpha < realAlpha&#41;;
    alpha = realAlpha;
  &#125; while&#40;retry&#41;;
  return alpha;
&#125;

// Root call&#58;
Search&#40;-MATE, +MATE, 100*centiPawn&#41;;
This would try to solve a fail low that just fails a little bit low in the current node, but on a drastic score drop would prefer to hand the fail low down to the parent.
Will keep it on my list. I have a version with no fail lows at the root now (window=(-inf, +inf)). Testing and tweaking as this affected several places in the code.

First thing I noticed is a massive reduction in those fail high followed by a fail low (at the root) circumstances that were always annoying... But I have to first confirm I haven't broken anything, then test thoroughly...
Next thing I noticed was about a -25 Elo change. Apparently the way I do aspiration windows (and code related to that) works pretty well. Code was a bit simpler without it, but also about -25 Elo worse, so obviously it is back in again...

Another wasted day...
User avatar
cdani
Posts: 2204
Joined: Sat Jan 18, 2014 10:24 am
Location: Andorra

Re: Restarting iterative deepening

Post by cdani »

bob wrote: Another wasted day...
I do not consider such essays as wasted, and I suppose you too, even if, like when one lose a game, might think that has wasted the time :-)
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Restarting iterative deepening

Post by bob »

cdani wrote:
bob wrote: Another wasted day...
I do not consider such essays as wasted, and I suppose you too, even if, like when one lose a game, might think that has wasted the time :-)
aspiration windows have always worked for me. always. Why I took the time to confirm they still do I will never know. :)
User avatar
hgm
Posts: 27812
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Restarting iterative deepening

Post by hgm »

But you are using them in an unusual way. Normally the idea behind aspiration is that you don't want the search to bother figuring out exactly how much the score of the PV move dropped when it drops more than the aspiration-window width. Because you are confident (without evidence, based on statistics only) that one of the other root moves will score inside that window too, so that an upper bound on the score of the old PV move below the aspiration window is already good enough. This is why you do the aspiration in the root, so that you will return there if the PV score dropped, so you can switch moves.

If you don't want to switch moves anyway, you might as well have applied the aspiration in node at a higher ply level.

If you find that it is better to not switch moves in the root (ply=1), then why would you expect it is better to switch moves on a PV that fails low in the PV node at ply=2 or ply=3?
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Restarting iterative deepening

Post by bob »

hgm wrote:But you are using them in an unusual way. Normally the idea behind aspiration is that you don't want the search to bother figuring out exactly how much the score of the PV move dropped when it drops more than the aspiration-window width. Because you are confident (without evidence, based on statistics only) that one of the other root moves will score inside that window too, so that an upper bound on the score of the old PV move below the aspiration window is already good enough. This is why you do the aspiration in the root, so that you will return there if the PV score dropped, so you can switch moves.

If you don't want to switch moves anyway, you might as well have applied the aspiration in node at a higher ply level.

If you find that it is better to not switch moves in the root (ply=1), then why would you expect it is better to switch moves on a PV that fails low in the PV node at ply=2 or ply=3?
What I am doing. When I fail low on the aspiration window I immediately lower the alpha bound and re-search this first root move again.

What I tried. I simply set the window to -inf,+inf for each iteration so there was never a fail low at all.

The only special thing I was doing was this: If I am pondering, and I ponder longer than the set target time because my opponent thinks a while, when he makes a move I could bail out instantly since I have already exceeded the target (but on his clock). What I currently do is notice that the first move has failed low, even though I don't have an actual score back yet, and I do NOT terminate the search, as I want to try to avoid the score drop. I can't imagine that is worth 25 Elo. But what I did notice is that iterations took longer with -/+inf bounds, which is not a surprise, but what was surprising was how much longer they tended to take, and apparently that was worth 25 Elo or so...
jwes
Posts: 778
Joined: Sat Jul 01, 2006 7:11 am

Re: Restarting iterative deepening

Post by jwes »

bob wrote:
hgm wrote:But you are using them in an unusual way. Normally the idea behind aspiration is that you don't want the search to bother figuring out exactly how much the score of the PV move dropped when it drops more than the aspiration-window width. Because you are confident (without evidence, based on statistics only) that one of the other root moves will score inside that window too, so that an upper bound on the score of the old PV move below the aspiration window is already good enough. This is why you do the aspiration in the root, so that you will return there if the PV score dropped, so you can switch moves.

If you don't want to switch moves anyway, you might as well have applied the aspiration in node at a higher ply level.

If you find that it is better to not switch moves in the root (ply=1), then why would you expect it is better to switch moves on a PV that fails low in the PV node at ply=2 or ply=3?
What I am doing. When I fail low on the aspiration window I immediately lower the alpha bound and re-search this first root move again.

What I tried. I simply set the window to -inf,+inf for each iteration so there was never a fail low at all.

The only special thing I was doing was this: If I am pondering, and I ponder longer than the set target time because my opponent thinks a while, when he makes a move I could bail out instantly since I have already exceeded the target (but on his clock). What I currently do is notice that the first move has failed low, even though I don't have an actual score back yet, and I do NOT terminate the search, as I want to try to avoid the score drop. I can't imagine that is worth 25 Elo. But what I did notice is that iterations took longer with -/+inf bounds, which is not a surprise, but what was surprising was how much longer they tended to take, and apparently that was worth 25 Elo or so...
I tried some experiments a while ago and found that it was good to re-search the same move on the first fail low, but if it fails low again, try the other moves first. Another way of looking at it is, if a move is likely to lose, I would rather try other moves first, because if the first move is the best move, the waste of time hardly matters.

I am also surprised that aspiration windows are worth 25 ELO, as that about 1/3 more nodes. I might double-check by running some positions to fixed depth and see that I get the same result while using a bunch more nodes.
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Restarting iterative deepening

Post by bob »

jwes wrote:
bob wrote:
hgm wrote:But you are using them in an unusual way. Normally the idea behind aspiration is that you don't want the search to bother figuring out exactly how much the score of the PV move dropped when it drops more than the aspiration-window width. Because you are confident (without evidence, based on statistics only) that one of the other root moves will score inside that window too, so that an upper bound on the score of the old PV move below the aspiration window is already good enough. This is why you do the aspiration in the root, so that you will return there if the PV score dropped, so you can switch moves.

If you don't want to switch moves anyway, you might as well have applied the aspiration in node at a higher ply level.

If you find that it is better to not switch moves in the root (ply=1), then why would you expect it is better to switch moves on a PV that fails low in the PV node at ply=2 or ply=3?
What I am doing. When I fail low on the aspiration window I immediately lower the alpha bound and re-search this first root move again.

What I tried. I simply set the window to -inf,+inf for each iteration so there was never a fail low at all.

The only special thing I was doing was this: If I am pondering, and I ponder longer than the set target time because my opponent thinks a while, when he makes a move I could bail out instantly since I have already exceeded the target (but on his clock). What I currently do is notice that the first move has failed low, even though I don't have an actual score back yet, and I do NOT terminate the search, as I want to try to avoid the score drop. I can't imagine that is worth 25 Elo. But what I did notice is that iterations took longer with -/+inf bounds, which is not a surprise, but what was surprising was how much longer they tended to take, and apparently that was worth 25 Elo or so...
I tried some experiments a while ago and found that it was good to re-search the same move on the first fail low, but if it fails low again, try the other moves first. Another way of looking at it is, if a move is likely to lose, I would rather try other moves first, because if the first move is the best move, the waste of time hardly matters.

I am also surprised that aspiration windows are worth 25 ELO, as that about 1/3 more nodes. I might double-check by running some positions to fixed depth and see that I get the same result while using a bunch more nodes.
There are several possible sources of this "25 elo". My time management which reacts to fail lows significantly, but without aspiration there are zero fail-lows, which negates part of that fairly well-tuned code (crafty's "pseudo-easy-move/hard-move" approach)...
User avatar
hgm
Posts: 27812
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Restarting iterative deepening

Post by hgm »

bob wrote:There are several possible sources of this "25 elo". My time management which reacts to fail lows significantly, but without aspiration there are zero fail-lows, which negates part of that fairly well-tuned code (crafty's "pseudo-easy-move/hard-move" approach)...
This is why playing games is really the wrong approach to measure this. This is just a tree-size issue, and measuring time-to-depth on some 10,000 positions should give you a much more reliable result, in a fraction of the time (10,000 positions ~ 100 games...).
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Restarting iterative deepening

Post by bob »

hgm wrote:
bob wrote:There are several possible sources of this "25 elo". My time management which reacts to fail lows significantly, but without aspiration there are zero fail-lows, which negates part of that fairly well-tuned code (crafty's "pseudo-easy-move/hard-move" approach)...
This is why playing games is really the wrong approach to measure this. This is just a tree-size issue, and measuring time-to-depth on some 10,000 positions should give you a much more reliable result, in a fraction of the time (10,000 positions ~ 100 games...).
I am not sure that is so reliable. A 50 move game is far different from 50 independent positions. Hash table. move ordering. time accumulation across positions... All play into how this works, in my case... Not to mention how things are connected with respect to evaluation (move to move sees relatively consistent scores, etc).