First post (and FailHigh question!)

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

xmas79
Posts: 286
Joined: Mon Jun 03, 2013 7:05 pm
Location: Italy

Re: First post (and FailHigh question!)

Post by xmas79 »

Sven Schüle wrote:
Chan Rasjid wrote:Almost all decent chess programs use fail-soft; ie search() always returns the exact score:
1) on fail low, do not return alpha, but the score (<= alpha).
2) on fail high, return score (>= beta), not beta.
I agree that using fail-soft may give a hint in this case. I'm not so sure whether so many programs actually use fail-soft. But I disagree on your description of fail-soft: it does not "always return the exact score", at least this can be misunderstood. On failing low or high it returns bounds the same way as fail-hard does, the only difference is that these bounds can be < alpha or > beta.

You can rewrite fail-hard and fail-soft alphabeta to fully equivalent code such that there is only one line of difference between both, and that is the initialization of the best score (initialized to alpha vs. -INF) prior to the move loop. This is done by always passing [-beta, -Max(alpha, bestScore)] to the next level, and by always returning bestScore.

Sven
Hi all,
I think I have a fail-soft framework already:

Code: Select all

search&#40;alpha,beta&#41;
  gen_moves&#40;);
  for each move
    make
    if &#40;first_move&#41;
      score = -search&#40;-beta, -alpha&#41;;
    else
    &#123;
        score = -search&#40;-alpha - 1, -alpha&#41;;
        if &#40;score > alpha && score < beta&#41; // research only if non pv nodes
          score = -search&#40;-beta, -alpha&#41;;
    &#125;
    unmake
    if &#40;score >= beta&#41;
        return score;
    if &#40;score > alpha&#41;
        alpha = score;
  end for

  // mate or stalemale?
  if &#40;moves_tried == 0&#41;
  &#123;
     if &#40;in check&#41; return LOST+ply; else return DRAW;
  &#125;

  return alpha;
end search
I'm still debugging this problem, but as far as I can see, I can tell the research code works as expected, as tracing to the mate position at ply 14 it backup to ply 13 a -mate_score_in_x, so ply 13 fails-high with score +mate_score_in_x to ply 12, but then ply 12 tries next move and improves alpha from -mate to -6.00, so score backed-up to ply 11 is not -matescore_in_x but is -6.00, which will be flip-flopped by negasearch until root is reached with positive sign, hence the score of +6.00. Still investigating why it fails-high at ply 14. A lot of nodes to look through... Maybe the problem is here and not in the research. Problem is that research is fair easy to trace because I already know the search will follow PV... the search before, instead, have a complete different move ordering....... I'm trying also to investigate this problem on other positions where depths are less than 14...
xmas79
Posts: 286
Joined: Mon Jun 03, 2013 7:05 pm
Location: Italy

Re: First post (and FailHigh question!)

Post by xmas79 »

Generally speaking, more cut-offs "for free" means less nodes to search, AKA less time spent on unuseful part of the tree space. So I think search quality is better.
User avatar
Desperado
Posts: 879
Joined: Mon Dec 15, 2008 11:45 am

Re: First post (and FailHigh question!)

Post by Desperado »

Hi Natale,

well, at least what you posted is not a "complete" fail-soft implementation.
You return score instead of beta bound when getting a cut, which is like it
should be in FS. But on the other hand, you return the hard alpha bound if you have a fail-lo at a node.
It should look like this...

Code: Select all

int search&#40;PARAMS&#41;
&#123;
    int bestScore = NO_VALUE;
    ...
    while&#40; moves )
   &#123;
        if&#40; firstMove )
       &#123;
         value = -search&#40;-beta,-alpha,...);
       &#125;
       else
      &#123;
         value = -search&#40;-alpha-1,-alpha,...);
         ...
      &#125;

      if&#40; value > bestScore ) bestScore = value;
      if&#40; value > alpha        ) alpha = value;
      if&#40; value >= beta       ) return value; // &#40;or simply bestScore ) may be a score above beta
   &#125;
    ...

   // This way you will also return values below alpha

   return bestScore; // may be a value below alpha
&#125;
Michael
tpetzke
Posts: 686
Joined: Thu Mar 03, 2011 4:57 pm
Location: Germany

Re: First post (and FailHigh question!)

Post by tpetzke »

I agree, in case it is really free and really helps.

From the Wiki
Fail-Soft has the reputation for searching less nodes than Fail-Hard, but might also require some care regarding to search instability issues in conjunction with transposition tables and various pruning-, reduction- and extension techniques.
The general recommendation I think for a beginner was to at least start with fail hard, as it is easier to catch bugs. I still use it.

