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

Add --handicap-rank-difference-{small,19x19} options #51

Merged
merged 1 commit into from
Dec 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions analysis/analyze_glicko2_daily_windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ def process_game(self, game: GameRecord) -> Glicko2Analytics:
black_base,
[
(
opponent.copy((1 if past_game.black_id != game.black_id else -1) * get_handicap_adjustment(opponent.rating, past_game.handicap)),
opponent.copy((1 if past_game.black_id != game.black_id else -1) * get_handicap_adjustment(opponent.rating, past_game.handicap,
komi=past_game.komi, size=past_game.size, rules=past_game.rules,
)),
past_game.winner_id == game.black_id
)
for past_game, opponent in self._storage.get_matches_newer_or_equal_to(
Expand All @@ -58,7 +60,9 @@ def process_game(self, game: GameRecord) -> Glicko2Analytics:
white_base,
[
(
opponent.copy((1 if past_game.black_id != game.white_id else -1) * get_handicap_adjustment(opponent.rating, past_game.handicap)),
opponent.copy((1 if past_game.black_id != game.white_id else -1) * get_handicap_adjustment(opponent.rating, past_game.handicap,
komi=past_game.komi, size=past_game.size, rules=past_game.rules,
)),
past_game.winner_id == game.white_id
)
for past_game, opponent in self._storage.get_matches_newer_or_equal_to(
Expand All @@ -76,7 +80,9 @@ def process_game(self, game: GameRecord) -> Glicko2Analytics:
skipped=False,
game=game,
expected_win_rate=black_cur.expected_win_probability(
white_cur, get_handicap_adjustment(black_cur.rating, game.handicap), ignore_g=True
white_cur, get_handicap_adjustment(black_cur.rating, game.handicap,
komi=game.komi, size=game.size, rules=game.rules,
), ignore_g=True
),
black_rating=black_cur.rating,
white_rating=white_cur.rating,
Expand Down
12 changes: 9 additions & 3 deletions analysis/analyze_glicko2_glickman_weekly_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ def process_game(self, game: GameRecord) -> Glicko2Analytics:
black_base,
[
(
opponent.copy((1 if past_game.black_id != game.black_id else -1) * get_handicap_adjustment(opponent.rating, past_game.handicap)),
opponent.copy((1 if past_game.black_id != game.black_id else -1) * get_handicap_adjustment(opponent.rating, past_game.handicap,
komi=past_game.komi, size=past_game.size, rules=past_game.rules,
)),
past_game.winner_id == past_game.black_id
)
for past_game, opponent in self._storage.get_matches_newer_or_equal_to(
Expand All @@ -66,7 +68,9 @@ def process_game(self, game: GameRecord) -> Glicko2Analytics:
white_base,
[
(
opponent.copy((1 if past_game.black_id != game.white_id else -1) * get_handicap_adjustment(opponent.rating, past_game.handicap)),
opponent.copy((1 if past_game.black_id != game.white_id else -1) * get_handicap_adjustment(opponent.rating, past_game.handicap,
komi=past_game.komi, size=past_game.size, rules=past_game.rules,
)),
past_game.winner_id == past_game.white_id
)
for past_game, opponent in self._storage.get_matches_newer_or_equal_to(
Expand All @@ -84,7 +88,9 @@ def process_game(self, game: GameRecord) -> Glicko2Analytics:
skipped=False,
game=game,
expected_win_rate=black_cur.expected_win_probability(
white_cur, get_handicap_adjustment(black_cur.rating, game.handicap), ignore_g=True
white_cur, get_handicap_adjustment(black_cur.rating, game.handicap,
komi=game.komi, size=game.size, rules=game.rules,
), ignore_g=True
),
black_rating=black_cur.rating,
white_rating=white_cur.rating,
Expand Down
16 changes: 12 additions & 4 deletions analysis/analyze_glicko2_one_game_at_a_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,14 @@ def process_game(self, game: GameRecord) -> Glicko2Analytics:
black = self._storage.get(game.black_id)
white = self._storage.get(game.white_id)


updated_black = glicko2_update(
black,
[
(
white.copy(-get_handicap_adjustment(white.rating, game.handicap)),
white.copy(-get_handicap_adjustment(white.rating, game.handicap,
komi=game.komi, size=game.size,
rules=game.rules,
)),
game.winner_id == game.black_id,
)
],
Expand All @@ -50,7 +52,10 @@ def process_game(self, game: GameRecord) -> Glicko2Analytics:
white,
[
(
black.copy(get_handicap_adjustment(black.rating, game.handicap)),
black.copy(get_handicap_adjustment(black.rating, game.handicap,
komi=game.komi, size=game.size,
rules=game.rules,
)),
game.winner_id == game.white_id,
)
],
Expand All @@ -65,7 +70,10 @@ def process_game(self, game: GameRecord) -> Glicko2Analytics:
skipped=False,
game=game,
expected_win_rate=black.expected_win_probability(
white, get_handicap_adjustment(black.rating, game.handicap), ignore_g=True
white, get_handicap_adjustment(black.rating, game.handicap,
komi=game.komi, size=game.size,
rules=game.rules,
), ignore_g=True
),
black_rating=black.rating,
white_rating=white.rating,
Expand Down
12 changes: 9 additions & 3 deletions analysis/analyze_glicko2_one_game_at_a_time_rating_grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ def process_game(self, game: GameRecord) -> Dict[str, Glicko2Analytics]:
black,
[
(
src_white.copy(-get_handicap_adjustment(src_white.rating, game.handicap)),
src_white.copy(-get_handicap_adjustment(src_white.rating, game.handicap,
komi=game.komi, size=game.size, rules=game.rules,
)),
game.winner_id == game.black_id,
)
],
Expand All @@ -73,7 +75,9 @@ def process_game(self, game: GameRecord) -> Dict[str, Glicko2Analytics]:
white,
[
(
src_black.copy(get_handicap_adjustment(src_black.rating, game.handicap)),
src_black.copy(get_handicap_adjustment(src_black.rating, game.handicap,
komi=game.komi, size=game.size, rules=game.rules,
)),
game.winner_id == game.white_id,
)
],
Expand All @@ -89,7 +93,9 @@ def process_game(self, game: GameRecord) -> Dict[str, Glicko2Analytics]:
skipped=False,
game=game,
expected_win_rate=black.expected_win_probability(
white, get_handicap_adjustment(black.rating, game.handicap), ignore_g=True
white, get_handicap_adjustment(black.rating, game.handicap,
komi=game.komi, size=game.size, rules=game.rules,
), ignore_g=True
),
black_rating=black.rating,
white_rating=white.rating,
Expand Down
12 changes: 9 additions & 3 deletions analysis/analyze_glicko2_weekly_window_no_unxepected_changes.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ def process_game(self, game: GameRecord) -> Glicko2Analytics:
black_base,
[
(
opponent.copy((1 if past_game.black_id != game.black_id else -1) * get_handicap_adjustment(opponent.rating, past_game.handicap)),
opponent.copy((1 if past_game.black_id != game.black_id else -1) * get_handicap_adjustment(opponent.rating, past_game.handicap,
komi=past_game.komi, size=past_game.size, rules=past_game.rules,
)),
past_game.winner_id == past_game.black_id
)
for past_game, opponent in self._storage.get_matches_newer_or_equal_to(
Expand All @@ -63,7 +65,9 @@ def process_game(self, game: GameRecord) -> Glicko2Analytics:
white_base,
[
(
opponent.copy((1 if past_game.black_id != game.white_id else -1) * get_handicap_adjustment(opponent.rating, past_game.handicap)),
opponent.copy((1 if past_game.black_id != game.white_id else -1) * get_handicap_adjustment(opponent.rating, past_game.handicap,
komi=past_game.komi, size=past_game.size, rules=past_game.rules,
)),
past_game.winner_id == past_game.white_id
)
for past_game, opponent in self._storage.get_matches_newer_or_equal_to(
Expand Down Expand Up @@ -96,7 +100,9 @@ def process_game(self, game: GameRecord) -> Glicko2Analytics:
skipped=False,
game=game,
expected_win_rate=black_cur.expected_win_probability(
white_cur, get_handicap_adjustment(black_cur.rating, game.handicap), ignore_g=True
white_cur, get_handicap_adjustment(black_cur.rating, game.handicap,
komi=game.komi, size=game.size, rules=game.rules,
), ignore_g=True
),
black_rating=black_cur.rating,
white_rating=white_cur.rating,
Expand Down
12 changes: 9 additions & 3 deletions analysis/analyze_glicko2_weekly_window_reduce_rating_movement.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ def process_game(self, game: GameRecord) -> Glicko2Analytics:
black_base,
[
(
opponent.copy((1 if past_game.black_id != game.black_id else -1) * get_handicap_adjustment(opponent.rating, past_game.handicap)),
opponent.copy((1 if past_game.black_id != game.black_id else -1) * get_handicap_adjustment(opponent.rating, past_game.handicap,
komi=past_game.komi, size=past_game.size, rules=past_game.rules,
)),
past_game.winner_id == past_game.black_id
)
for past_game, opponent in self._storage.get_matches_newer_or_equal_to(
Expand All @@ -68,7 +70,9 @@ def process_game(self, game: GameRecord) -> Glicko2Analytics:
white_base,
[
(
opponent.copy((1 if past_game.black_id != game.white_id else -1) * get_handicap_adjustment(opponent.rating, past_game.handicap)),
opponent.copy((1 if past_game.black_id != game.white_id else -1) * get_handicap_adjustment(opponent.rating, past_game.handicap,
komi=past_game.komi, size=past_game.size, rules=past_game.rules,
)),
past_game.winner_id == past_game.white_id
)
for past_game, opponent in self._storage.get_matches_newer_or_equal_to(
Expand Down Expand Up @@ -112,7 +116,9 @@ def process_game(self, game: GameRecord) -> Glicko2Analytics:
skipped=False,
game=game,
expected_win_rate=black_cur.expected_win_probability(
white_cur, get_handicap_adjustment(black_cur.rating, game.handicap), ignore_g=True
white_cur, get_handicap_adjustment(black_cur.rating, game.handicap,
komi=game.komi, size=game.size, rules=game.rules,
), ignore_g=True
),
black_rating=black_cur.rating,
white_rating=white_cur.rating,
Expand Down
16 changes: 11 additions & 5 deletions analysis/analyze_gor.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,19 @@ def process_game(self, game: GameRecord) -> GorAnalytics:


updated_black = gor_update(
black.with_handicap(get_handicap_adjustment(black.rating, game.handicap)),
#white.with_handicap(-get_handicap_adjustment(white.rating, game.handicap)),
black.with_handicap(get_handicap_adjustment(black.rating, game.handicap,
komi=game.komi, size=game.size, rules=game.rules,
)),
#white.with_handicap(-get_handicap_adjustment(white.rating, game.handicap, ...)),
white,
1 if game.winner_id == game.black_id else 0,
)

updated_white = gor_update(
white,
black.with_handicap(get_handicap_adjustment(black.rating, game.handicap)),
black.with_handicap(get_handicap_adjustment(black.rating, game.handicap,
komi=game.komi, size=game.size, rules=game.rules,
)),
1 if game.winner_id == game.white_id else 0,
)

Expand All @@ -65,8 +69,10 @@ def process_game(self, game: GameRecord) -> GorAnalytics:
return GorAnalytics(
skipped=False,
game=game,
expected_win_rate=black.with_handicap(get_handicap_adjustment(white.rating, game.handicap)).expected_win_probability(
#white.copy(-get_handicap_adjustment(white.rating, game.handicap))
expected_win_rate=black.with_handicap(get_handicap_adjustment(white.rating, game.handicap,
komi=game.komi, size=game.size, rules=game.rules,
)).expected_win_probability(
#white.copy(-get_handicap_adjustment(white.rating, game.handicap, ...))
white
),
black_rating=black.rating,
Expand Down
79 changes: 74 additions & 5 deletions analysis/util/RatingMath.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,25 @@
P = 1
HALF_STONE_HANDICAP = False
HALF_STONE_HANDICAP_FOR_ALL_RANKS = False
HANDICAP_RANK_DIFFERENCE_SMALL = False
HANDICAP_RANK_DIFFERENCE_19X19 = False

cli.add_argument(
"--half-stone-handicap", dest="half_stone_handicap", const=1, default=False, action="store_const", help="Use a 0.5 rank adjustment for hc1",
)
cli.add_argument(
"--half-stone-handicap-for-all-ranks", dest="half_stone_handicap_for_all_ranks", const=1, default=False, action="store_const", help="use rankdiff -0.5 for handicap",
)
cli.add_argument(
"--handicap-rank-difference-small",
dest="handicap_rank_difference_small", const=1, default=False, action="store_const",
help="compute effective handicap rank difference with komi for small boards",
)
cli.add_argument(
"--handicap-rank-difference-19x19",
dest="handicap_rank_difference_19x19", const=1, default=False, action="store_const",
help="compute effective handicap rank difference with komi for 19x19 boards",
)

logarithmic = cli.add_argument_group(
"logarithmic ranking variables", "rating to ranks converted with `(log(rating / a) ** p) * c + d`",
Expand Down Expand Up @@ -77,14 +89,65 @@ def set_exhaustive_log_parameters(a: float, c:float, d:float, p:float = 1.0) ->
D = d
P = p

def get_handicap_adjustment(rating: float, handicap: int) -> float:

def get_handicap_rank_difference(handicap: int, size: int, komi: float, rules: str) -> float:
global HALF_STONE_HANDICAP
global HALF_STONE_HANDICAP_FOR_ALL_RANKS
global HANDICAP_RANK_DIFFERENCE_SMALL
global HANDICAP_RANK_DIFFERENCE_19X19

if (HANDICAP_RANK_DIFFERENCE_19X19 and size == 19) or (HANDICAP_RANK_DIFFERENCE_SMALL and size != 19):
# The territorial value of a free stone.
stone_value = 12

# Number of extra moves black makes before white responds.
num_extra_moves = handicap - 1 if handicap > 1 else 0

if rules == "japanese" or rules == "korean":
# Territory scoring.
area_bonus = 0
komi_bonus = 0
else:
# Bonus for the area value of a stone in area scoring.
area_bonus = 1

# Chinese and AGA rules add extra komi when there's a handicap but
# don't store it in the 'komi' field.
if rules == "chinese":
komi_bonus = 1 * handicap
elif rules == "aga":
komi_bonus = 1 * num_extra_moves
else:
komi_bonus = 0

# Figure out the point value of black's head start, if any, by
# subtracting the actual komi from the fair komi for an even game, and
# adding the point value of any extra moves.
fair_komi = stone_value / 2 + area_bonus + 0.5
actual_komi = komi + komi_bonus
value_extra_moves = (stone_value + area_bonus) * num_extra_moves
head_start = fair_komi - actual_komi + value_extra_moves

# Convert back to a fractional handicap, using scaling factors of 3x
# and 6x for 9x9 and 13x13.
if size == 9:
return head_start * 6 / stone_value
if size == 13:
return head_start * 3 / stone_value
return head_start / stone_value

if HALF_STONE_HANDICAP_FOR_ALL_RANKS:
return rank_to_rating(rating_to_rank(rating) + (handicap - 0.5 if handicap > 0 else 0)) - rating
return handicap - 0.5 if handicap > 0 else 0
if HALF_STONE_HANDICAP:
return rank_to_rating(rating_to_rank(rating) + (0.5 if handicap == 1 else handicap)) - rating
return rank_to_rating(rating_to_rank(rating) + handicap) - rating
return 0.5 if handicap == 1 else handicap
return handicap


def get_handicap_adjustment(rating: float, handicap: int, size: int, komi: float, rules: str) -> float:
rank_difference = get_handicap_rank_difference(handicap, size, komi, rules)
effective_rank = rating_to_rank(rating) + rank_difference
return rank_to_rating(effective_rank) - rating


def set_optimizer_rating_points(points: List[float]) -> None:
global optimizer_rating_control_points
Expand All @@ -99,9 +162,13 @@ def configure_rating_to_rank(args: argparse.Namespace) -> None:
global D
global HALF_STONE_HANDICAP
global HALF_STONE_HANDICAP_FOR_ALL_RANKS
global HANDICAP_RANK_DIFFERENCE_SMALL
global HANDICAP_RANK_DIFFERENCE_19X19

HALF_STONE_HANDICAP = args.half_stone_handicap
HALF_STONE_HANDICAP_FOR_ALL_RANKS = args.half_stone_handicap_for_all_ranks
HANDICAP_RANK_DIFFERENCE_SMALL = args.handicap_rank_difference_small
HANDICAP_RANK_DIFFERENCE_19X19 = args.handicap_rank_difference_19x19
system: str = args.ranks
a: float = args.a
c: float = args.c
Expand Down Expand Up @@ -260,7 +327,9 @@ def __rating_to_rank(rating: float) -> float:
else:
raise NotImplementedError

assert round(get_handicap_adjustment(1000.0, 0), 8) == 0
for size in [9, 13, 19]:
assert round(get_handicap_adjustment(1000.0, 0, size=size, rules="japanese", komi=6.5), 8) == 0
assert round(get_handicap_adjustment(1000.0, 0, size=size, rules="aga", komi=7.5), 8) == 0


def lerp(x:float, y:float, a:float):
Expand Down