Fix TT: Gains 83.0 +/- 32.5 elo
This commit is contained in:
parent
9a41ba50ff
commit
5100bc744c
|
@ -127,6 +127,8 @@ proc log(self: SearchManager, depth: int) =
|
||||||
elapsedMsec = elapsed.inMilliseconds.uint64
|
elapsedMsec = elapsed.inMilliseconds.uint64
|
||||||
nps = 1000 * (self.nodeCount div max(elapsedMsec, 1))
|
nps = 1000 * (self.nodeCount div max(elapsedMsec, 1))
|
||||||
var logMsg = &"info depth {depth} time {elapsedMsec} nodes {self.nodeCount} nps {nps}"
|
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():
|
if self.bestMoveRoot != nullMove():
|
||||||
logMsg &= &" score cp {self.bestRootScore} pv {self.bestMoveRoot.toAlgebraic()}"
|
logMsg &= &" score cp {self.bestRootScore} pv {self.bestMoveRoot.toAlgebraic()}"
|
||||||
echo logMsg
|
echo logMsg
|
||||||
|
@ -268,8 +270,8 @@ proc search(self: SearchManager, depth, ply: int, alpha, beta: Score): Score {.d
|
||||||
var score: Score
|
var score: Score
|
||||||
var fullDepth = true
|
var fullDepth = true
|
||||||
when defined(searchLMR):
|
when defined(searchLMR):
|
||||||
if extension == 0 and i >= 3 and not move.isCapture():
|
if extension == 0 and i >= 5 and not move.isCapture():
|
||||||
# Late Move Reduction: assume our move orderer did a good job,
|
# 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.
|
# 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
|
# If this move turns out to be better than we expected, we'll re-search
|
||||||
# it at full depth
|
# it at full depth
|
||||||
|
|
|
@ -44,16 +44,41 @@ type
|
||||||
bestMove*: Move
|
bestMove*: Move
|
||||||
|
|
||||||
TTable* = ref object
|
TTable* = ref object
|
||||||
|
## A transposition table
|
||||||
data: seq[TTEntry]
|
data: seq[TTEntry]
|
||||||
|
when defined(debug):
|
||||||
|
hits: uint64
|
||||||
|
occupancy: uint64
|
||||||
|
collisions: uint64
|
||||||
size: 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 =
|
proc newTranspositionTable*(size: uint64): TTable =
|
||||||
## Initializes a new transposition table of
|
## Initializes a new transposition table of
|
||||||
## size bytes
|
## size bytes
|
||||||
new(result)
|
new(result)
|
||||||
let numEntries = size div sizeof(TTEntry).uint64
|
let numEntries = size div sizeof(TTEntry).uint64
|
||||||
result.data = newSeq[TTEntry](numEntries)
|
result.data = newSeq[TTEntry](numEntries)
|
||||||
|
result.size = numEntries
|
||||||
|
|
||||||
|
|
||||||
func getIndex(self: TTable, key: ZobristKey): uint64 =
|
func getIndex(self: TTable, key: ZobristKey): uint64 =
|
||||||
|
@ -71,6 +96,14 @@ func getIndex(self: TTable, key: ZobristKey): uint64 =
|
||||||
|
|
||||||
func store*(self: TTable, depth: uint8, score: Score, hash: ZobristKey, bestMove: Move, flag: TTentryFlag) =
|
func store*(self: TTable, depth: uint8, score: Score, hash: ZobristKey, bestMove: Move, flag: TTentryFlag) =
|
||||||
## Stores an entry in the transposition table
|
## Stores an entry in the transposition table
|
||||||
|
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)
|
self.data[self.getIndex(hash)] = TTEntry(flag: flag, score: int16(score), hash: hash, depth: depth, bestMove: bestMove)
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,6 +116,9 @@ proc get*(self: TTable, hash: ZobristKey, depth: uint8): tuple[success: bool, en
|
||||||
## it's true
|
## it's true
|
||||||
result.entry = self.data[self.getIndex(hash)]
|
result.entry = self.data[self.getIndex(hash)]
|
||||||
result.success = result.entry.hash == hash and result.entry.depth >= depth
|
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] =
|
proc get*(self: TTable, hash: ZobristKey): tuple[success: bool, entry: TTEntry] =
|
||||||
|
@ -93,3 +129,6 @@ proc get*(self: TTable, hash: ZobristKey): tuple[success: bool, entry: TTEntry]
|
||||||
## invalid unless it's true
|
## invalid unless it's true
|
||||||
result.entry = self.data[self.getIndex(hash)]
|
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()
|
session.board = newDefaultChessboard()
|
||||||
of Go:
|
of Go:
|
||||||
when defined(useTT):
|
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:
|
if session.debug:
|
||||||
echo &"info string created {session.hashTableSize} MiB TT"
|
echo &"info string created {session.hashTableSize} MiB TT"
|
||||||
session.transpositionTable = newTranspositionTable(session.hashTableSize * 1024 * 1024)
|
|
||||||
session.searchThread = new Thread[tuple[session: UCISession, command: UCICommand]]
|
session.searchThread = new Thread[tuple[session: UCISession, command: UCICommand]]
|
||||||
createThread(session.searchThread[], bestMove, (session, cmd))
|
createThread(session.searchThread[], bestMove, (session, cmd))
|
||||||
if session.debug:
|
if session.debug:
|
||||||
|
|
Loading…
Reference in New Issue