Add gates 1-2 audit and repair workflow
This commit is contained in:
@@ -0,0 +1,40 @@
|
|||||||
|
run:
|
||||||
|
experiment_name: gates-1-2-long-random-exploiter
|
||||||
|
seed: 20260705
|
||||||
|
learner_seat: 0
|
||||||
|
total_updates: 1200
|
||||||
|
log_every: 10
|
||||||
|
checkpoint_every: 100
|
||||||
|
artifact_root: /mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/exploiters
|
||||||
|
|
||||||
|
opponent:
|
||||||
|
name: league_v1_update_500_frozen
|
||||||
|
|
||||||
|
network:
|
||||||
|
hidden_size: 512
|
||||||
|
num_layers: 3
|
||||||
|
|
||||||
|
ppo:
|
||||||
|
batch_games: 8192
|
||||||
|
rollout_steps: 400
|
||||||
|
gamma: 1.0
|
||||||
|
gae_lambda: 0.95
|
||||||
|
clip_epsilon: 0.2
|
||||||
|
entropy_coef: 0.01
|
||||||
|
value_coef: 0.5
|
||||||
|
max_grad_norm: 0.5
|
||||||
|
learning_rate: 0.0003
|
||||||
|
epochs: 4
|
||||||
|
minibatches: 128
|
||||||
|
|
||||||
|
reward:
|
||||||
|
terminal_scale: 50.0
|
||||||
|
potential_shaping_initial: 1.0
|
||||||
|
potential_shaping_final: 0.0
|
||||||
|
potential_shaping_anneal_steps: 5000000
|
||||||
|
|
||||||
|
evaluation:
|
||||||
|
games: 2000
|
||||||
|
duplicate: true
|
||||||
|
shuffle_bank_seed: 20260704
|
||||||
|
batch_games: 8192
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
run:
|
||||||
|
experiment_name: gates-1-2-replay-exploiter
|
||||||
|
seed: 20260705
|
||||||
|
learner_seat: 0
|
||||||
|
total_updates: 900
|
||||||
|
log_every: 10
|
||||||
|
checkpoint_every: 100
|
||||||
|
artifact_root: /mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/exploiters
|
||||||
|
|
||||||
|
opponent:
|
||||||
|
name: league_v1_update_500_frozen
|
||||||
|
|
||||||
|
network:
|
||||||
|
hidden_size: 512
|
||||||
|
num_layers: 3
|
||||||
|
|
||||||
|
ppo:
|
||||||
|
batch_games: 8192
|
||||||
|
rollout_steps: 400
|
||||||
|
gamma: 1.0
|
||||||
|
gae_lambda: 0.95
|
||||||
|
clip_epsilon: 0.2
|
||||||
|
entropy_coef: 0.01
|
||||||
|
value_coef: 0.5
|
||||||
|
max_grad_norm: 0.5
|
||||||
|
learning_rate: 0.0003
|
||||||
|
epochs: 4
|
||||||
|
minibatches: 128
|
||||||
|
|
||||||
|
reward:
|
||||||
|
terminal_scale: 50.0
|
||||||
|
potential_shaping_initial: 0.0
|
||||||
|
potential_shaping_final: 0.0
|
||||||
|
potential_shaping_anneal_steps: 0
|
||||||
|
|
||||||
|
evaluation:
|
||||||
|
games: 2000
|
||||||
|
duplicate: true
|
||||||
|
shuffle_bank_seed: 20260704
|
||||||
|
batch_games: 8192
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
run:
|
||||||
|
experiment_name: gates-1-2-smoke-exploiter
|
||||||
|
seed: 20260705
|
||||||
|
learner_seat: 0
|
||||||
|
total_updates: 1
|
||||||
|
log_every: 1
|
||||||
|
checkpoint_every: 1
|
||||||
|
artifact_root: /mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2-smoke/exploiters
|
||||||
|
|
||||||
|
opponent:
|
||||||
|
name: league_v1_update_500_frozen
|
||||||
|
|
||||||
|
network:
|
||||||
|
hidden_size: 512
|
||||||
|
num_layers: 3
|
||||||
|
|
||||||
|
ppo:
|
||||||
|
batch_games: 8
|
||||||
|
rollout_steps: 16
|
||||||
|
gamma: 1.0
|
||||||
|
gae_lambda: 0.95
|
||||||
|
clip_epsilon: 0.2
|
||||||
|
entropy_coef: 0.01
|
||||||
|
value_coef: 0.5
|
||||||
|
max_grad_norm: 0.5
|
||||||
|
learning_rate: 0.0003
|
||||||
|
epochs: 1
|
||||||
|
minibatches: 2
|
||||||
|
|
||||||
|
reward:
|
||||||
|
terminal_scale: 50.0
|
||||||
|
potential_shaping_initial: 1.0
|
||||||
|
potential_shaping_final: 0.0
|
||||||
|
potential_shaping_anneal_steps: 5000000
|
||||||
|
|
||||||
|
evaluation:
|
||||||
|
games: 2
|
||||||
|
duplicate: true
|
||||||
|
shuffle_bank_seed: 20260704
|
||||||
|
batch_games: 2
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
run:
|
||||||
|
experiment_name: gates-1-2-warmstart-gate3-exploiter
|
||||||
|
seed: 20260705
|
||||||
|
learner_seat: 0
|
||||||
|
total_updates: 900
|
||||||
|
log_every: 10
|
||||||
|
checkpoint_every: 100
|
||||||
|
artifact_root: /mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/exploiters
|
||||||
|
|
||||||
|
opponent:
|
||||||
|
name: league_v1_update_500_frozen
|
||||||
|
|
||||||
|
network:
|
||||||
|
hidden_size: 512
|
||||||
|
num_layers: 3
|
||||||
|
|
||||||
|
ppo:
|
||||||
|
batch_games: 8192
|
||||||
|
rollout_steps: 400
|
||||||
|
gamma: 1.0
|
||||||
|
gae_lambda: 0.95
|
||||||
|
clip_epsilon: 0.2
|
||||||
|
entropy_coef: 0.01
|
||||||
|
value_coef: 0.5
|
||||||
|
max_grad_norm: 0.5
|
||||||
|
learning_rate: 0.0003
|
||||||
|
epochs: 4
|
||||||
|
minibatches: 128
|
||||||
|
|
||||||
|
reward:
|
||||||
|
terminal_scale: 50.0
|
||||||
|
potential_shaping_initial: 0.0
|
||||||
|
potential_shaping_final: 0.0
|
||||||
|
potential_shaping_anneal_steps: 0
|
||||||
|
|
||||||
|
evaluation:
|
||||||
|
games: 2000
|
||||||
|
duplicate: true
|
||||||
|
shuffle_bank_seed: 20260704
|
||||||
|
batch_games: 8192
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
run:
|
||||||
|
artifact_root: /mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2-smoke
|
||||||
|
report_path: /mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2-smoke/report.md
|
||||||
|
summary_path: /mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2-smoke/summary.jsonl
|
||||||
|
shuffle_bank_seed: 20260704
|
||||||
|
gpu_budget_hours: 1.0
|
||||||
|
|
||||||
|
target:
|
||||||
|
config: /mnt/2tbhdd/coolrl-lost-cities-artifacts/league/2026-07-05_052325_jax-ppo-league-v1/main_ppo_config.json
|
||||||
|
checkpoint: /mnt/2tbhdd/coolrl-lost-cities-artifacts/league/2026-07-05_052325_jax-ppo-league-v1/snapshots/cycle_01_update_000500
|
||||||
|
|
||||||
|
gate1:
|
||||||
|
games: 2
|
||||||
|
batch_games: 2
|
||||||
|
delta_games: 2
|
||||||
|
delta_target_events: 2
|
||||||
|
delta_pairs: 2
|
||||||
|
delta_batch_events: 1
|
||||||
|
|
||||||
|
gate2:
|
||||||
|
eval_games: 2
|
||||||
|
pass_threshold: 0.55
|
||||||
|
exploiters:
|
||||||
|
- name: long_random_smoke
|
||||||
|
config: configs/jax_ppo/gates-1-2-exploiter-smoke.yaml
|
||||||
|
|
||||||
|
repair:
|
||||||
|
max_cycles: 1
|
||||||
|
league_template: configs/jax_ppo/league-smoke.yaml
|
||||||
|
experiment_name: jax-ppo-gates-1-2-repair-smoke
|
||||||
|
artifact_subdir: gate2c
|
||||||
|
evaluation_games: 2
|
||||||
|
evaluation_batch_games: 2
|
||||||
|
guard_expert_ci_low: -1000.0
|
||||||
|
guard_max_steps_rate: 1.0
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
run:
|
||||||
|
artifact_root: /mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2
|
||||||
|
report_path: docs/reports/gates-1-2-2026-07-05.md
|
||||||
|
summary_path: docs/reports/gates-1-2-2026-07-05-summary.jsonl
|
||||||
|
shuffle_bank_seed: 20260704
|
||||||
|
gpu_budget_hours: 8.0
|
||||||
|
|
||||||
|
target:
|
||||||
|
config: /mnt/2tbhdd/coolrl-lost-cities-artifacts/league/2026-07-05_052325_jax-ppo-league-v1/main_ppo_config.json
|
||||||
|
checkpoint: /mnt/2tbhdd/coolrl-lost-cities-artifacts/league/2026-07-05_052325_jax-ppo-league-v1/snapshots/cycle_01_update_000500
|
||||||
|
|
||||||
|
gate1:
|
||||||
|
games: 2000
|
||||||
|
batch_games: 8192
|
||||||
|
delta_games: 200
|
||||||
|
delta_target_events: 500
|
||||||
|
delta_pairs: 64
|
||||||
|
delta_batch_events: 16
|
||||||
|
|
||||||
|
gate2:
|
||||||
|
eval_games: 2000
|
||||||
|
pass_threshold: 0.55
|
||||||
|
exploiters:
|
||||||
|
- name: long_random
|
||||||
|
config: configs/jax_ppo/gates-1-2-exploiter-long-random.yaml
|
||||||
|
notes: random init + shaping anneal, extended budget
|
||||||
|
- name: warmstart_gate3
|
||||||
|
config: configs/jax_ppo/gates-1-2-exploiter-warmstart.yaml
|
||||||
|
resume: /mnt/2tbhdd/coolrl-lost-cities-artifacts/ladder-v2/2026-07-05_013223_jax-ppo-ladder-v2-expert/latest
|
||||||
|
notes: ladder v2 gate-3 warm start, shaping disabled
|
||||||
|
- name: replay_exploiter
|
||||||
|
config: configs/jax_ppo/gates-1-2-exploiter-replay.yaml
|
||||||
|
resume: /mnt/2tbhdd/coolrl-lost-cities-artifacts/league/2026-07-05_052325_jax-ppo-league-v1/exploiters/2026-07-05_060727_jax-ppo-league-v1-cycle-1-exploiter/latest
|
||||||
|
notes: league v1 exploiter warm start, shaping disabled
|
||||||
|
|
||||||
|
repair:
|
||||||
|
max_cycles: 3
|
||||||
|
league_template: configs/jax_ppo/league-v1.yaml
|
||||||
|
experiment_name: jax-ppo-gates-1-2-repair
|
||||||
|
artifact_subdir: gate2c
|
||||||
|
evaluation_games: 2000
|
||||||
|
evaluation_batch_games: 8192
|
||||||
|
guard_expert_ci_low: 0.0
|
||||||
|
guard_max_steps_rate: 0.02
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{"event": "gate1_tournament", "games": 4000, "json": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate1/expert_cap2_vs_expert_cap3.json", "learner": "expert_cap2", "losses": 2102.0, "max_steps_rate": 0.0, "mean_game_length": 46.549, "mean_score_diff": -1.89325, "opened_colors_per_game": 1.77925, "opponent": "expert_cap3", "play_action_rate": 0.2414775169804832, "positive_expeditions_per_game": 0.94175, "score_diff_ci95_high": -1.4203123965597364, "score_diff_ci95_low": -2.366187603440264, "score_diff_std": 15.261096936571331, "ties": 132.0, "wilson_high": 0.45693730157215046, "wilson_low": 0.42617495329274474, "win_rate": 0.4415, "wins": 1766.0}
|
||||||
|
{"event": "gate1_tournament", "games": 4000, "json": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate1/expert_cap2_vs_expert_capN.json", "learner": "expert_cap2", "losses": 2092.0, "max_steps_rate": 0.0, "mean_game_length": 46.354, "mean_score_diff": -1.88075, "opened_colors_per_game": 1.7815, "opponent": "expert_capN", "play_action_rate": 0.24223387949830538, "positive_expeditions_per_game": 0.93725, "score_diff_ci95_high": -1.4070318876291175, "score_diff_ci95_low": -2.3544681123708826, "score_diff_std": 15.286282970338549, "ties": 130.0, "wilson_high": 0.45994507591745637, "wilson_low": 0.4291614222877006, "win_rate": 0.4445, "wins": 1778.0}
|
||||||
|
{"event": "gate1_tournament", "games": 4000, "json": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate1/expert_cap3_vs_expert_capN.json", "learner": "expert_cap3", "losses": 1927.0, "max_steps_rate": 0.0, "mean_game_length": 45.35975, "mean_score_diff": 0.0285, "opened_colors_per_game": 2.21525, "opponent": "expert_capN", "play_action_rate": 0.3101634934459303, "positive_expeditions_per_game": 1.20625, "score_diff_ci95_high": 0.5258735279417411, "score_diff_ci95_low": -0.46887352794174114, "score_diff_std": 16.04961324366783, "ties": 137.0, "wilson_high": 0.49949486790031544, "wilson_low": 0.4685358342849551, "win_rate": 0.484, "wins": 1936.0}
|
||||||
|
{"event": "gate1_vs_league", "games": 4000, "json": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate1/expert_cap2_vs_league_v1_update_500.json", "learner": "expert_cap2", "losses": 2871.0, "max_steps_rate": 0.00025, "mean_game_length": 55.372, "mean_score_diff": -20.88625, "opened_colors_per_game": 1.9735, "opponent": "league_v1_update_500", "play_action_rate": 0.22526015834941476, "positive_expeditions_per_game": 1.09725, "score_diff_ci95_high": -19.787867065349186, "score_diff_ci95_low": -21.984632934650815, "score_diff_std": 35.44342491958145, "ties": 39.0, "wilson_high": 0.2865114339331819, "wilson_low": 0.2589251127636324, "win_rate": 0.2725, "wins": 1090.0}
|
||||||
|
{"event": "gate1_vs_league", "games": 4000, "json": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate1/expert_cap3_vs_league_v1_update_500.json", "learner": "expert_cap3", "losses": 2590.0, "max_steps_rate": 0.0, "mean_game_length": 53.52525, "mean_score_diff": -14.35125, "opened_colors_per_game": 2.7385, "opponent": "league_v1_update_500", "play_action_rate": 0.320897958422324, "positive_expeditions_per_game": 1.52675, "score_diff_ci95_high": -13.256641796659636, "score_diff_ci95_low": -15.445858203340364, "score_diff_std": 35.32161912528796, "ties": 50.0, "wilson_high": 0.3548273870268761, "wilson_low": 0.32547963482582853, "win_rate": 0.34, "wins": 1360.0}
|
||||||
|
{"event": "gate1_vs_league", "games": 4000, "json": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate1/expert_capN_vs_league_v1_update_500.json", "learner": "expert_capN", "losses": 2585.0, "max_steps_rate": 0.0, "mean_game_length": 53.29175, "mean_score_diff": -13.967, "opened_colors_per_game": 3.004, "opponent": "league_v1_update_500", "play_action_rate": 0.3410701746172932, "positive_expeditions_per_game": 1.56475, "score_diff_ci95_high": -12.879677994093045, "score_diff_ci95_low": -15.054322005906956, "score_diff_std": 35.086502770569304, "ties": 49.0, "wilson_high": 0.3563415432992672, "wilson_low": 0.3269626002235683, "win_rate": 0.3415, "wins": 1366.0}
|
||||||
|
{"ci95_high": 0.3559042062015777, "ci95_low": -0.32834170620157765, "deltas_npy": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate1/delta_open_deltas.npy", "event": "gate1_delta_open", "histogram": {"counts": [107, 1643, 5209, 7192, 10627, 5447, 1662, 113], "edges": [-200.0, -100.0, -50.0, -20.0, 0.0, 20.0, 50.0, 100.0, 200.0]}, "histogram_png": "docs/reports/gates-1-2-delta-open-hist.png", "judgment": "near_zero", "mean_delta": 0.01378125, "pairs": 64, "quantiles": {"max": 149.0, "min": -167.0, "p05": -52.0, "p25": -17.0, "p50": 0.0, "p75": 17.0, "p95": 51.0}, "samples": 32000, "states": 500, "std_delta": 31.225479356323433}
|
||||||
|
{"checkpoint": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/exploiters/2026-07-05_094311_gates-1-2-long-random-exploiter/latest", "event": "gate2_exploiter", "exploiter": "long_random", "games": 4000, "json": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/exploiters/2026-07-05_094311_gates-1-2-long-random-exploiter/eval_vs_league_v1_update_500_duplicate.json", "losses": 1610.0, "max_steps_rate": 0.0, "mean_game_length": 50.74375, "mean_score_diff": 10.95125, "notes": "random init + shaping anneal, extended budget", "opened_colors_per_game": 4.99575, "play_action_rate": 0.8010700772505124, "positive_expeditions_per_game": 2.53625, "resume": null, "score_diff_ci95_high": 12.423541316332845, "score_diff_ci95_low": 9.478958683667155, "score_diff_std": 47.50897440589277, "ties": 42.0, "train_dir": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/exploiters/2026-07-05_094311_gates-1-2-long-random-exploiter", "wilson_high": 0.6021679468487495, "wilson_low": 0.5716651100188423, "win_rate": 0.587, "wins": 2348.0}
|
||||||
|
{"checkpoint": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/exploiters/2026-07-05_105902_gates-1-2-warmstart-gate3-exploiter/latest", "event": "gate2_exploiter", "exploiter": "warmstart_gate3", "games": 4000, "json": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/exploiters/2026-07-05_105902_gates-1-2-warmstart-gate3-exploiter/eval_vs_league_v1_update_500_duplicate.json", "losses": 1605.0, "max_steps_rate": 0.0, "mean_game_length": 50.8715, "mean_score_diff": 11.38075, "notes": "ladder v2 gate-3 warm start, shaping disabled", "opened_colors_per_game": 4.9945, "play_action_rate": 0.798003736847281, "positive_expeditions_per_game": 2.5195, "resume": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/ladder-v2/2026-07-05_013223_jax-ppo-ladder-v2-expert/latest", "score_diff_ci95_high": 12.872234578510747, "score_diff_ci95_low": 9.889265421489254, "score_diff_std": 48.128316645747006, "ties": 35.0, "train_dir": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/exploiters/2026-07-05_105902_gates-1-2-warmstart-gate3-exploiter", "wilson_high": 0.6051483732088389, "wilson_low": 0.5746789269990148, "win_rate": 0.59, "wins": 2360.0}
|
||||||
|
{"checkpoint": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/exploiters/2026-07-05_115602_gates-1-2-replay-exploiter/latest", "event": "gate2_exploiter", "exploiter": "replay_exploiter", "games": 4000, "json": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/exploiters/2026-07-05_115602_gates-1-2-replay-exploiter/eval_vs_league_v1_update_500_duplicate.json", "losses": 1638.0, "max_steps_rate": 0.0, "mean_game_length": 51.4305, "mean_score_diff": 10.42525, "notes": "league v1 exploiter warm start, shaping disabled", "opened_colors_per_game": 4.99775, "play_action_rate": 0.7904596181514173, "positive_expeditions_per_game": 2.54225, "resume": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/league/2026-07-05_052325_jax-ppo-league-v1/exploiters/2026-07-05_060727_jax-ppo-league-v1-cycle-1-exploiter/latest", "score_diff_ci95_high": 11.913719629678091, "score_diff_ci95_low": 8.936780370321909, "score_diff_std": 48.0310280688623, "ties": 34.0, "train_dir": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/exploiters/2026-07-05_115602_gates-1-2-replay-exploiter", "wilson_high": 0.5971992743148633, "wilson_low": 0.5666433769856256, "win_rate": 0.582, "wins": 2328.0}
|
||||||
|
{"event": "gate2_judgment", "passed": false, "threshold": 0.55, "worst_exploiter": "warmstart_gate3", "worst_win_rate": 0.59}
|
||||||
|
{"elapsed_seconds": 11425.08623591601, "event": "gates_complete", "run_dir": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2"}
|
||||||
|
{"cycle": 1, "event": "gate2c_league_cycle", "league_config": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/cycle_01/league_config.yaml", "league_run_dir": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/league/2026-07-05_125709_jax-ppo-gates-1-2-repair-c01", "target_checkpoint": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/league/2026-07-05_125709_jax-ppo-gates-1-2-repair-c01/snapshots/cycle_01_update_000500", "target_config": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/league/2026-07-05_125709_jax-ppo-gates-1-2-repair-c01/main_ppo_config.json", "worst_protocol": "warmstart_gate3"}
|
||||||
|
{"cycle": 1, "event": "gate2c_guard_expert", "games": 4000, "json": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/cycle_01/guard_vs_heuristic_expert.json", "losses": 1188.0, "max_steps_rate": 0.0, "mean_game_length": 54.61975, "mean_score_diff": 19.654, "opened_colors_per_game": 4.7015, "passed": true, "play_action_rate": 0.6708126417051431, "positive_expeditions_per_game": 2.1505, "score_diff_ci95_high": 20.81558482366198, "score_diff_ci95_low": 18.49241517633802, "score_diff_std": 37.482869759149246, "target_checkpoint": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/league/2026-07-05_125709_jax-ppo-gates-1-2-repair-c01/snapshots/cycle_01_update_000500", "target_config": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/league/2026-07-05_125709_jax-ppo-gates-1-2-repair-c01/main_ppo_config.json", "ties": 41.0, "wilson_high": 0.7068566468456556, "wilson_low": 0.6782734877661645, "win_rate": 0.69275, "wins": 2771.0}
|
||||||
|
{"checkpoint": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/cycle_01/battery/2026-07-05_143807_gates-1-2-long-random-exploiter/latest", "cycle": 1, "event": "gate2c_exploiter", "exploiter": "long_random", "games": 4000, "json": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/cycle_01/battery/2026-07-05_143807_gates-1-2-long-random-exploiter/eval_vs_repair_cycle_01_duplicate.json", "losses": 1810.0, "max_steps_rate": 0.0, "mean_game_length": 51.4185, "mean_score_diff": 6.27925, "notes": "random init + shaping anneal, extended budget", "opened_colors_per_game": 4.99425, "play_action_rate": 0.7816023796562719, "positive_expeditions_per_game": 2.52, "resume": null, "score_diff_ci95_high": 7.76660187726116, "score_diff_ci95_low": 4.79189812273884, "score_diff_std": 47.99495961530356, "target_checkpoint": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/league/2026-07-05_125709_jax-ppo-gates-1-2-repair-c01/snapshots/cycle_01_update_000500", "target_config": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/league/2026-07-05_125709_jax-ppo-gates-1-2-repair-c01/main_ppo_config.json", "target_name": "repair_cycle_01", "ties": 34.0, "train_dir": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/cycle_01/battery/2026-07-05_143807_gates-1-2-long-random-exploiter", "wilson_high": 0.5544028831760525, "wilson_low": 0.5235222802473508, "win_rate": 0.539, "wins": 2156.0}
|
||||||
|
{"checkpoint": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/cycle_01/battery/2026-07-05_155430_gates-1-2-warmstart-gate3-exploiter/latest", "cycle": 1, "event": "gate2c_exploiter", "exploiter": "warmstart_gate3", "games": 4000, "json": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/cycle_01/battery/2026-07-05_155430_gates-1-2-warmstart-gate3-exploiter/eval_vs_repair_cycle_01_duplicate.json", "losses": 1763.0, "max_steps_rate": 0.0, "mean_game_length": 50.434, "mean_score_diff": 7.0285, "notes": "ladder v2 gate-3 warm start, shaping disabled", "opened_colors_per_game": 4.9935, "play_action_rate": 0.8006960073764884, "positive_expeditions_per_game": 2.4845, "resume": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/ladder-v2/2026-07-05_013223_jax-ppo-ladder-v2-expert/latest", "score_diff_ci95_high": 8.490821414519859, "score_diff_ci95_low": 5.5661785854801415, "score_diff_std": 47.18725831288327, "target_checkpoint": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/league/2026-07-05_125709_jax-ppo-gates-1-2-repair-c01/snapshots/cycle_01_update_000500", "target_config": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/league/2026-07-05_125709_jax-ppo-gates-1-2-repair-c01/main_ppo_config.json", "target_name": "repair_cycle_01", "ties": 41.0, "train_dir": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/cycle_01/battery/2026-07-05_155430_gates-1-2-warmstart-gate3-exploiter", "wilson_high": 0.5643659496573598, "wilson_low": 0.5335400249002497, "win_rate": 0.549, "wins": 2196.0}
|
||||||
|
{"checkpoint": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/cycle_01/battery/2026-07-05_165151_gates-1-2-replay-exploiter/latest", "cycle": 1, "event": "gate2c_exploiter", "exploiter": "replay_exploiter", "games": 4000, "json": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/cycle_01/battery/2026-07-05_165151_gates-1-2-replay-exploiter/eval_vs_repair_cycle_01_duplicate.json", "losses": 1798.0, "max_steps_rate": 0.0, "mean_game_length": 51.116, "mean_score_diff": 6.10225, "notes": "league v1 exploiter warm start, shaping disabled", "opened_colors_per_game": 4.99425, "play_action_rate": 0.7845902569268536, "positive_expeditions_per_game": 2.50025, "resume": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/league/2026-07-05_052325_jax-ppo-league-v1/exploiters/2026-07-05_060727_jax-ppo-league-v1-cycle-1-exploiter/latest", "score_diff_ci95_high": 7.583110013023179, "score_diff_ci95_low": 4.62138998697682, "score_diff_std": 47.785475385853, "target_checkpoint": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/league/2026-07-05_125709_jax-ppo-gates-1-2-repair-c01/snapshots/cycle_01_update_000500", "target_config": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/league/2026-07-05_125709_jax-ppo-gates-1-2-repair-c01/main_ppo_config.json", "target_name": "repair_cycle_01", "ties": 45.0, "train_dir": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/cycle_01/battery/2026-07-05_165151_gates-1-2-replay-exploiter", "wilson_high": 0.5546520360903574, "wilson_low": 0.523772647611401, "win_rate": 0.53925, "wins": 2157.0}
|
||||||
|
{"cycle": 1, "event": "gate2c_judgment", "passed": true, "threshold": 0.55, "worst_exploiter": "warmstart_gate3", "worst_win_rate": 0.549}
|
||||||
|
{"elapsed_seconds_total": 28945.184503759025, "event": "gates_repair_complete", "run_dir": "/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2"}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
# Gates 1-2 Report - 2026-07-05
|
||||||
|
|
||||||
|
**Run dir:** `/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2`.
|
||||||
|
**Target:** `/mnt/2tbhdd/coolrl-lost-cities-artifacts/league/2026-07-05_052325_jax-ppo-league-v1/snapshots/cycle_01_update_000500`.
|
||||||
|
|
||||||
|
## Gate 1A - Policy Class Tournament
|
||||||
|
|
||||||
|
| Learner | Opponent | Win rate | Mean diff | CI low | Opened colors | Max-step |
|
||||||
|
| --- | --- | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
| `expert_cap2` | `expert_cap3` | 0.4415 | -1.8933 | -2.3662 | 1.7792 | 0.0000 |
|
||||||
|
| `expert_cap2` | `expert_capN` | 0.4445 | -1.8807 | -2.3545 | 1.7815 | 0.0000 |
|
||||||
|
| `expert_cap3` | `expert_capN` | 0.4840 | +0.0285 | -0.4689 | 2.2153 | 0.0000 |
|
||||||
|
|
||||||
|
## Gate 1A - Variants vs League v1
|
||||||
|
|
||||||
|
| Learner | Opponent | Win rate | Mean diff | CI low | Opened colors | Max-step |
|
||||||
|
| --- | --- | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
| `expert_cap2` | `league_v1_update_500` | 0.2725 | -20.8863 | -21.9846 | 1.9735 | 0.0003 |
|
||||||
|
| `expert_cap3` | `league_v1_update_500` | 0.3400 | -14.3513 | -15.4459 | 2.7385 | 0.0000 |
|
||||||
|
| `expert_capN` | `league_v1_update_500` | 0.3415 | -13.9670 | -15.0543 | 3.0040 | 0.0000 |
|
||||||
|
|
||||||
|
## Gate 1B - Delta Open Audit
|
||||||
|
|
||||||
|
- States: 500
|
||||||
|
- Paired samples: 32000
|
||||||
|
- Mean delta: +0.0138
|
||||||
|
- CI95: [-0.3283, +0.3559]
|
||||||
|
- Judgment: `near_zero`
|
||||||
|
- Histogram: `docs/reports/gates-1-2-delta-open-hist.png`
|
||||||
|
|
||||||
|
## Gate 1C - Selectivity Judgment
|
||||||
|
|
||||||
|
통념 기각/미결: capN은 집중 변형보다 유의하게 나쁘지 않고, 리그 정책의 4번째+ 오픈 delta는 0 근처다. selectivity는 현재 주요 성능 병목으로 보이지 않는다.
|
||||||
|
|
||||||
|
## Gate 2A - Strengthened Exploiter Battery
|
||||||
|
|
||||||
|
| Exploiter | Win rate | Mean diff | CI low | Opened colors | Max-step | Run |
|
||||||
|
| --- | ---: | ---: | ---: | ---: | ---: | --- |
|
||||||
|
| `long_random` | 0.5870 | +10.9512 | +9.4790 | 4.9958 | 0.0000 | `/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/exploiters/2026-07-05_094311_gates-1-2-long-random-exploiter` |
|
||||||
|
| `warmstart_gate3` | 0.5900 | +11.3808 | +9.8893 | 4.9945 | 0.0000 | `/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/exploiters/2026-07-05_105902_gates-1-2-warmstart-gate3-exploiter` |
|
||||||
|
| `replay_exploiter` | 0.5820 | +10.4253 | +8.9368 | 4.9977 | 0.0000 | `/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/exploiters/2026-07-05_115602_gates-1-2-replay-exploiter` |
|
||||||
|
|
||||||
|
## Gate 2B - Robustness Judgment
|
||||||
|
|
||||||
|
보수 필요: worst exploiter `warmstart_gate3` win rate 0.5900 vs threshold 0.5500.
|
||||||
|
|
||||||
|
## Gate 2C - Conditional Repair League
|
||||||
|
|
||||||
|
| Cycle | Worst protocol used | Guard pass | Battery worst | Passed | Checkpoint |
|
||||||
|
| ---: | --- | ---: | ---: | ---: | --- |
|
||||||
|
| 1 | `warmstart_gate3` | True | 0.5490 | True | `/mnt/2tbhdd/coolrl-lost-cities-artifacts/gates-1-2/2026-07-05_094238_gates-1-2/gate2c/league/2026-07-05_125709_jax-ppo-gates-1-2-repair-c01/snapshots/cycle_01_update_000500` |
|
||||||
|
|
||||||
|
| Cycle | Exploiter | Win rate | Mean diff | CI low | Opened colors | Max-step |
|
||||||
|
| ---: | --- | ---: | ---: | ---: | ---: | ---: |
|
||||||
|
| 1 | `long_random` | 0.5390 | +6.2793 | +4.7919 | 4.9943 | 0.0000 |
|
||||||
|
| 1 | `warmstart_gate3` | 0.5490 | +7.0285 | +5.5662 | 4.9935 | 0.0000 |
|
||||||
|
| 1 | `replay_exploiter` | 0.5393 | +6.1022 | +4.6214 | 4.9943 | 0.0000 |
|
||||||
|
|
||||||
|
## Human Play Recommendation
|
||||||
|
|
||||||
|
조건부 예: 강화 exploiter 관문은 통과했다. 다만 selectivity 관문이 미결/부분 지지이면 인간 대전은 실력 인증이 아니라 행동 양식 진단으로 시작해야 한다.
|
||||||
|
|
||||||
|
## Decisions
|
||||||
|
|
||||||
|
- Existing `heuristic_expert` remains unchanged. The cap variants add only a hard `max_open_colors` gate around new-color openings.
|
||||||
|
- `expert_capN` means no hard cap; EV thresholds and the existing soft concentration penalties are retained.
|
||||||
|
- Warm-started exploiters use shaping coefficient 0 to measure target-specific exploitation without reintroducing early shaping rewards.
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
File diff suppressed because it is too large
Load Diff
@@ -72,6 +72,7 @@ class LeagueConfig:
|
|||||||
evaluation_shuffle_bank_seed: int = 20260704
|
evaluation_shuffle_bank_seed: int = 20260704
|
||||||
recent_snapshot_evals: int = 3
|
recent_snapshot_evals: int = 3
|
||||||
exploiter_config: str = "configs/jax_ppo/ladder-v2-exploiter.yaml"
|
exploiter_config: str = "configs/jax_ppo/ladder-v2-exploiter.yaml"
|
||||||
|
exploiter_resume: str | None = None
|
||||||
exploiter_updates: int = 250
|
exploiter_updates: int = 250
|
||||||
expert_guard_ci_low: float = 0.0
|
expert_guard_ci_low: float = 0.0
|
||||||
max_steps_guard: float = 0.02
|
max_steps_guard: float = 0.02
|
||||||
@@ -115,6 +116,7 @@ def load_league_config(path: str | Path) -> LeagueConfig:
|
|||||||
evaluation_shuffle_bank_seed=evaluation.get("shuffle_bank_seed", 20260704),
|
evaluation_shuffle_bank_seed=evaluation.get("shuffle_bank_seed", 20260704),
|
||||||
recent_snapshot_evals=evaluation.get("recent_snapshot_evals", 3),
|
recent_snapshot_evals=evaluation.get("recent_snapshot_evals", 3),
|
||||||
exploiter_config=exploiter.get("config", "configs/jax_ppo/ladder-v2-exploiter.yaml"),
|
exploiter_config=exploiter.get("config", "configs/jax_ppo/ladder-v2-exploiter.yaml"),
|
||||||
|
exploiter_resume=exploiter.get("resume"),
|
||||||
exploiter_updates=exploiter.get("updates", 250),
|
exploiter_updates=exploiter.get("updates", 250),
|
||||||
expert_guard_ci_low=guards.get("expert_ci_low", 0.0),
|
expert_guard_ci_low=guards.get("expert_ci_low", 0.0),
|
||||||
max_steps_guard=guards.get("max_steps_rate", 0.02),
|
max_steps_guard=guards.get("max_steps_rate", 0.02),
|
||||||
@@ -392,6 +394,7 @@ def run_exploiter_cycle(
|
|||||||
exploiter_cfg,
|
exploiter_cfg,
|
||||||
ppo_cfg,
|
ppo_cfg,
|
||||||
target.checkpoint or cfg.warm_start_checkpoint,
|
target.checkpoint or cfg.warm_start_checkpoint,
|
||||||
|
resume=cfg.exploiter_resume,
|
||||||
)
|
)
|
||||||
result = evaluate_checkpoint_match(
|
result = evaluate_checkpoint_match(
|
||||||
exploiter_cfg,
|
exploiter_cfg,
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ ACTION_DRAW_SOURCE = ACTION_IDS % 6
|
|||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class HeuristicExpertConfig:
|
class HeuristicExpertConfig:
|
||||||
|
max_open_colors: int | None = None
|
||||||
target_open_colors: int = 3
|
target_open_colors: int = 3
|
||||||
fourth_color_margin: float = 38.0
|
fourth_color_margin: float = 38.0
|
||||||
extra_color_margin: float = 58.0
|
extra_color_margin: float = 58.0
|
||||||
@@ -64,7 +65,7 @@ class HeuristicExpertConfig:
|
|||||||
|
|
||||||
|
|
||||||
def policy_by_name(name: str) -> ActionPolicy:
|
def policy_by_name(name: str) -> ActionPolicy:
|
||||||
normalized = name.replace("-", "_")
|
normalized = name.replace("-", "_").lower()
|
||||||
if normalized == "discard_only":
|
if normalized == "discard_only":
|
||||||
return discard_only_action
|
return discard_only_action
|
||||||
if normalized == "heuristic_balanced":
|
if normalized == "heuristic_balanced":
|
||||||
@@ -73,6 +74,12 @@ def policy_by_name(name: str) -> ActionPolicy:
|
|||||||
return heuristic_cautious_action
|
return heuristic_cautious_action
|
||||||
if normalized == "heuristic_expert":
|
if normalized == "heuristic_expert":
|
||||||
return heuristic_expert_action
|
return heuristic_expert_action
|
||||||
|
if normalized in {"expert_cap2", "heuristic_expert_cap2"}:
|
||||||
|
return make_heuristic_expert_policy(HeuristicExpertConfig(max_open_colors=2))
|
||||||
|
if normalized in {"expert_cap3", "heuristic_expert_cap3"}:
|
||||||
|
return make_heuristic_expert_policy(HeuristicExpertConfig(max_open_colors=3))
|
||||||
|
if normalized in {"expert_capn", "expert_cap_n", "heuristic_expert_capn"}:
|
||||||
|
return make_heuristic_expert_policy(HeuristicExpertConfig(max_open_colors=None))
|
||||||
msg = f"unknown opponent policy: {name}"
|
msg = f"unknown opponent policy: {name}"
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
@@ -197,6 +204,11 @@ def _heuristic_expert_action(
|
|||||||
|
|
||||||
progress = (state.draw_ptr - 16).astype(jnp.float32) / DECK_DRAWS
|
progress = (state.draw_ptr - 16).astype(jnp.float32) / DECK_DRAWS
|
||||||
active_colors = jnp.sum(state.col_len[player] > 0).astype(jnp.float32)
|
active_colors = jnp.sum(state.col_len[player] > 0).astype(jnp.float32)
|
||||||
|
hard_cap_allows_new_color = (
|
||||||
|
jnp.asarray(True)
|
||||||
|
if cfg.max_open_colors is None
|
||||||
|
else active_colors < jnp.asarray(cfg.max_open_colors, dtype=jnp.float32)
|
||||||
|
)
|
||||||
open_threshold = (
|
open_threshold = (
|
||||||
cfg.base_open_threshold
|
cfg.base_open_threshold
|
||||||
+ progress * cfg.late_open_threshold
|
+ progress * cfg.late_open_threshold
|
||||||
@@ -259,11 +271,14 @@ def _heuristic_expert_action(
|
|||||||
defensive_sacrifice = (
|
defensive_sacrifice = (
|
||||||
(discard_danger > 22.0)
|
(discard_danger > 22.0)
|
||||||
& ~own_open
|
& ~own_open
|
||||||
|
& hard_cap_allows_new_color
|
||||||
& (active_colors < cfg.target_open_colors)
|
& (active_colors < cfg.target_open_colors)
|
||||||
& (rank_i <= 5)
|
& (rank_i <= 5)
|
||||||
& (color_open_value > -18.0)
|
& (color_open_value > -18.0)
|
||||||
)
|
)
|
||||||
new_color_allowed = jnp.where(is_handshake, hs_open_allowed, open_allowed)
|
new_color_allowed = (
|
||||||
|
jnp.where(is_handshake, hs_open_allowed, open_allowed) & hard_cap_allows_new_color
|
||||||
|
)
|
||||||
play_score = jnp.where(
|
play_score = jnp.where(
|
||||||
own_open,
|
own_open,
|
||||||
jnp.where(
|
jnp.where(
|
||||||
|
|||||||
@@ -1290,10 +1290,18 @@ def cli_main(argv: list[str] | None = None) -> None:
|
|||||||
league_run_parser = league_sub.add_parser("run")
|
league_run_parser = league_sub.add_parser("run")
|
||||||
league_run_parser.add_argument("--config", required=True)
|
league_run_parser.add_argument("--config", required=True)
|
||||||
|
|
||||||
|
gates_parser = sub.add_parser("gates")
|
||||||
|
gates_sub = gates_parser.add_subparsers(dest="gates_command", required=True)
|
||||||
|
gates_run_parser = gates_sub.add_parser("run")
|
||||||
|
gates_run_parser.add_argument("--config", required=True)
|
||||||
|
gates_repair_parser = gates_sub.add_parser("repair")
|
||||||
|
gates_repair_parser.add_argument("--config", required=True)
|
||||||
|
gates_repair_parser.add_argument("--run-dir", required=True)
|
||||||
|
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
cfg = (
|
cfg = (
|
||||||
load_config(args.config, overrides=parse_overrides(args.set))
|
load_config(args.config, overrides=parse_overrides(args.set))
|
||||||
if hasattr(args, "config") and args.command != "league"
|
if hasattr(args, "config") and args.command not in {"league", "gates"}
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
if args.command == "rollout-smoke":
|
if args.command == "rollout-smoke":
|
||||||
@@ -1378,6 +1386,17 @@ def cli_main(argv: list[str] | None = None) -> None:
|
|||||||
|
|
||||||
run_dir = run_league(args.config)
|
run_dir = run_league(args.config)
|
||||||
print(run_dir)
|
print(run_dir)
|
||||||
|
elif args.command == "gates":
|
||||||
|
if args.gates_command == "run":
|
||||||
|
from lost_cities_jax.gates import run_gates
|
||||||
|
|
||||||
|
run_dir = run_gates(args.config)
|
||||||
|
print(run_dir)
|
||||||
|
elif args.gates_command == "repair":
|
||||||
|
from lost_cities_jax.gates import repair_gates
|
||||||
|
|
||||||
|
run_dir = repair_gates(args.config, args.run_dir)
|
||||||
|
print(run_dir)
|
||||||
|
|
||||||
|
|
||||||
def _create_run_dir(cfg: JaxPPOConfig) -> Path:
|
def _create_run_dir(cfg: JaxPPOConfig) -> Path:
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from lost_cities_jax.gates import load_gates_config
|
||||||
|
|
||||||
|
|
||||||
|
def test_gates_config_loads_repair_settings():
|
||||||
|
cfg = load_gates_config("configs/jax_ppo/gates-1-2.yaml")
|
||||||
|
assert cfg.gate2_pass_threshold == 0.55
|
||||||
|
assert len(cfg.exploiters) == 3
|
||||||
|
assert cfg.repair.max_cycles == 3
|
||||||
|
assert cfg.repair.league_template == "configs/jax_ppo/league-v1.yaml"
|
||||||
|
assert cfg.repair.evaluation_games == 2000
|
||||||
|
|
||||||
|
|
||||||
|
def test_gates_smoke_config_uses_smoke_repair_template():
|
||||||
|
cfg = load_gates_config("configs/jax_ppo/gates-1-2-smoke.yaml")
|
||||||
|
assert cfg.repair.max_cycles == 1
|
||||||
|
assert cfg.repair.league_template == "configs/jax_ppo/league-smoke.yaml"
|
||||||
|
assert cfg.repair.guard_max_steps_rate == 1.0
|
||||||
@@ -10,10 +10,12 @@ import pytest
|
|||||||
from lost_cities_jax import legal_action_mask, reset
|
from lost_cities_jax import legal_action_mask, reset
|
||||||
from lost_cities_jax.engine import current_hand_sorted, decode_action, reset_from_order
|
from lost_cities_jax.engine import current_hand_sorted, decode_action, reset_from_order
|
||||||
from lost_cities_jax.opponents import (
|
from lost_cities_jax.opponents import (
|
||||||
|
HeuristicExpertConfig,
|
||||||
discard_only_action,
|
discard_only_action,
|
||||||
heuristic_balanced_action,
|
heuristic_balanced_action,
|
||||||
heuristic_cautious_action,
|
heuristic_cautious_action,
|
||||||
heuristic_expert_action,
|
heuristic_expert_action,
|
||||||
|
make_heuristic_expert_policy,
|
||||||
)
|
)
|
||||||
from lost_cities_jax.ppo import (
|
from lost_cities_jax.ppo import (
|
||||||
JaxPPOConfig,
|
JaxPPOConfig,
|
||||||
@@ -178,6 +180,76 @@ def test_expert_avoids_discarding_immediately_useful_opponent_card():
|
|||||||
assert hand[hand_slot] != dangerous
|
assert hand[hand_slot] != dangerous
|
||||||
|
|
||||||
|
|
||||||
|
def test_expert_cap2_blocks_third_open_color():
|
||||||
|
state = _manual_state(
|
||||||
|
p0_hand=[
|
||||||
|
_hs_card(2),
|
||||||
|
_rank_card(2, 7),
|
||||||
|
_rank_card(2, 8),
|
||||||
|
_rank_card(2, 9),
|
||||||
|
_rank_card(2, 10),
|
||||||
|
_rank_card(3, 2),
|
||||||
|
_rank_card(3, 3),
|
||||||
|
_rank_card(4, 2),
|
||||||
|
],
|
||||||
|
p0_board=[_rank_card(0, 2), _rank_card(1, 2)],
|
||||||
|
to_move=0,
|
||||||
|
)
|
||||||
|
policy = make_heuristic_expert_policy(HeuristicExpertConfig(max_open_colors=2))
|
||||||
|
action = int(policy(state, jnp.int32(0), jax.random.PRNGKey(1)))
|
||||||
|
hand_slot, place_type, _ = [int(x) for x in decode_action(jnp.asarray(action))]
|
||||||
|
hand = [int(x) for x in current_hand_sorted(state, 0)]
|
||||||
|
opened_new_color = (
|
||||||
|
place_type == PLAY and state.col_len[0, hand[hand_slot] // CARDS_PER_COLOR] == 0
|
||||||
|
)
|
||||||
|
assert not bool(opened_new_color)
|
||||||
|
|
||||||
|
|
||||||
|
def test_expert_cap3_allows_third_but_blocks_fourth_open_color():
|
||||||
|
cap3 = make_heuristic_expert_policy(HeuristicExpertConfig(max_open_colors=3))
|
||||||
|
third_state = _manual_state(
|
||||||
|
p0_hand=[
|
||||||
|
_hs_card(2),
|
||||||
|
_rank_card(2, 7),
|
||||||
|
_rank_card(2, 8),
|
||||||
|
_rank_card(2, 9),
|
||||||
|
_rank_card(2, 10),
|
||||||
|
_rank_card(3, 2),
|
||||||
|
_rank_card(3, 3),
|
||||||
|
_rank_card(4, 2),
|
||||||
|
],
|
||||||
|
p0_board=[_rank_card(0, 2), _rank_card(1, 2)],
|
||||||
|
to_move=0,
|
||||||
|
)
|
||||||
|
action = int(cap3(third_state, jnp.int32(0), jax.random.PRNGKey(1)))
|
||||||
|
hand_slot, place_type, _ = [int(x) for x in decode_action(jnp.asarray(action))]
|
||||||
|
hand = [int(x) for x in current_hand_sorted(third_state, 0)]
|
||||||
|
assert place_type == PLAY
|
||||||
|
assert third_state.col_len[0, hand[hand_slot] // CARDS_PER_COLOR] == 0
|
||||||
|
|
||||||
|
fourth_state = _manual_state(
|
||||||
|
p0_hand=[
|
||||||
|
_hs_card(3),
|
||||||
|
_rank_card(3, 7),
|
||||||
|
_rank_card(3, 8),
|
||||||
|
_rank_card(3, 9),
|
||||||
|
_rank_card(3, 10),
|
||||||
|
_rank_card(4, 2),
|
||||||
|
_rank_card(4, 3),
|
||||||
|
_rank_card(4, 4),
|
||||||
|
],
|
||||||
|
p0_board=[_rank_card(0, 2), _rank_card(1, 2), _rank_card(2, 2)],
|
||||||
|
to_move=0,
|
||||||
|
)
|
||||||
|
action = int(cap3(fourth_state, jnp.int32(0), jax.random.PRNGKey(1)))
|
||||||
|
hand_slot, place_type, _ = [int(x) for x in decode_action(jnp.asarray(action))]
|
||||||
|
hand = [int(x) for x in current_hand_sorted(fourth_state, 0)]
|
||||||
|
opened_new_color = (
|
||||||
|
place_type == PLAY and fourth_state.col_len[0, hand[hand_slot] // CARDS_PER_COLOR] == 0
|
||||||
|
)
|
||||||
|
assert not bool(opened_new_color)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"policy_name", ["discard_only", "heuristic_balanced", "heuristic_cautious"]
|
"policy_name", ["discard_only", "heuristic_balanced", "heuristic_cautious"]
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user