Skip to content

[2/6] Fix transposition table with proper bounds#32

Open
luccabb wants to merge 2 commits intofeature/psqt-evaluation-performancefrom
feature/transposition-table-bounds
Open

[2/6] Fix transposition table with proper bounds#32
luccabb wants to merge 2 commits intofeature/psqt-evaluation-performancefrom
feature/transposition-table-bounds

Conversation

@luccabb
Copy link
Owner

@luccabb luccabb commented Jan 20, 2026

Summary

  • Add Bound enum (EXACT, LOWER_BOUND, UPPER_BOUND) for correct TT behavior
  • Use Zobrist hash as cache key instead of FEN string (faster)
  • Store bound type and depth with each cache entry
  • Fix null move pruning condition (was missing null_move parameter check)
  • Update parallel engines to use new cache format

Details

The transposition table now correctly stores and uses bound information:

  • EXACT: Score is within the alpha-beta window, can be used directly
  • LOWER_BOUND: Node failed high (score >= beta), true score is at least this value
  • UPPER_BOUND: Node failed low (score <= alpha), true score is at most this value

This prevents incorrect cutoffs and score usage that can cause search instability.

Parallel Engine Updates

All parallel engines (lazy_smp, l1p, l2p) updated to:

  • Use Zobrist hash for cache key lookup
  • Use context managers for proper Pool/Manager cleanup
  • Fix score negation in l1p (opponent perspective -> our perspective)

Test plan

  • All 64 unit tests pass
  • Verified correct bound handling in search

🤖 Generated with Claude Code

@luccabb luccabb force-pushed the feature/transposition-table-bounds branch from bb2ac9f to f833c45 Compare January 21, 2026 06:40
@luccabb luccabb force-pushed the feature/psqt-evaluation-performance branch from bca3f3e to d7df55a Compare January 21, 2026 06:43
@luccabb luccabb force-pushed the feature/transposition-table-bounds branch from f833c45 to 7a14812 Compare January 21, 2026 06:43
@luccabb luccabb changed the base branch from feature/psqt-evaluation-performance to master January 21, 2026 07:00
@luccabb luccabb changed the base branch from master to feature/psqt-evaluation-performance January 21, 2026 07:06
@luccabb luccabb changed the title [2/9] Fix transposition table with proper bounds [2/7] Fix transposition table with proper bounds Jan 21, 2026
@luccabb luccabb force-pushed the feature/psqt-evaluation-performance branch from d7df55a to e21928a Compare January 21, 2026 07:33
@luccabb luccabb force-pushed the feature/transposition-table-bounds branch from 4f7fad5 to 1c7b8d9 Compare January 21, 2026 07:33
@luccabb luccabb changed the title [2/7] Fix transposition table with proper bounds [2/6] Fix transposition table with proper bounds Jan 21, 2026
@github-actions
Copy link

🔬 Stockfish Benchmark Results

vs Stockfish Skill Level 3

Metric Wins Losses Draws Total Win %
Overall 10 88 2 100 10.0%
As White 7 42 1 50 14.0%
As Black 3 46 1 50 6.0%

Non-checkmate endings:

  • Draw by 3-fold repetition: 2

vs Stockfish Skill Level 4

Metric Wins Losses Draws Total Win %
Overall 7 91 2 100 7.0%
As White 3 46 1 50 6.0%
As Black 4 45 1 50 8.0%

Non-checkmate endings:

  • Draw by insufficient mating material: 1
  • Draw by 3-fold repetition: 1

vs Stockfish Skill Level 5

Metric Wins Losses Draws Total Win %
Overall 2 97 1 100 2.0%
As White 2 47 1 50 4.0%
As Black 0 50 0 50 0%

Non-checkmate endings:

  • Draw by 3-fold repetition: 1
Configuration
  • 5 chunks × 20 rounds × 3 skill levels = 300 total games
  • Each opening played with colors reversed (-repeat) for fairness
  • Moonfish: 60s per move
  • Stockfish: 60+5 time control

luccabb and others added 2 commits February 15, 2026 22:29
Implements correct transposition table behavior with bound types:

**Transposition Table Changes:**
- Add `Bound` enum: EXACT, LOWER_BOUND, UPPER_BOUND
- Use Zobrist hash as cache key (fast integer vs slow FEN string)
- Store bound type and depth with each cache entry
- Only use cached scores when depth is sufficient
- Properly handle bound types in lookups:
  - EXACT: use score directly
  - LOWER_BOUND: use if score >= beta (fail high)
  - UPPER_BOUND: use if score <= alpha (fail low)