Thomas...
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: First post (and FailHigh question!)

Post by Sven »

hgm wrote:
Sven Schüle wrote:I'm not so sure whether so many programs actually use fail-soft.
Because in combination with hashing it is an improvement without any trade-offs. You will see hash hits causing a cutoff that otherwise would not have been possible because the score bound was too high (or low), just because when storing it you carelessly rounded the bound to alpha or beta. And there is no downside.
I did not ask "why" ... No need to convince me of fail-soft since I am using it as well for a very long time (I think I never used fail-hard in any serious engine). I was just curious how many other engines actually use it.

Sven
Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: First post (and FailHigh question!)

Post by Henk »

xmas79 wrote:
Sven Schüle wrote:
Chan Rasjid wrote:Almost all decent chess programs use fail-soft; ie search() always returns the exact score:
1) on fail low, do not return alpha, but the score (<= alpha).
2) on fail high, return score (>= beta), not beta.
I agree that using fail-soft may give a hint in this case. I'm not so sure whether so many programs actually use fail-soft. But I disagree on your description of fail-soft: it does not "always return the exact score", at least this can be misunderstood. On failing low or high it returns bounds the same way as fail-hard does, the only difference is that these bounds can be < alpha or > beta.

You can rewrite fail-hard and fail-soft alphabeta to fully equivalent code such that there is only one line of difference between both, and that is the initialization of the best score (initialized to alpha vs. -INF) prior to the move loop. This is done by always passing [-beta, -Max(alpha, bestScore)] to the next level, and by always returning bestScore.

Sven
Hi all,
I think I have a fail-soft framework already:

Code: Select all

search&#40;alpha,beta&#41;
  gen_moves&#40;);
  for each move
    make
    if &#40;first_move&#41;
      score = -search&#40;-beta, -alpha&#41;;
    else
    &#123;
        score = -search&#40;-alpha - 1, -alpha&#41;;
        if &#40;score > alpha && score < beta&#41; // research only if non pv nodes
          score = -search&#40;-beta, -alpha&#41;;
    &#125;
    unmake
    if &#40;score >= beta&#41;
        return score;
    if &#40;score > alpha&#41;
        alpha = score;
  end for

  // mate or stalemale?
  if &#40;moves_tried == 0&#41;
  &#123;
     if &#40;in check&#41; return LOST+ply; else return DRAW;
  &#125;

  return alpha;
end search
I'm still debugging this problem, but as far as I can see, I can tell the research code works as expected, as tracing to the mate position at ply 14 it backup to ply 13 a -mate_score_in_x, so ply 13 fails-high with score +mate_score_in_x to ply 12, but then ply 12 tries next move and improves alpha from -mate to -6.00, so score backed-up to ply 11 is not -matescore_in_x but is -6.00, which will be flip-flopped by negasearch until root is reached with positive sign, hence the score of +6.00. Still investigating why it fails-high at ply 14. A lot of nodes to look through... Maybe the problem is here and not in the research. Problem is that research is fair easy to trace because I already know the search will follow PV... the search before, instead, have a complete different move ordering....... I'm trying also to investigate this problem on other positions where depths are less than 14...
I even do not understand why

score = -search(-beta, -score);

makes the search gets worse when you do not have any extensions
or pruning except for quiescence search.
Chan Rasjid
Posts: 588
Joined: Thu Mar 09, 2006 4:47 pm
Location: Singapore

Re: First post (and FailHigh question!)

Post by Chan Rasjid »

tpetzke wrote:I agree, in case it is really free and really helps.

From the Wiki
Fail-Soft has the reputation for searching less nodes than Fail-Hard, but might also require some care regarding to search instability issues in conjunction with transposition tables and various pruning-, reduction- and extension techniques.
The general recommendation I think for a beginner was to at least start with fail hard, as it is easier to catch bugs. I still use it.

Thomas...
Fail soft is really free. The fail high and soft score x > beta is as theoretically sound as an lower bound as beta itself. It just mean that x, as well as beta, is a lower bound to the exact score of optimal play. The only reason Bob gave why Crafty uses fail hard is that it was easier for him to debug his (must be very buggy !!!) SMP search.

I think using fail soft should not pose much a a problem once we are aware when we need to be careful. There are only few cases where we may need to be careful:
1) when search() returns with a concocted "artificial" score that is outside of [alpha, beta] that is not from recursive search() itself, not from eval() and also not from the TT. I don't recall now any situation it may happen. There may come a time when we have a great idea about aborting search with failing low or high when it would be better just to fail with the bounds alpha or beta.
2) nullmove; I think it is safer to fail high on a nullmove success with beta rather than any search() score > beta. Nullmove is an unusual search where we trust beta as the only acceptable lower bound.

