Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to have Stockfish 17 Win-Draw-Loss Model #1108

Open
MX6464 opened this issue Sep 23, 2024 · 4 comments
Open

Update to have Stockfish 17 Win-Draw-Loss Model #1108

MX6464 opened this issue Sep 23, 2024 · 4 comments
Milestone

Comments

@MX6464
Copy link

MX6464 commented Sep 23, 2024

Can anyone add the new Stockfish 17 Win-Draw-Loss model? https://github.com/official-stockfish/WDL_model

@niklasf
Copy link
Owner

niklasf commented Sep 27, 2024

Looks like this time it's not just updating the parameters (official-stockfish/Stockfish@2054add), but also taking into account material counts: official-stockfish/Stockfish@9b92ada.

@robertnurnberg
Copy link

That is correct. What does/did python-chess use SF's wdl model for?

@MX6464
Copy link
Author

MX6464 commented Sep 27, 2024

python-chess WDL calculations found here:

def wdl(self, *, model: WdlModel = "sf", ply: int = 30) -> Wdl:
"""
Returns statistics for the expected outcome of this game, based on
a *model*, given that this score is reached at *ply*.
Scores have a total order, but it makes little sense to compute
the difference between two scores. For example, going from
``Cp(-100)`` to ``Cp(+100)`` is much more significant than going
from ``Cp(+300)`` to ``Cp(+500)``. It is better to compute differences
of the expectation values for the outcome of the game (based on winning
chances and drawing chances).
>>> Cp(100).wdl().expectation() - Cp(-100).wdl().expectation() # doctest: +ELLIPSIS
0.379...
>>> Cp(500).wdl().expectation() - Cp(300).wdl().expectation() # doctest: +ELLIPSIS
0.015...
:param model:
* ``sf``, the WDL model used by the latest Stockfish
(currently ``sf16``).
* ``sf16``, the WDL model used by Stockfish 16.
* ``sf15.1``, the WDL model used by Stockfish 15.1.
* ``sf15``, the WDL model used by Stockfish 15.
* ``sf14``, the WDL model used by Stockfish 14.
* ``sf12``, the WDL model used by Stockfish 12.
* ``lichess``, the win rate model used by Lichess.
Does not use *ply*, and does not consider drawing chances.
:param ply: The number of half-moves played since the starting
position. Models may scale scores slightly differently based on
this. Defaults to middle game.
"""
@abc.abstractmethod
def __neg__(self) -> Score:
...
@abc.abstractmethod
def __pos__(self) -> Score:
...
@abc.abstractmethod
def __abs__(self) -> Score:
...
def _score_tuple(self) -> Tuple[bool, bool, bool, int, Optional[int]]:
mate = self.mate()
return (
isinstance(self, MateGivenType),
mate is not None and mate > 0,
mate is None,
-(mate or 0),
self.score(),
)
def __eq__(self, other: object) -> bool:
if isinstance(other, Score):
return self._score_tuple() == other._score_tuple()
else:
return NotImplemented
def __lt__(self, other: object) -> bool:
if isinstance(other, Score):
return self._score_tuple() < other._score_tuple()
else:
return NotImplemented
def __le__(self, other: object) -> bool:
if isinstance(other, Score):
return self._score_tuple() <= other._score_tuple()
else:
return NotImplemented
def __gt__(self, other: object) -> bool:
if isinstance(other, Score):
return self._score_tuple() > other._score_tuple()
else:
return NotImplemented
def __ge__(self, other: object) -> bool:
if isinstance(other, Score):
return self._score_tuple() >= other._score_tuple()
else:
return NotImplemented
def _sf16_1_wins(cp: int, *, ply: int) -> int:
# https://github.com/official-stockfish/Stockfish/blob/sf_16.1/src/uci.cpp#L48
NormalizeToPawnValue = 356
# https://github.com/official-stockfish/Stockfish/blob/sf_16.1/src/uci.cpp#L383-L384
m = min(120, max(8, ply / 2 + 1)) / 32
a = (((-1.06249702 * m + 7.42016937) * m + 0.89425629) * m) + 348.60356174
b = (((-5.33122190 * m + 39.57831533) * m + -90.84473771) * m) + 123.40620748
x = min(4000, max(cp * NormalizeToPawnValue / 100, -4000))
return int(0.5 + 1000 / (1 + math.exp((a - x) / b)))
def _sf16_wins(cp: int, *, ply: int) -> int:
# https://github.com/official-stockfish/Stockfish/blob/sf_16/src/uci.h#L38
NormalizeToPawnValue = 328
# https://github.com/official-stockfish/Stockfish/blob/sf_16/src/uci.cpp#L200-L224
m = min(240, max(ply, 0)) / 64
a = (((0.38036525 * m + -2.82015070) * m + 23.17882135) * m) + 307.36768407
b = (((-2.29434733 * m + 13.27689788) * m + -14.26828904) * m) + 63.45318330
x = min(4000, max(cp * NormalizeToPawnValue / 100, -4000))
return int(0.5 + 1000 / (1 + math.exp((a - x) / b)))
def _sf15_1_wins(cp: int, *, ply: int) -> int:
# https://github.com/official-stockfish/Stockfish/blob/sf_15.1/src/uci.h#L38
NormalizeToPawnValue = 361
# https://github.com/official-stockfish/Stockfish/blob/sf_15.1/src/uci.cpp#L200-L224
m = min(240, max(ply, 0)) / 64
a = (((-0.58270499 * m + 2.68512549) * m + 15.24638015) * m) + 344.49745382
b = (((-2.65734562 * m + 15.96509799) * m + -20.69040836) * m) + 73.61029937
x = min(4000, max(cp * NormalizeToPawnValue / 100, -4000))
return int(0.5 + 1000 / (1 + math.exp((a - x) / b)))
def _sf15_wins(cp: int, *, ply: int) -> int:
# https://github.com/official-stockfish/Stockfish/blob/sf_15/src/uci.cpp#L200-L220
m = min(240, max(ply, 0)) / 64
a = (((-1.17202460e-1 * m + 5.94729104e-1) * m + 1.12065546e+1) * m) + 1.22606222e+2
b = (((-1.79066759 * m + 11.30759193) * m + -17.43677612) * m) + 36.47147479
x = min(2000, max(cp, -2000))
return int(0.5 + 1000 / (1 + math.exp((a - x) / b)))
def _sf14_wins(cp: int, *, ply: int) -> int:
# https://github.com/official-stockfish/Stockfish/blob/sf_14/src/uci.cpp#L200-L220
m = min(240, max(ply, 0)) / 64
a = (((-3.68389304 * m + 30.07065921) * m + -60.52878723) * m) + 149.53378557
b = (((-2.01818570 * m + 15.85685038) * m + -29.83452023) * m) + 47.59078827
x = min(2000, max(cp, -2000))
return int(0.5 + 1000 / (1 + math.exp((a - x) / b)))
def _sf12_wins(cp: int, *, ply: int) -> int:
# https://github.com/official-stockfish/Stockfish/blob/sf_12/src/uci.cpp#L198-L218
m = min(240, max(ply, 0)) / 64
a = (((-8.24404295 * m + 64.23892342) * m + -95.73056462) * m) + 153.86478679
b = (((-3.37154371 * m + 28.44489198) * m + -56.67657741) * m) + 72.05858751
x = min(1000, max(cp, -1000))
return int(0.5 + 1000 / (1 + math.exp((a - x) / b)))
def _lichess_raw_wins(cp: int) -> int:
# https://github.com/lichess-org/lila/pull/11148
# https://github.com/lichess-org/lila/blob/2242b0a08faa06e7be5508d338ede7bb09049777/modules/analyse/src/main/WinPercent.scala#L26-L30
return round(1000 / (1 + math.exp(-0.00368208 * cp)))

@robertnurnberg
Copy link

robertnurnberg commented Sep 27, 2024

Ok, so this needs to be based on material count now, so quite an invasive change. Also NormalizeToPawnValue needs to be replaced by a now.

Edit: And the capping to [-4000,4000] can go.

@niklasf niklasf added this to the v2.0.0 milestone Oct 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants