Problem with Syzygy tablebase

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

eligolf
Posts: 114
Joined: Sat Nov 14, 2020 12:49 pm
Full name: Elias Nilsson

Problem with Syzygy tablebase

Post by eligolf »

I have implemented a Syzygy tabelbase to my engine and technically it works fine. The only problem is that it sometimes choses to simplify to another table instead of going for an easy mate or to sac Q to go for a KR vs K endame instead of KRQ vs K. In the example below, my engine choses to go for Rh1+ which leads to a mate after pawn promotion of d-pawn. The problem is that it has a mate in 2 to use instead, basically any move followed by Rh1# after I move my king.

[d]8/8/8/3p3r/8/5kp1/8/6K1 b - - 0 1

The way I implemented this is that before I go into Negamax loop I check if I am in endgame and have less than 6 pieces left on the table (I use 3,4 and 5 syzygy). If so, it goes into below code to find the position in the tablebase (this example is for a winning position):

Code: Select all

 
    # Find position in tablebase
    with chess.syzygy.open_tablebase('syzygy') as tablebase:
        best_dtz = tablebase.get_dtz(board)
        best_wdl = tablebase.get_wdl(board)
        
    # If finding a winning position in the tablebases
    if best_wdl in (1, 2):

        # Find all possible moves and try them to see if it lowers original best_dtz
        valid_moves = gamestate.get_valid_moves()
        best_move = valid_moves[0]
        for move in valid_moves:
        
            # Make the move and convert to fen to use the Python-chess module
            piece_captured = gamestate.board[move[1]]
            gamestate.make_move(move[0], move[1])
            fen = fh.gamestate_to_fen(gamestate)
            board = chess.Board(fen)

            with chess.syzygy.open_tablebase('syzygy') as tablebase:
                new_dtz = tablebase.get_dtz(board)
                new_wdl = tablebase.get_wdl(board)

            # If winning capture or pawn move, play that immediately. Else see if one can lower dtz.
            if new_wdl in (-1, -2):
                if gamestate.piece_moved == 'p' or piece_captured != '--':
                    gamestate.unmake_move()
                    return move, 1e9
                else:
                    if abs(new_dtz) <= abs(best_dtz):
                        best_dtz = new_dtz
                        best_move = move

        return best_move, 1e9
So basically I try to find the minimum DTZ in the tablebase for each possible move. But since this is not always the same as DTM (distance to mate) it often goes for the DTZ = 0 and then converts to another table to find the mate.

Can I somehow get the DTM instead, or how do you guys solve this?
jdart
Posts: 4367
Joined: Fri Mar 10, 2006 5:23 am
Location: http://www.arasanchess.org

Re: Problem with Syzygy tablebase

Post by jdart »

This problem is inherent in the Syzygy tablebases because they do not provide DTM.

What Stockfish and most engines do is first, filter the moves from the tablebases so that you are only considering those that are at least as good as the best result. In other words, if it is a won position, consider only moves that preserve the win.

Then, they actually search the moves. This will result in the engine finding shallow mates as in your example. This won't totally fix all issues though because of the horizon effect: the engine may still play lines that do not give the shortest win.
User avatar
Fabio Gobbato
Posts: 217
Joined: Fri Apr 11, 2014 10:45 am
Full name: Fabio Gobbato

Re: Problem with Syzygy tablebase

Post by Fabio Gobbato »

For every tb position I compute a material score of the position and I try to estimate the distance to mate. For a bigger material advantage I give a lower distance to mate and for a smaller advantage I give an higher distance to mate.
A tb win must always be a lower bound while a tb loss must always be an upper bound.

I use these functions to estimate the distance to mate:

Code: Select all

static inline int TBWin(TStructThread *t,int ply)
{
   int K = Material(t)/5;
   K = Min(Max(K,-200),200); // K goes from -200 to +200 (-1000cp:1000cp)
   return MATE-240+K-ply;
}

static inline int TBLoss(TStructThread *t,int ply)
{
   int K = Material(t)/5;
   K = Min(Max(K,-200),200); // K goes from -200 to +200 (-1000cp:1000cp)
   return -MATE+240+K+ply;
}
eligolf
Posts: 114
Joined: Sat Nov 14, 2020 12:49 pm
Full name: Elias Nilsson

Re: Problem with Syzygy tablebase

Post by eligolf »

Thank you guys! Maybe I will try to implement a shallow search on the moves to find the mate, it will at least be better than missing mate in 1 or 2 :)
Michel
Posts: 2272
Joined: Mon Sep 29, 2008 1:50 am

Re: Problem with Syzygy tablebase

Post by Michel »

Actually the mate problem can be solved very easily by regarding the TB scores as bounds... In that way the engine will keep searching after a TB win or loss.
Ideas=science. Simplification=engineering.
Without ideas there is nothing to simplify.
User avatar
Fabio Gobbato
Posts: 217
Joined: Fri Apr 11, 2014 10:45 am
Full name: Fabio Gobbato

Re: Problem with Syzygy tablebase

Post by Fabio Gobbato »

Fabio Gobbato wrote: Thu Dec 03, 2020 4:58 pm For every tb position I compute a material score of the position and I try to estimate the distance to mate. For a bigger material advantage I give a lower distance to mate and for a smaller advantage I give an higher distance to mate.
A tb win must always be a lower bound while a tb loss must always be an upper bound.

I use these functions to estimate the distance to mate:

Code: Select all

static inline int TBWin(TStructThread *t,int ply)
{
   int K = Material(t)/5;
   K = Min(Max(K,-200),200); // K goes from -200 to +200 (-1000cp:1000cp)
   return MATE-240+K-ply;
}

static inline int TBLoss(TStructThread *t,int ply)
{
   int K = Material(t)/5;
   K = Min(Max(K,-200),200); // K goes from -200 to +200 (-1000cp:1000cp)
   return -MATE+240+K+ply;
}
This help to enter on a tb position with the max material advantage, but if the tb position is at the root node the tb is used only to filter the moves and is disabled while searching. I haven't read carefully the question. I'm sorry.