futile futility pruning attempt

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

Ferdy
Posts: 4833
Joined: Sun Aug 10, 2008 3:15 pm
Location: Philippines

Re: futile futility pruning attempt

Post by Ferdy »

Sven Schüle wrote:
Ferdy wrote:Try this if there is improvement.

Code: Select all

int search(...) {
    if (!isCheck && (depthLeft == 1) && (beta-alpha == 1) && alpha > MIN_EVAL_SCORE) {
        int score = eval();

        if &#40;score + eval_queen <= alpha&#41;
            return score;
   &#125;

   for&#40;Move x &#58; moves&#41; &#123;
       etc
   &#125;
&#125;
Would you call that "futility pruning", even though it prunes strong moves instead of futile moves (the opponent's previous move raised the static eval far above his beta)?
There are 3 cases of futility pruning that I know of.
1. Position futility pruning
2. Move futility pruning
3. Game futility pruning

The example above is of case 1.

Case 2 is something like,

Code: Select all

while &#40;m = getMove&#40;)) &#123;
    if futileMove&#40;m&#41;
        continue
&#125;
Case 3 is when your position at the root is very bad and you just resign the game. Not found in uci but winboard engines.

I view futility pruning from the player who is the side to move. He can ask the questions, is this position hopeless? Or am I in a hopeless position? Or is the move I am trying to make is hopeless? Or am I already lost?
Last edited by Ferdy on Thu Mar 09, 2017 1:23 am, edited 2 times in total.
Karlo Bala
Posts: 373
Joined: Wed Mar 22, 2006 10:17 am
Location: Novi Sad, Serbia
Full name: Karlo Balla

Re: futile futility pruning attempt

Post by Karlo Bala »

flok wrote:Hi,

Currently my fut. prun code looks like this:

Code: Select all

int search&#40;...) &#123;
    if (!isCheck && depthLeft == 1&#41; &#123;
        int score = eval&#40;);

        if &#40;score + eval_queen < alpha&#41;
            return score;
   &#125;

   for&#40;Move x &#58; moves&#41; &#123;
       etc
   &#125;
&#125;

2 questions:

* am I right to return score when pruning? or should it be alpha? it is a fail-soft application

* the wiki says that you should not do this pruning when either alpha or beta is near the mate score. what is near in this case?
I suggest that you first try the "Move Count Based Pruning". If it works, then you can make it more aggressive using a futile margin.

The code could be like this:

Code: Select all

for &#40;moves&#41;
&#123;
  if (!in_check && !pv && alpha > -WIN && !check && !capture && !push7rank && movenum > 4 + depth*depth&#41; // 4*depth or 1<<depth, whatever you like
     continue; // prune

  makemove&#40;)
  search&#40;...)
  unmakemove&#40;)
  ...

&#125;
Best Regards,
Karlo Balla Jr.
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: futile futility pruning attempt

Post by Sven »

Ferdy wrote:
Sven Schüle wrote:
Ferdy wrote:Try this if there is improvement.

Code: Select all

int search&#40;...) &#123;
    if (!isCheck && &#40;depthLeft == 1&#41; && &#40;beta-alpha == 1&#41; && alpha > MIN_EVAL_SCORE&#41; &#123;
        int score = eval&#40;);

        if &#40;score + eval_queen <= alpha&#41;
            return score;
   &#125;

   for&#40;Move x &#58; moves&#41; &#123;
       etc
   &#125;
&#125;
Would you call that "futility pruning", even though it prunes strong moves instead of futile moves (the opponent's previous move raised the static eval far above his beta)?
There are 3 cases of futility pruning that I know of.
1. Position futility pruning
2. Move futility pruning
3. Game futility pruning

The example above is of case 1.

Case 2 is something like,

Code: Select all

while &#40;m = getMove&#40;)) &#123;
    if futileMove&#40;m&#41;
        continue
&#125;
Case 3 is when your position at the root is very bad and you just resign the game. Not found in uci but winboard engines.

I view futility pruning from the player who is the side to move. He can ask the questions, is this position hopeless? Or am I in a hopeless position? Or is the move I am trying to make is hopeless? Or am I already lost?
Case 3 should be irrelevant in this thread. Case 1 is interesting but as far as I know we almost always think of case 2 if we talk about "futility pruning" in chess engine programming. I also think that case 1 is a very risky kind of pruning, and I guess it is not what the OP intended to do.
Ferdy
Posts: 4833
Joined: Sun Aug 10, 2008 3:15 pm
Location: Philippines

Re: futile futility pruning attempt

Post by Ferdy »

Sven Schüle wrote:
Ferdy wrote:
Sven Schüle wrote:
Ferdy wrote:Try this if there is improvement.

Code: Select all

int search&#40;...) &#123;
    if (!isCheck && &#40;depthLeft == 1&#41; && &#40;beta-alpha == 1&#41; && alpha > MIN_EVAL_SCORE&#41; &#123;
        int score = eval&#40;);

        if &#40;score + eval_queen <= alpha&#41;
            return score;
   &#125;

   for&#40;Move x &#58; moves&#41; &#123;
       etc
   &#125;
&#125;
Would you call that "futility pruning", even though it prunes strong moves instead of futile moves (the opponent's previous move raised the static eval far above his beta)?
There are 3 cases of futility pruning that I know of.
1. Position futility pruning
2. Move futility pruning
3. Game futility pruning

The example above is of case 1.

Case 2 is something like,

Code: Select all

while &#40;m = getMove&#40;)) &#123;
    if futileMove&#40;m&#41;
        continue
&#125;
Case 3 is when your position at the root is very bad and you just resign the game. Not found in uci but winboard engines.

I view futility pruning from the player who is the side to move. He can ask the questions, is this position hopeless? Or am I in a hopeless position? Or is the move I am trying to make is hopeless? Or am I already lost?
Case 3 should be irrelevant in this thread.
It is not irrelevant, it is there to better understand the concept of futility.
Sven Schüle wrote: Case 1 is interesting but as far as I know we almost always think of case 2 if we talk about "futility pruning" in chess engine programming. I also think that case 1 is a very risky kind of pruning, and I guess it is not what the OP intended to do.
The advantage of case 1 is that you can have the full evaluation of the position which can be useful in other areas too, unlike case 2 where it could be expensive to call the full eval after every move to determine if move is futile or not although there are other means to achieve effective pruning. The risks in case 1 can be minimized by adding other conditions and better tuned margins.
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: futile futility pruning attempt

Post by Sven »

Ferdy wrote:
Sven Schüle wrote: Case 1 is interesting but as far as I know we almost always think of case 2 if we talk about "futility pruning" in chess engine programming. I also think that case 1 is a very risky kind of pruning, and I guess it is not what the OP intended to do.
The advantage of case 1 is that you can have the full evaluation of the position which can be useful in other areas too, unlike case 2 where it could be expensive to call the full eval after every move to determine if move is futile or not although there are other means to achieve effective pruning. The risks in case 1 can be minimized by adding other conditions and better tuned margins.
Have you ever seen "case 1" (you call it "position futility pruning") being used in any serious engine so far? Even SF does not use it as far as I know (and SF uses almost all search techniques that are considered valid today).

"Case 2" can be implemented in two ways (as I pointed out several times in this thread): either at the parent node (within the move loop) or at the child node (at the top of search()). When applying it at the parent node you do not need to call eval() after each move, instead you can use the saved score from the current node (saved above the move loop for that purpose) and calculate the expected gain for the current move that might become pruned.

Comparing advantages of "case 1" and "case 2" in terms of things like less calls of eval() is a moot point in my opinion since both kinds of pruning differ a lot from each other. Note that "case 1" pruning does not even take into account whether the moving side which appears to be "lost" (e.g. a queen below alpha) can simply recapture the queen, or can give check (which could be checkmate or a forced mate in 2 or win the queen or ...). It turns the current node into a leaf without considering available moves. I don't know how this risk could be reduced effectively. Margin = 2*queen_value ?
tttony
Posts: 268
Joined: Sun Apr 24, 2011 12:33 am

Re: futile futility pruning attempt

Post by tttony »

flok wrote:Hi,

Currently my fut. prun code looks like this:

Code: Select all

int search&#40;...) &#123;
    if (!isCheck && depthLeft == 1&#41; &#123;
        int score = eval&#40;);

        if &#40;score + eval_queen < alpha&#41;
            return score;
   &#125;

   for&#40;Move x &#58; moves&#41; &#123;
       etc
   &#125;
&#125;

2 questions:

* am I right to return score when pruning? or should it be alpha? it is a fail-soft application

* the wiki says that you should not do this pruning when either alpha or beta is near the mate score. what is near in this case?
I tested this simillar, it's reversed or called in SF static null move pruning http://www.talkchess.com/forum/viewtopi ... at&start=0 in my old engine and it worked fine but I returned the margin(eval - piece_value) score instead of beta
Ferdy
Posts: 4833
Joined: Sun Aug 10, 2008 3:15 pm
Location: Philippines

Re: futile futility pruning attempt

Post by Ferdy »

Sven Schüle wrote:
Ferdy wrote:
Sven Schüle wrote: Case 1 is interesting but as far as I know we almost always think of case 2 if we talk about "futility pruning" in chess engine programming. I also think that case 1 is a very risky kind of pruning, and I guess it is not what the OP intended to do.
The advantage of case 1 is that you can have the full evaluation of the position which can be useful in other areas too, unlike case 2 where it could be expensive to call the full eval after every move to determine if move is futile or not although there are other means to achieve effective pruning. The risks in case 1 can be minimized by adding other conditions and better tuned margins.
Have you ever seen "case 1" (you call it "position futility pruning") being used in any serious engine so far? Even SF does not use it as far as I know (and SF uses almost all search techniques that are considered valid today).
It does not matter if the engine using it is serious or not the point is the method of pruning exists. You seemed to imply that techniques not in Stockfish is invalid :). What happened to you?

Fortunately Stockfish seemed to have it and they call it razoring with some refinements that is using qsearch value.

Code: Select all

// Step 6. Razoring &#40;skipped when in check&#41;
    if (   !PvNode
        &&  depth < 4 * ONE_PLY
        &&  eval + razor_margin&#91;depth&#93; <= alpha
        &&  ttMove == MOVE_NONE&#41;
    &#123;
        if (   depth <= ONE_PLY
            && eval + razor_margin&#91;3 * ONE_PLY&#93; <= alpha&#41;
            return qsearch<NonPV, false>&#40;pos, ss, alpha, beta, DEPTH_ZERO&#41;;

        Value ralpha = alpha - razor_margin&#91;depth&#93;;
        Value v = qsearch<NonPV, false>&#40;pos, ss, ralpha, ralpha+1, DEPTH_ZERO&#41;;
        if &#40;v <= ralpha&#41;
            return v;
    &#125;
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: futile futility pruning attempt

Post by Sven »

Ferdy wrote:
Sven Schüle wrote:
Ferdy wrote:
Sven Schüle wrote: Case 1 is interesting but as far as I know we almost always think of case 2 if we talk about "futility pruning" in chess engine programming. I also think that case 1 is a very risky kind of pruning, and I guess it is not what the OP intended to do.
The advantage of case 1 is that you can have the full evaluation of the position which can be useful in other areas too, unlike case 2 where it could be expensive to call the full eval after every move to determine if move is futile or not although there are other means to achieve effective pruning. The risks in case 1 can be minimized by adding other conditions and better tuned margins.
Have you ever seen "case 1" (you call it "position futility pruning") being used in any serious engine so far? Even SF does not use it as far as I know (and SF uses almost all search techniques that are considered valid today).
It does not matter if the engine using it is serious or not the point is the method of pruning exists. You seemed to imply that techniques not in Stockfish is invalid :). What happened to you?

Fortunately Stockfish seemed to have it and they call it razoring with some refinements that is using qsearch value.
Nothing happened to me. Of course I did not want to imply that techniques that are not in Stockfish are invalid. But despite your opinion as well as that of Tony (see his recent reply in this thread), I strongly disagree that the pruning method described in this thread has any serious value. I'm pretty sure it neither was nor is present in Stockfish, Komodo, or any other strong engine, and it is not "reverse futility pruning", "static null move pruning" or anything similar. Both look very different, they do not prune with a condition like "eval + margin <= alpha" at the top of a node (but with "eval - margin >= beta" which is quite the opposite).

It is also not "razoring", even though it may look "close" to it. The big difference to "razoring" is that the latter is not applied at PV nodes or nodes which have a TT move (both conditions are not present in the OP code snippet) and - most important - that "razoring" only prunes if qsearch() confirms the fail-low somehow. I would not call the addition of the two missing conditions and the qsearch() confirmation step a "refinement", it turns the whole thing into something completely different in my view. Not using a confirmation like qsearch() to avoid missing an own "strong" move that would avoid to fail low is obviously hilarious, so why should someone consider it serious?

But we don't need to continue this battle, maybe in fact we are not too far away from each other ;-) It seems obvious to me that the OP wanted to implement futility pruning but failed to do it right. Now there are various ways for him to improve his code, and in the end he might get both futility pruning *and* razoring to work :-)