Fix TT: Gains 83.0 +/- 32.5 elo
This commit is contained in:
parent
1e06a5caef
commit
0b66f67e8c
|
@ -127,6 +127,8 @@ proc log(self: SearchManager, depth: int) =
|
|||
elapsedMsec = elapsed.inMilliseconds.uint64
|
||||
nps = 1000 * (self.nodeCount div max(elapsedMsec, 1))
|
||||
var logMsg = &"info depth {depth} time {elapsedMsec} nodes {self.nodeCount} nps {nps}"
|
||||
if not self.transpositionTable.isNil():
|
||||
logMsg &= &" hashfull {self.transpositionTable.getFillEstimate()}"
|
||||
if self.bestMoveRoot != nullMove():
|
||||
logMsg &= &" score cp {self.bestRootScore} pv {self.bestMoveRoot.toAlgebraic()}"
|
||||
echo logMsg
|
||||
|
@ -268,8 +270,8 @@ proc search(self: SearchManager, depth, ply: int, alpha, beta: Score): Score {.d
|
|||
var score: Score
|
||||
var fullDepth = true
|
||||
when defined(searchLMR):
|
||||
if extension == 0 and i >= 3 and not move.isCapture():
|
||||
# Late Move Reduction: assume our move orderer did a good job,
|
||||
if extension == 0 and i >= 5 and not move.isCapture():
|
||||
# Late Move Reductions: assume our move orderer did a good job,
|
||||
# so it is not worth it to look at all moves at the same depth equally.
|
||||
# If this move turns out to be better than we expected, we'll re-search
|
||||
# it at full depth
|
||||
|
|
|
@ -44,16 +44,41 @@ type
|
|||
bestMove*: Move
|
||||
|
||||
TTable* = ref object
|
||||
## A transposition table
|
||||
data: seq[TTEntry]
|
||||
when defined(debug):
|
||||
hits: uint64
|
||||
occupancy: uint64
|
||||
collisions: uint64
|
||||
size: uint64
|
||||
|
||||
|
||||
func size*(self: TTable): uint64 = self.size
|
||||
|
||||
when defined(debug):
|
||||
func hits*(self: TTable): uint64 = self.hits
|
||||
func collisions*(self: TTable): uint64 = self.collisions
|
||||
func occupancy*(self: TTable): uint64 = self.occupancy
|
||||
|
||||
|
||||
func getFillEstimate*(self: TTable): uint64 =
|
||||
# For performance reasons, we estimate the occupancy by
|
||||
# looking at the first 1000 entries in the table. Why 1000?
|
||||
# Because the "hashfull" info message is conventionally not a
|
||||
# percentage, but rather a per...millage? It's in thousandths
|
||||
# rather than hundredths is the point, don't ask me why
|
||||
for i in 0..999:
|
||||
if self.data[i].hash != ZobristKey(0):
|
||||
inc(result)
|
||||
|
||||
|
||||
proc newTranspositionTable*(size: uint64): TTable =
|
||||
## Initializes a new transposition table of
|
||||
## size bytes
|
||||
new(result)
|
||||
let numEntries = size div sizeof(TTEntry).uint64
|
||||
result.data = newSeq[TTEntry](numEntries)
|
||||
result.size = numEntries
|
||||
|
||||
|
||||
func getIndex(self: TTable, key: ZobristKey): uint64 =
|
||||
|
@ -71,7 +96,15 @@ func getIndex(self: TTable, key: ZobristKey): uint64 =
|
|||
|
||||
func store*(self: TTable, depth: uint8, score: Score, hash: ZobristKey, bestMove: Move, flag: TTentryFlag) =
|
||||
## Stores an entry in the transposition table
|
||||
self.data[self.getIndex(hash)] = TTEntry(flag: flag, score: int16(score), hash: hash, depth: depth, bestMove: bestMove)
|
||||
when defined(debug):
|
||||
let idx = self.getIndex(hash)
|
||||
if self.data[idx].hash != ZobristKey(0):
|
||||
inc(self.collisions)
|
||||
else:
|
||||
inc(self.occupancy)
|
||||
self.data[idx] = TTEntry(flag: flag, score: int16(score), hash: hash, depth: depth, bestMove: bestMove)
|
||||
else:
|
||||
self.data[self.getIndex(hash)] = TTEntry(flag: flag, score: int16(score), hash: hash, depth: depth, bestMove: bestMove)
|
||||
|
||||
|
||||
proc get*(self: TTable, hash: ZobristKey, depth: uint8): tuple[success: bool, entry: TTEntry] =
|
||||
|
@ -83,6 +116,9 @@ proc get*(self: TTable, hash: ZobristKey, depth: uint8): tuple[success: bool, en
|
|||
## it's true
|
||||
result.entry = self.data[self.getIndex(hash)]
|
||||
result.success = result.entry.hash == hash and result.entry.depth >= depth
|
||||
when defined(debug):
|
||||
if result.success:
|
||||
inc(self.hits)
|
||||
|
||||
|
||||
proc get*(self: TTable, hash: ZobristKey): tuple[success: bool, entry: TTEntry] =
|
||||
|
@ -92,4 +128,7 @@ proc get*(self: TTable, hash: ZobristKey): tuple[success: bool, entry: TTEntry]
|
|||
## or other anomaly: the result should be considered
|
||||
## invalid unless it's true
|
||||
result.entry = self.data[self.getIndex(hash)]
|
||||
result.success = result.entry.hash == hash
|
||||
result.success = result.entry.hash == hash
|
||||
when defined(debug):
|
||||
if result.success:
|
||||
inc(self.hits)
|
|
@ -354,10 +354,10 @@ proc startUCISession* =
|
|||
session.board = newDefaultChessboard()
|
||||
of Go:
|
||||
when defined(useTT):
|
||||
if session.transpositionTable.isNil():
|
||||
if session.transpositionTable.isNil() or session.transpositionTable.size() == 0:
|
||||
session.transpositionTable = newTranspositionTable(session.hashTableSize * 1024 * 1024)
|
||||
if session.debug:
|
||||
echo &"info string created {session.hashTableSize} MiB TT"
|
||||
session.transpositionTable = newTranspositionTable(session.hashTableSize * 1024 * 1024)
|
||||
session.searchThread = new Thread[tuple[session: UCISession, command: UCICommand]]
|
||||
createThread(session.searchThread[], bestMove, (session, cmd))
|
||||
if session.debug:
|
||||
|
|
Loading…
Reference in New Issue