fail hard

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

User avatar
lucasart
Posts: 3232
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

fail hard

Post by lucasart »

Are there any strong programs using fail hard?

I remember Bob Hyatt saying that fail soft was pointless, and that he uses fail hard in Crafty.

When I tried fail hard in DiscoCheck, it was a ~20 elo loss. However the implementation was somewhat nicer, and allowed me to remove a few fail soft related hacks. I'm still experimenting, trying to retain some of the simplicity benefit of fail soft, without the elo loss. I'm trying some half-assed approaches.

What's the consensus here? (if there is any).
Michel
Posts: 2272
Joined: Mon Sep 29, 2008 1:50 am

Re: fail hard

Post by Michel »

I think fail soft is better since you can get more hash cutoffs that way (when revisiting the position with different alpha,beta). The drawback is that you have to make sure that the bounds you return are correct in case of forward pruning so as to not violate the alpha,beta contract. Of course there is no guarantee that the bounds returned by fail hard are correct either but they are the safest choice.

But I think it really all depends on tuning. If your engine was tuned using fail soft it is not a surprise you experience a large elo drop when suddenly switching to fail hard.
Henk
Posts: 7220
Joined: Mon May 27, 2013 10:31 am

Re: fail hard

Post by Henk »

When you fail low and futile moves are pruned away there are cases that you have to return alpha anyway. My program uses fail soft. Fail hard appeared to be no improvement. Could be fail hard gives less fluctuations in evaluation scores I don't know.
Stan Arts
Posts: 179
Joined: Fri Feb 14, 2014 10:53 pm
Location: the Netherlands

Re: fail hard

Post by Stan Arts »

The main advantage, probably, of fail hard is that it's easier to implement.
For example you don't need a separate eval variable set to -inf at every new node but simply an alpha variable that's allowed to rise and initially set to the value of that of 2 ply before.
But that means ofcourse that you don't get a move at all if the score remains equal or below alpha.
With fail soft at the end of a child node you probably do something like

if best_score[depth] > best_score[depth-1] then best_score[depth-1] = best_score[depth]

In addition to

if best_score[depth] > alpha[depth-1] then alpha[depth-1] = best_score[depth]

And with fail hard you probably only need the second line.

But with fail soft it happens pretty often that you get scores outside of bounds. They can be scores from hash, indications from eval, matescores and who knows. And that just sounds like extra information to me though probably rather useless.
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: fail hard

Post by bob »

lucasart wrote:Are there any strong programs using fail hard?

I remember Bob Hyatt saying that fail soft was pointless, and that he uses fail hard in Crafty.

When I tried fail hard in DiscoCheck, it was a ~20 elo loss. However the implementation was somewhat nicer, and allowed me to remove a few fail soft related hacks. I'm still experimenting, trying to retain some of the simplicity benefit of fail soft, without the elo loss. I'm trying some half-assed approaches.

What's the consensus here? (if there is any).
Where would the 20 elo come from???
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: fail hard

Post by Sven »

Stan Arts wrote:The main advantage, probably, of fail hard is that it's easier to implement.
For example you don't need a separate eval variable set to -inf at every new node but simply an alpha variable that's allowed to rise and initially set to the value of that of 2 ply before.
But that means ofcourse that you don't get a move at all if the score remains equal or below alpha.
With fail soft at the end of a child node you probably do something like

if best_score[depth] > best_score[depth-1] then best_score[depth-1] = best_score[depth]

In addition to

if best_score[depth] > alpha[depth-1] then alpha[depth-1] = best_score[depth]

And with fail hard you probably only need the second line.

But with fail soft it happens pretty often that you get scores outside of bounds. They can be scores from hash, indications from eval, matescores and who knows. And that just sounds like extra information to me though probably rather useless.
In fail hard, the lazy approach is indeed to reuse "alpha" as "best_score" and update it accordingly. But often you also need to keep track of the original value of "alpha" that was valid when entering a new node, e.g. for correct tracking of the PV or to store correct "exact/lower bound/upper bound" information in the TT.

So in fact you still need two variables, one for the original alpha and one for the best score, which allows to implement fail soft and fail hard with exactly the same algorithm except for the initialization of "best_score": you set it to "alpha" in fail hard and to "-INF" in fail soft. Apart from that initialization, both fail hard and fail soft can do the recursive call to search() (or the equivalent in an iterative implementation) with "-beta, -Max(alpha, best_score)". That "Max(...)" expression looks pointless for fail hard, and of course you can replace it by "best_score" when optimizing for speed, but for the purpose of comparing the algorithms the original form could be kept.
syzygy
Posts: 5566
Joined: Tue Feb 28, 2012 11:56 pm

Re: fail hard

Post by syzygy »

Stan Arts wrote:But that means ofcourse that you don't get a move at all if the score remains equal or below alpha.
I don't think the "best" move should be used for anything in case alpha is not improved upon. It's basically a random move because the search has made no effort to see how bad or not-so-bad all of the "below alpha" moves are.
elcabesa
Posts: 855
Joined: Sun May 23, 2010 1:32 pm

Re: fail hard

Post by elcabesa »

correct me whether I'm wrong, but I'm I don't use originalAlpha in my failsoft.
I set the type of the node to typeScoreLowerThanAlpha entering the search and then I change it to typeExact when I check if the score>alpha
at the end of each iteration.
Just before saving it to the TranspositionTable I cheched if score>=beta, if it's true i set the type to typeScoreHigherThanBeta
Stan Arts
Posts: 179
Joined: Fri Feb 14, 2014 10:53 pm
Location: the Netherlands

Re: fail hard

Post by Stan Arts »

Sven Schüle wrote: In fail hard, the lazy approach is indeed to reuse "alpha" as "best_score" and update it accordingly. But often you also need to keep track of the original value of "alpha" that was valid when entering a new node, e.g. for correct tracking of the PV or to store correct "exact/lower bound/upper bound" information in the TT.

So in fact you still need two variables, one for the original alpha and one for the best score, which allows to implement fail soft and fail hard with exactly the same algorithm except for the initialization of "best_score": you set it to "alpha" in fail hard and to "-INF" in fail soft. Apart from that initialization, both fail hard and fail soft can do the recursive call to search() (or the equivalent in an iterative implementation) with "-beta, -Max(alpha, best_score)". That "Max(...)" expression looks pointless for fail hard, and of course you can replace it by "best_score" when optimizing for speed, but for the purpose of comparing the algorithms the original form could be kept.
Isn't the orinigal alpha, still the alpha of depth - 2 ?
Stan Arts
Posts: 179
Joined: Fri Feb 14, 2014 10:53 pm
Location: the Netherlands

Re: fail hard

Post by Stan Arts »

syzygy wrote: I don't think the "best" move should be used for anything in case alpha is not improved upon. It's basically a random move because the search has made no effort to see how bad or not-so-bad all of the "below alpha" moves are.
Sure, though pretty funny things get returned in a fail soft search and it's always been my hope that once in a while < alpha scoring turns up something in the sense of a least worst capture or so. Otherwise it should pretty much return the first move and then storing doesn't hurt anyway. Ofcourse that's something to test but I've never done that.
(My previous efforts pretty much show what happens when you code completely by intuition/do no testing at all except for programming bugs.
While ago I came up with a really fast (for me) mailbox datastructure/generator and recently I've finally felt inspired to code it up. Hence my current renewed spark of interest in computerchess. ..But I'm doing it for the C64. :) 8 bit 6502 assembly ftw. With a pc version on the side to wrap my head around the datastructures. But I have no plans to develop it into a full program again. ..or maybe.)