Best Regards,
Rasjid.
Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: First post (and FailHigh question!)

Post by Henk »

So what to do when search() returns with a concocted "artificial" score that is outside of [alpha, beta] that is not from recursive search() itself, not from eval() and also not from the TT ?
Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: First post (and FailHigh question!)

Post by Henk »

Henk wrote:
xmas79 wrote:
Sven Schüle wrote:
Chan Rasjid wrote:Almost all decent chess programs use fail-soft; ie search() always returns the exact score:
1) on fail low, do not return alpha, but the score (<= alpha).
2) on fail high, return score (>= beta), not beta.
I agree that using fail-soft may give a hint in this case. I'm not so sure whether so many programs actually use fail-soft. But I disagree on your description of fail-soft: it does not "always return the exact score", at least this can be misunderstood. On failing low or high it returns bounds the same way as fail-hard does, the only difference is that these bounds can be < alpha or > beta.

You can rewrite fail-hard and fail-soft alphabeta to fully equivalent code such that there is only one line of difference between both, and that is the initialization of the best score (initialized to alpha vs. -INF) prior to the move loop. This is done by always passing [-beta, -Max(alpha, bestScore)] to the next level, and by always returning bestScore.

Sven
Hi all,
I think I have a fail-soft framework already:

Code: Select all

search&#40;alpha,beta&#41;
  gen_moves&#40;);
  for each move
    make
    if &#40;first_move&#41;
      score = -search&#40;-beta, -alpha&#41;;
    else
    &#123;
        score = -search&#40;-alpha - 1, -alpha&#41;;
        if &#40;score > alpha && score < beta&#41; // research only if non pv nodes
          score = -search&#40;-beta, -alpha&#41;;
    &#125;
    unmake
    if &#40;score >= beta&#41;
        return score;
    if &#40;score > alpha&#41;
        alpha = score;
  end for

  // mate or stalemale?
  if &#40;moves_tried == 0&#41;
  &#123;
     if &#40;in check&#41; return LOST+ply; else return DRAW;
  &#125;

  return alpha;
end search
I'm still debugging this problem, but as far as I can see, I can tell the research code works as expected, as tracing to the mate position at ply 14 it backup to ply 13 a -mate_score_in_x, so ply 13 fails-high with score +mate_score_in_x to ply 12, but then ply 12 tries next move and improves alpha from -mate to -6.00, so score backed-up to ply 11 is not -matescore_in_x but is -6.00, which will be flip-flopped by negasearch until root is reached with positive sign, hence the score of +6.00. Still investigating why it fails-high at ply 14. A lot of nodes to look through... Maybe the problem is here and not in the research. Problem is that research is fair easy to trace because I already know the search will follow PV... the search before, instead, have a complete different move ordering....... I'm trying also to investigate this problem on other positions where depths are less than 14...
I even do not understand why

score = -search(-beta, -score);

makes the search gets worse when you do not have any extensions
or pruning except for quiescence search.
Correction:

I do not know if score = -search(-beta, -score);

makes the search gets worse when you do not have any extensions
or pruning except for quiescence search.


But this is a theoretical question. Every clone uses null move pruning.
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: First post (and FailHigh question!)

Post by Sven »

xmas79 wrote:I think I have a fail-soft framework already:

Code: Select all

search&#40;alpha,beta&#41;
  gen_moves&#40;);
  for each move
    make
    if &#40;first_move&#41;
      score = -search&#40;-beta, -alpha&#41;;
    else
    &#123;
        score = -search&#40;-alpha - 1, -alpha&#41;;
        if &#40;score > alpha && score < beta&#41; // research only if non pv nodes
          score = -search&#40;-beta, -alpha&#41;;
    &#125;
    unmake
    if &#40;score >= beta&#41;
        return score;
    if &#40;score > alpha&#41;
        alpha = score;
  end for

  // mate or stalemale?
  if &#40;moves_tried == 0&#41;
  &#123;
     if &#40;in check&#41; return LOST+ply; else return DRAW;
  &#125;

  return alpha;
end search
This is almost pure fail-hard :-) The only deviation was already mentioned by Michael: you return "score" instead of "beta" in case of a beta cutoff (and additionally you possibly return a mate or draw score even if it is outside the alpha-beta window). But this won't make any difference in my opinion since the parent will simply not improve his "alpha" anyway, so the return value goes fully unnoticed. Even if you use the same algorithm at root I think it should not matter. But you can try whether I am right or wrong by replacing the "return score" by "return beta", of course :-)

Sven