**Null Move Pruning Fix:**
- Added missing `null_move` parameter check (was always trying null move)

**Parallel Engine Updates:**
- Update lazy_smp, l1p, l2p to use new zobrist hash cache key
- Add context managers for Pool/Manager (proper resource cleanup)
- Fix score negation in l1p (opponent perspective -> our perspective)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@luccabb luccabb force-pushed the feature/transposition-table-bounds branch from fbfac44 to 6912b81 Compare February 16, 2026 06:34
@luccabb luccabb force-pushed the feature/psqt-evaluation-performance branch from 42e6fc1 to 6c5f8af Compare February 16, 2026 06:34
@luccabb
Copy link
Owner Author

luccabb commented Feb 16, 2026

/run-nps-benchmark

@github-actions
Copy link

⚡ NPS Benchmark Results

Metric Value
Depth 5
Positions 48
Total nodes 25043687
Total time 2651.28s
Nodes/second 9445

Node count is the primary signal — it's deterministic and catches search behavior changes. If the node count changes, the PR changed search behavior. NPS is informational only (CI runner performance varies).

Per-position breakdown
Position  1/48: nodes=208940     time=17.67s  nps=11826
Position  2/48: nodes=1105550    time=108.17s  nps=10220
Position  3/48: nodes=19218      time=1.46s  nps=13201
Position  4/48: nodes=1317286    time=151.81s  nps=8676
Position  5/48: nodes=159788     time=19.69s  nps=8114
Position  6/48: nodes=463056     time=49.91s  nps=9278
Position  7/48: nodes=226632     time=27.77s  nps=8161
Position  8/48: nodes=671582     time=59.87s  nps=11217
Position  9/48: nodes=1911870    time=178.56s  nps=10707
Position 10/48: nodes=499511     time=54.74s  nps=9124
Position 11/48: nodes=644015     time=77.83s  nps=8274
Position 12/48: nodes=1140029    time=135.25s  nps=8428
Position 13/48: nodes=1175548    time=126.79s  nps=9271
Position 14/48: nodes=815258     time=86.78s  nps=9394
Position 15/48: nodes=974275     time=98.08s  nps=9933
Position 16/48: nodes=465441     time=41.33s  nps=11261
Position 17/48: nodes=13922      time=1.01s  nps=13777
Position 18/48: nodes=8801       time=0.45s  nps=19349
Position 19/48: nodes=37410      time=2.92s  nps=12816
Position 20/48: nodes=75661      time=4.89s  nps=15472
Position 21/48: nodes=54866      time=4.51s  nps=12152
Position 22/48: nodes=572        time=0.03s  nps=20067
Position 23/48: nodes=6634       time=0.42s  nps=15741
Position 24/48: nodes=50071      time=3.87s  nps=12941
Position 25/48: nodes=9154       time=0.57s  nps=16071
Position 26/48: nodes=75947      time=6.33s  nps=12003
Position 27/48: nodes=150123     time=13.07s  nps=11484
Position 28/48: nodes=552794     time=51.52s  nps=10728
Position 29/48: nodes=244226     time=26.51s  nps=9212
Position 30/48: nodes=2752       time=0.22s  nps=12696
Position 31/48: nodes=1655450    time=163.17s  nps=10145
Position 32/48: nodes=1276259    time=121.18s  nps=10532
Position 33/48: nodes=1901722    time=303.30s  nps=6270
Position 34/48: nodes=1357225    time=186.35s  nps=7283
Position 35/48: nodes=765752     time=70.38s  nps=10879
Position 36/48: nodes=2475889    time=232.70s  nps=10640
Position 37/48: nodes=1433122    time=123.89s  nps=11568
Position 38/48: nodes=10881      time=0.52s  nps=21021
Position 39/48: nodes=8814       time=0.32s  nps=27770
Position 40/48: nodes=22399      time=0.44s  nps=51445
Position 41/48: nodes=29056      time=2.09s  nps=13899
Position 42/48: nodes=78302      time=5.63s  nps=13903
Position 43/48: nodes=10814      time=0.63s  nps=17272
Position 44/48: nodes=97438      time=8.46s  nps=11523
Position 45/48: nodes=82875      time=7.17s  nps=11556
Position 46/48: nodes=756757     time=73.03s  nps=10361
Position 47/48: nodes=0          time=0.00s  nps=0  (terminal)
Position 48/48: nodes=0          time=0.00s  nps=0  (terminal)

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

Successfully merging this pull request may close these issues.

1 participant