diff options
| author | Scott Gasch <[email protected]> | 2026-09-25 08:44:25 -0700 |
|---|---|---|
| committer | Scott Gasch <[email protected]> | 2026-09-25 08:44:25 -0700 |
| commit | 9b28080f8b3dca4588cb2aaaf748451f45e3c626 (patch) | |
| tree | 54e0aff5d6ee1520c590c7c04a5ae2f8299e7497 /src/probe.c | |
| parent | 66740dc89c7351c120c25788d0079055034f4942 (diff) | |
Two ideas:
1. Nullmove R=3 + depth/6 along with some ShouldWeDoNullmoveSearch
tweaking and calibrating.
2. Probe EGTB everywhere in the search as long as the table/position
is resident in memory.
Diffstat (limited to 'src/probe.c')
| -rw-r--r-- | src/probe.c | 194 |
1 files changed, 121 insertions, 73 deletions
diff --git a/src/probe.c b/src/probe.c index 2bddf99..269a1b9 100644 --- a/src/probe.c +++ b/src/probe.c @@ -138,10 +138,25 @@ Routine description: Build the set of bitboards Fathom's tb_probe_wdl wants out of our POSITION. Fathom expects the standard tablebase square numbering - (a1 == bit 0 ... h8 == bit 63), which is exactly what our TO64() - macro produces -- note this is *not* the same square numbering as - our engine's own internal BBSQUARE/COOR_TO_BB bitboards, so we - must not use those macros here. + (a1 == bit 0 ... h8 == bit 63); our own internal bitboards + (bbPieces/bbPawns/bbOccupiedSide) instead index bit = rankTopDown*8 + + file (rankTopDown 0 == rank 8 ... 7 == rank 1 -- see TO64's own + (7 - (x>>4)) flip). Those two numberings differ by exactly one + 64-bit byte-swap: internal bit r*8+f (byte r, offset f) lands at + Fathom bit (7-r)*8+f (byte 7-r, offset f) under bswap64, matching + TO64's formula term for term. So this can OR our own bitboards + together and byte-swap the result directly -- O(1) per output + bitboard -- instead of walking every piece one at a time through + CoorFromBitBoardRank8ToRank1/TO64. (2026-09-24: replaced the + original per-piece-popping version, which showed up as a real + self-play NPS/depth regression once EgtbProbeLikelyResident started + calling this from QSearch's hot path -- see CLAUDE.md.) + + No bbPieces[color][KING] exists (deliberately -- see its own + comment), so the king bitboard is built from the single square in + cKingSq[color] instead; equivalent to bswapping a bitboard with only + that one bit set, since bswap64 is just a bit permutation and + commutes with OR. Parameters: @@ -154,75 +169,22 @@ Return value: **/ { - ULONG uColor; - COOR c; - UINT64 bb; - - *pu64White = *pu64Black = 0ULL; - *pu64Kings = *pu64Queens = *pu64Rooks = 0ULL; - *pu64Bishops = *pu64Knights = *pu64Pawns = 0ULL; - - for (uColor = BLACK; uColor <= WHITE; uColor++) - { - UINT64 *pu64Side = (uColor == WHITE) ? pu64White : pu64Black; - - { - BITBOARD bbPawns = pos->bbPawns[uColor]; - - while (IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(&bbPawns))) - { - bb = (1ULL << (TO64(c))); - *pu64Side |= bb; - *pu64Pawns |= bb; - } - } - - { - c = KingPosition(pos, uColor); - ASSERT(IS_ON_BOARD(c)); - ASSERT(IS_KING(pos->rgSquare[c].pPiece)); - bb = (1ULL << (TO64(c))); - *pu64Side |= bb; - *pu64Kings |= bb; - } - - { - BITBOARD bbType; - COOR cType; - - bbType = pos->bbPieces[uColor][KNIGHT]; - while (IS_ON_BOARD(cType = CoorFromBitBoardRank8ToRank1(&bbType))) - { - bb = (1ULL << (TO64(cType))); - *pu64Side |= bb; - *pu64Knights |= bb; - } + UINT64 u64Kings = (1ULL << COOR_TO_BIT_NUMBER(pos->cKingSq[WHITE])) | + (1ULL << COOR_TO_BIT_NUMBER(pos->cKingSq[BLACK])); - bbType = pos->bbPieces[uColor][BISHOP]; - while (IS_ON_BOARD(cType = CoorFromBitBoardRank8ToRank1(&bbType))) - { - bb = (1ULL << (TO64(cType))); - *pu64Side |= bb; - *pu64Bishops |= bb; - } - - bbType = pos->bbPieces[uColor][ROOK]; - while (IS_ON_BOARD(cType = CoorFromBitBoardRank8ToRank1(&bbType))) - { - bb = (1ULL << (TO64(cType))); - *pu64Side |= bb; - *pu64Rooks |= bb; - } - - bbType = pos->bbPieces[uColor][QUEEN]; - while (IS_ON_BOARD(cType = CoorFromBitBoardRank8ToRank1(&bbType))) - { - bb = (1ULL << (TO64(cType))); - *pu64Side |= bb; - *pu64Queens |= bb; - } - } - } + *pu64White = __builtin_bswap64((UINT64)pos->bbOccupiedSide[WHITE]); + *pu64Black = __builtin_bswap64((UINT64)pos->bbOccupiedSide[BLACK]); + *pu64Kings = __builtin_bswap64(u64Kings); + *pu64Queens = __builtin_bswap64( + (UINT64)(pos->bbPieces[WHITE][QUEEN] | pos->bbPieces[BLACK][QUEEN])); + *pu64Rooks = __builtin_bswap64( + (UINT64)(pos->bbPieces[WHITE][ROOK] | pos->bbPieces[BLACK][ROOK])); + *pu64Bishops = __builtin_bswap64( + (UINT64)(pos->bbPieces[WHITE][BISHOP] | pos->bbPieces[BLACK][BISHOP])); + *pu64Knights = __builtin_bswap64( + (UINT64)(pos->bbPieces[WHITE][KNIGHT] | pos->bbPieces[BLACK][KNIGHT])); + *pu64Pawns = __builtin_bswap64( + (UINT64)(pos->bbPawns[WHITE] | pos->bbPawns[BLACK])); } @@ -324,6 +286,72 @@ Return value: } +FLAG +EgtbProbeLikelyResident(SEARCHER_THREAD_CONTEXT *ctx) +/** + +Routine description: + + Cheap, non-blocking predictor for "would an EGTB probe of the + current position be low latency?" -- used to let deep search/qsearch + nodes probe the EGTB (which is normally reserved for shallow, near- + root plies to avoid stalling the tree search on a disk read) once + the specific pages this exact position's lookup needs are already + resident, whether from an earlier probe this run or (for 3-5 man + tables) because they were mlock()'d in whole at load time. + + Does not itself probe the tablebase, take g_uEgtbLock, or read any + file data that isn't already confirmed resident first -- see + tb_wdl_probe_is_resident in fathom/tbprobe.c for the mincore()-gated + walk this performs (indexTable/sizeTable/data-block addresses for + 6-man tables; a single ready[] check for the mlock()'d 3-5 man + tier). Safe to call from every leaf-ish node without worrying about + search slowdown. + + Same castling/fifty-move/cardinality gating as ProbeEGTB (a probe + that ProbeEGTB itself would refuse is never "likely resident"). + +Parameters: + + SEARCHER_THREAD_CONTEXT *ctx + +Return value: + + FLAG -- TRUE iff a subsequent ProbeEGTB call for this exact position + is expected to hit already-resident tablebase data rather than pay a + first-touch mmap()/parse (and possibly disk-read) cost. + +**/ +{ + POSITION *pos = &(ctx->sPosition); + UINT64 u64White, u64Black, u64Kings, u64Queens; + UINT64 u64Rooks, u64Bishops, u64Knights, u64Pawns; + ULONG wcount, bcount; + + if (FALSE == g_fEgtbInitialized || 0 == TB_LARGEST) + { + return(FALSE); + } + if ((0 != pos->bvCastleInfo) || (0 != pos->uFifty)) + { + return(FALSE); + } + wcount = TotalNonPawnCount(pos, WHITE) + FastCountBits(pos->bbPawns[WHITE]); + bcount = TotalNonPawnCount(pos, BLACK) + FastCountBits(pos->bbPawns[BLACK]); + if ((wcount + bcount) > TB_LARGEST) + { + return(FALSE); + } + + _BuildFathomBitboards(pos, &u64White, &u64Black, &u64Kings, &u64Queens, + &u64Rooks, &u64Bishops, &u64Knights, &u64Pawns); + return(1 == tb_wdl_probe_is_resident(u64White, u64Black, u64Kings, + u64Queens, u64Rooks, u64Bishops, + u64Knights, u64Pawns, + (pos->uToMove == WHITE))); +} + + // // Convert a Fathom tablebase square index (a1==0 ... h8==63) back into // our own COOR encoding. Inverse of TO64(). @@ -487,8 +515,28 @@ Return value: (mv.cTo == cTo) && (mv.pPromoted == pPromotes)) { + // Root-only: use the DTZ ply count tb_probe_root already + // packed into uResult (no extra probe) to report a real, + // ply-distance-aware mate score instead of the flat + // EGTB_WIN_SCORE/LOSS_SCORE used by in-search probes + // (ProbeEGTB/RecognLookup) -- those stay WDL-only and + // untouched. util.c's SCORE-to-string formatter already + // treats any |score| >= NMATE as a mate score and derives + // the move count as (INFINITY_SCORE - iScore) / 2, so + // INFINITY_SCORE -/+ uDtz round-trips through that + // unmodified as "+MATE<n>"/"-MATE<n>". Clamp defensively: + // a uDtz large enough to push the score below NMATE would + // just silently fall back to plain-decimal display, not + // corrupt anything, but keep it a real mate score at every + // legal DTZ value we could plausibly see (TB_MAX_PLY=256 + // exceeds NMATE's 200-point margin in principle, however + // unlikely in practice for <=7-man tables). + ULONG uDtz = TB_GET_DTZ(uResult); + if (uDtz >= (+INFINITY_SCORE - NMATE)) uDtz = (+INFINITY_SCORE - NMATE - 1); *pmv = mv; - *piScore = (TB_WIN == uWdl) ? EGTB_WIN_SCORE : EGTB_LOSS_SCORE; + *piScore = (TB_WIN == uWdl) ? + (SCORE)(+INFINITY_SCORE - uDtz) : + (SCORE)(-INFINITY_SCORE + uDtz); return(TRUE); } } |
