I'm trying to make Minic compatible with Armageddon (draw is a win for Black).
To do so I first convert centipawn to WDL values (despite the "polemic" I'm using the same script as what Vondele did for SF, using Minic game to fit a 3rd order polynomial on the current ply for "a" and "b" coefficient of a shifted sigmoid). And I added a fonction to convert back a win probability to a score.
I'm using that if armageddon is enabled. If it is black turn I add draw probability to win probability and convert this to a new corrected cp score.
If it is White turn, I add draw probability to lose probability and convert this to a new corrected opposite cp score.
Maybe just the code speaks better
Code: Select all
// idea from Stockfish
namespace WDL{
// Coefficients of a 3rd order polynomial fit based on Minic test data (from CCRL, CEGT, FGRL)
const double as[] = {-13.65744616, 94.04894005, -95.05180396, 84.853482690};
const double bs[] = {-10.78187987, 77.22626799, -132.72201029, 122.54185402};
}
inline double toWDLModel(ScoreType v, DepthType ply) {
// limit input ply and rescale
const double m = std::min(DepthType(256), ply) / 32.0;
const double a = (((WDL::as[0] * m + WDL::as[1]) * m + WDL::as[2]) * m) + WDL::as[3];
const double b = (((WDL::bs[0] * m + WDL::bs[1]) * m + WDL::bs[2]) * m) + WDL::bs[3];
// clamp score
const double x = std::clamp(double((a - v) / b), -600.0, 600.0);
// win probability from 0 to 1000
return 0.5 + 1000. / (1. + std::exp(x));
}
inline ScoreType fromWDLModel(double w, DepthType ply) {
// limit input ply and rescale
const double m = std::min(DepthType(256), ply) / 32.0;
const double a = (((WDL::as[0] * m + WDL::as[1]) * m + WDL::as[2]) * m) + WDL::as[3];
const double b = (((WDL::bs[0] * m + WDL::bs[1]) * m + WDL::bs[2]) * m) + WDL::bs[3];
const double s = a - b * std::log(1000./(std::max(w,0.5+std::numeric_limits<double>::epsilon())-0.5) - 1.);
return ScoreType(std::clamp(s, double(-MATE + ply) , double(MATE - ply + 1)) );
}
ScoreType armageddonScore(ScoreType score, DepthType ply, Color c){
if ( ! DynamicConfig::armageddon) return score;
double wdlW = toWDLModel(score,ply);
double wdlL = toWDLModel(-score,ply);
const double wdlD = 1000 - wdlW - wdlL;
if (c == Co_Black ){
wdlW += wdlD;
score = fromWDLModel(wdlW,ply);
}
else{
wdlL += wdlD;
score = -fromWDLModel(wdlL,ply);
}
return score;
}
I'm tracking some bugs.
For instance, it seems to me that the clamping in toWDLModel (you can use 600 or 800 as bound) is necessary so that std::exp don't return inf.
Next thing is that std::log(1000./(std::max(w,0.5+std::numeric_limits<double>::epsilon())-0.5) - 1.); that we shall manipulate carefully.
Of course draw score is handle separately also taking armageddon onto account.
Any idea of better formulas to take into account without struggling to much ?