Transposition Table , and search result ?

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

MahmoudUthman
Posts: 234
Joined: Sat Jan 17, 2015 11:54 pm

Transposition Table , and search result ?

Post by MahmoudUthman »

how much does(should) a transposition table affect the search result, before implementing the TT ,the search was perfectly stable ,after implementing it (With fail hard normal alpha beta),the program play's different(&bad) moves from the version without TT at the same depth, could this be a TT error, even though the ttentry is checked using the full (64Bit) zobrist key, and the move it contains is checked against all the legal moves' of the position being searched ?
Henk
Posts: 7218
Joined: Mon May 27, 2013 10:31 am

Re: Transposition Table , and search result ?

Post by Henk »

Did you already try using alpha in the research step of PVS ?
MahmoudUthman
Posts: 234
Joined: Sat Jan 17, 2015 11:54 pm

Re: Transposition Table , and search result ?

Post by MahmoudUthman »

I'm not using PVS yet I'm just using normal AlphaBeta:

Code: Select all

int alphaBeta( int alpha, int beta, int depthleft ) {
   if( depthleft == 0 ) return quiesce( alpha, beta );
   for ( all moves)  {
      score = -alphaBeta( -beta, -alpha, depthleft - 1 );
      if( score >= beta )
         return beta;   //  fail hard beta-cutoff
      if( score > alpha )
         alpha = score; // alpha acts like max in MiniMax
   }
   return alpha;
}
Henk
Posts: 7218
Joined: Mon May 27, 2013 10:31 am

Re: Transposition Table , and search result ?

Post by Henk »

Just disable all pruning, reductions, quiescence search.

Or go back to most simple search.
If it is still giving errors then it must be Transposition table.
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Transposition Table , and search result ?

Post by bob »

MahmoudUthman wrote:how much does(should) a transposition table affect the search result, before implementing the TT ,the search was perfectly stable ,after implementing it (With fail hard normal alpha beta),the program play's different(&bad) moves from the version without TT at the same depth, could this be a TT error, even though the ttentry is checked using the full (64Bit) zobrist key, and the move it contains is checked against all the legal moves' of the position being searched ?
Ttable should NOT introduce errors if it is working correctly. If it is broken, of course, all bets are off.

Best way to debug is to find the shallowest search that will produce something that looks wrong, and dump the tree with and without ttable and find out what is going wrong. Sometimes a pencil and paper are the only way to do this. I have created so many tree dumps over the years I could not begin to count them.
MahmoudUthman
Posts: 234
Joined: Sat Jan 17, 2015 11:54 pm

Re: Transposition Table , and search result ?

Post by MahmoudUthman »

Henk van den Belt, Robert Hyatt , thanks.
the TT was indeed broken, after fixing it the search is close to normal , but the TT version is always behind the non TT version when playing against other engines , I have identified the code responsible for this but I don't understand why is this happening (if I use a score from the hash table for the current position at greater search depth shouldn't that enhance the engine not the opposite) ?

Code: Select all

static int AlphaBetaT(int alpha, int beta, int depthleft)
{
	if (depthleft == 0) return qSearchFree(alpha, beta);
	for &#40;int i = 0, J = HalfMoveCounter - 2; i < HalfMoveClock; i += 2&#41;
	&#123;
		if &#40;Positionkey == GameHistory&#91;J&#93;)
			return 0;
		J -= 2;
	&#125;
	NodesSearched++;

	ExtMove LocalBestMove;
	TTEntry ttEntry;
	bool FoundTTEntry = TTLookUp&#40;ttEntry&#41;;
	LocalBestMove.M = ttEntry.BestMove.M & 0x3ffffULL;//Masking Relevant bits&#40;18&#41;
	ExtMove Available&#91;218&#93;;
	U64 InCheck;
	U32 CapturesCount = 0, QuietCount = 0;
	//Generat Ordered Moves MVV/LVA
	if &#40;STM&#41;	Move&#58;&#58;GenLegalMoves<W, 218>&#40;Available, InCheck, CapturesCount, QuietCount&#41;;
	else		Move&#58;&#58;GenLegalMoves<B, 218>&#40;Available, InCheck, CapturesCount, QuietCount&#41;;
	//Perform Complete Legality Check
	bool tvalid =FoundTTEntry&& Move&#58;&#58;IsValid&#40;LocalBestMove,Available&#41;;

	//This Line is the cause if i replace ">=" with "==" in &#58; &#40;ttEntry.BestMove.Depth >= depthleft&#41;
	//the Engine plays as good as the non hashed version "Fixed depth games"
	if &#40;tvalid && &#40;ttEntry.BestMove.Depth >= depthleft&#41;)
	&#123;
		if &#40;ttEntry.BestMove.boundType == BoundType&#58;&#58;Exact&#41; return ttEntry.Score;
		if (&#40;ttEntry.BestMove.boundType == BoundType&#58;&#58;Upper&#41; & &#40;ttEntry.Score >= beta&#41;) return beta;
		if (&#40;ttEntry.BestMove.boundType == BoundType&#58;&#58;Lower&#41; & &#40;ttEntry.Score <= alpha&#41;) return alpha;
	&#125;
	BoundType BT=BoundType&#58;&#58;&#58;&#58;Lower;
	if &#40;tvalid&#41;
	&#123;
		Move&#58;&#58;MakeMoveSearch&#40;LocalBestMove&#41;;
		auto sScore = -AlphaBetaT&#40;-beta, -alpha, depthleft - 1&#41;;
		Move&#58;&#58;UnMakeSearch&#40;LocalBestMove&#41;;
		if &#40;sScore >= beta&#41;
		&#123;
			if (&#40;TypeBoard&#91;LocalBestMove.To&#93; == 0&#41; && &#40;LocalBestMove.M != Killers&#91;ply&#93;&#91;0&#93;.M&#41;)//NonCapture&#58;UpdateKillers
			&#123;
				Killers&#91;ply&#93;&#91;1&#93; = Killers&#91;ply&#93;&#91;0&#93;; Killers&#91;ply&#93;&#91;0&#93; = LocalBestMove;
			&#125;
			TTAdd&#40;LocalBestMove, depthleft, BoundType&#58;&#58;Upper, beta&#41;;
			return beta;
		&#125;
		if &#40;sScore > alpha&#41;
		&#123;
			alpha = sScore;
			BT=BoundType&#58;&#58;Exact;
		&#125;
	&#125;
	ExtMove ttMove = LocalBestMove;
	
	for &#40;unsigned int i = 0; i < CapturesCount; i++)
	&#123;
		if &#40;Available&#91;i&#93;.M == ttMove.M&#41; continue;//Skip TTMove
		Move&#58;&#58;MakeMoveSearch&#40;Available&#91;i&#93;);
		auto score = -AlphaBetaT&#40;-beta, -alpha, depthleft - 1&#41;;
		Move&#58;&#58;UnMakeSearch&#40;Available&#91;i&#93;);
		if &#40;score >= beta&#41; 
		&#123;
			TTAdd&#40;Available&#91;i&#93;, depthleft, BoundType&#58;&#58;Upper, beta&#41;;//Beta instead
			return beta;
		&#125;
		if &#40;score > alpha&#41; 
		&#123;
			alpha = score;
			BT=BoundType&#58;&#58;Exact;
		&#125;
	&#125;
	//Similar Loop For Quiets

	//Mate/Stale
	if (&#40;CapturesCount + QuietCount&#41; == 0&#41;
	&#123;
		auto Score=InCheck?--INT_MAX + ply&#58;0;
		TTAdd&#40;ExtMove&#40;), depthleft, BoundType&#58;&#58;Exact, Score&#41;;
		return Score;
	&#125;
	TTAdd&#40;LocalBestMove, depthleft, BT, alpha&#41;;
	return alpha;
&#125;
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Transposition Table , and search result ?

Post by Sven »

MahmoudUthman wrote:Henk van den Belt, Robert Hyatt , thanks.
the TT was indeed broken, after fixing it the search is close to normal , but the TT version is always behind the non TT version when playing against other engines , I have identified the code responsible for this but I don't understand why is this happening (if I use a score from the hash table for the current position at greater search depth shouldn't that enhance the engine not the opposite) ?

Code: Select all

if (&#40;ttEntry.BestMove.boundType == BoundType&#58;&#58;Upper&#41; & &#40;ttEntry.Score >= beta&#41;) return beta;
if (&#40;ttEntry.BestMove.boundType == BoundType&#58;&#58;Lower&#41; & &#40;ttEntry.Score <= alpha&#41;) return alpha;
I think you are mixing Upper and Lower here. "Upper" means "upper bound", so the actual value is <= the TT score. The opposite for "Lower". You can only return beta if you are sure that the TT score is >= beta, which requires the bound type to be "lower bound".
op12no2
Posts: 490
Joined: Tue Feb 04, 2014 12:25 pm
Full name: Colin Jenkins

Re: Transposition Table , and search result ?

Post by op12no2 »

Should the &s not be &&s in the lines Sven quoted...?

You don't seem to fiddle with mate TT values, so you could also try disabling the TT save for mate/stalemate for now; it may be causing some weirdness.
MahmoudUthman
Posts: 234
Joined: Sat Jan 17, 2015 11:54 pm

Re: Transposition Table , and search result ?

Post by MahmoudUthman »

Sven Schüle wrote:
I think you are mixing Upper and Lower here. "Upper" means "upper bound", so the actual value is <= the TT score. The opposite for "Lower". You can only return beta if you are sure that the TT score is >= beta, which requires the bound type to be "lower bound".
I don't use BoundType enumeration any where/way else so even if it was wrongly named it shouldn't affect the result since I'm using "Bound::Upper" to refer to beta cutoff's everywhere , and Bound::lower to refer to alpha's, for example my routine is identical to this
http://web.archive.org/web/200711120942 ... ashing.htm
with :
BoundType::Exact--->hashfEXACT
BoundType::Lower--->hashfALPHA
BoundType::Upper--->hashfBETA

Colin Jenkins wrote:

Code: Select all

Should the &s not be &&s in the lines Sven quoted...? 

 You don't seem to fiddle with mate TT values, so you could also try disabling the TT save for mate/stalemate for now; it may be causing some weirdness.
both sides are Boolean with no side effects so there shouldn't be any difference.
*seems like disabling the TT for Mate Scores changes the result ,I will try to identify the problem and test.[/quote]
MahmoudUthman
Posts: 234
Joined: Sat Jan 17, 2015 11:54 pm

Re: Transposition Table , and search result ?

Post by MahmoudUthman »

Sven Schüle,Colin Jenkins ,Thanks
The error was caused by implicit conversion(C++) ,the max ply def was (unsigned int) which caused the matedinmaxply def to be of type (unsigned int) resulting in the code adjusting matescores for the TT to modify non mate scores, anyway how many games do I need to put the engine through to measure changes to it's strength accurately :for example ,this is the result of 700 games (8 engines ,round robin , 25 rounds):

Code: Select all

3/28/2015 7&#58;15&#58;40 AM &#58;

    Program                          Elo    +   -   Games   Score   Av.Op.  Draws

  1 Ruffian 1.0.5                  &#58; 2736   90  82   175    90.9 %   2337    3.4 %
  2 SOS 5.1 for Arena              &#58; 2574   61  59   175    77.4 %   2360    5.1 %
  3 Spike 1.4                      &#58; 2380   50  50   175    48.9 %   2388    8.6 %
  4 ChessEngine                    &#58; 2338   51  51   175    42.0 %   2394    5.1 %
  5 AnMon 5.75                     &#58; 2336   49  50   175    41.7 %   2394   10.3 %
  6 ChessEngineX                   &#58; 2325   50  51   175    40.0 %   2396    8.0 %
  7 Chess_cpu                      &#58; 2266   52  54   175    31.1 %   2404    8.6 %
  8 Hermann 2.8 64 bit             &#58; 2243   54  55   175    28.0 %   2408    9.1 %
and the result of the matching:

Code: Select all

-----------------AnMon 5.75-----------------
AnMon 5.75 - Chess_cpu                 &#58; 14.5/25 12-8-5 (==10=1=01011110110001=011&#41;  58%   +56
AnMon 5.75 - ChessEngine               &#58; 11.0/25 11-14-0 &#40;1110100010000000011111001&#41;  44%   -42
AnMon 5.75 - ChessEngineX              &#58; 14.0/25 13-10-2 &#40;110101011111010=1=0100010&#41;  56%   +42
AnMon 5.75 - Hermann 2.8 64 bit        &#58; 15.0/25 12-7-6 &#40;00=0010111=111==10=1110=1&#41;  60%   +70
AnMon 5.75 - Ruffian 1.0.5             &#58; 1.5/25 1-23-1 &#40;000000000001000000000000=)   6%  -478
AnMon 5.75 - SOS 5.1 for Arena         &#58; 5.0/25 4-19-2 &#40;000000000011000000==10010&#41;  20%  -241
AnMon 5.75 - Spike 1.4                 &#58; 12.0/25 11-12-2 (=010111000=00101010011110&#41;  48%   -14
-----------------Chess_cpu-----------------
Chess_cpu - AnMon 5.75                 &#58; 10.5/25 8-12-5 (==01=0=10100001001110=100&#41;  42%   -56
Chess_cpu - ChessEngine                &#58; 10.5/25 10-14-1 &#40;01010100=1010101010110000&#41;  42%   -56
Chess_cpu - ChessEngineX               &#58; 8.0/25 6-15-4 &#40;101=100=00=000=0001010001&#41;  32%  -131
Chess_cpu - Hermann 2.8 64 bit         &#58; 17.5/25 17-7-1 &#40;00000011=1111111110111111&#41;  70%  +147
Chess_cpu - Ruffian 1.0.5              &#58; 2.0/25 1-22-2 &#40;0000000010000000=000000=0&#41;   8%  -424
Chess_cpu - SOS 5.1 for Arena          &#58; 1.5/25 1-23-1 &#40;000000001000000=000000000&#41;   6%  -478
Chess_cpu - Spike 1.4                  &#58; 4.5/25 4-20-1 &#40;0100=00000000100000000011&#41;  18%  -263
-----------------ChessEngine-----------------
ChessEngine - AnMon 5.75               &#58; 14.0/25 14-11-0 &#40;0001011101111111100000110&#41;  56%   +42
ChessEngine - Chess_cpu                &#58; 14.5/25 14-10-1 &#40;10101011=0101010101001111&#41;  58%   +56
ChessEngine - ChessEngineX             &#58; 13.0/25 13-12-0 &#40;1010101010101010101010101&#41;  52%   +14
ChessEngine - Hermann 2.8 64 bit       &#58; 16.5/25 15-7-3 &#40;0=00101011101=11=11111101&#41;  66%  +115
ChessEngine - Ruffian 1.0.5            &#58; 2.0/25 2-23-0 &#40;0000000000000000001000100&#41;   8%  -424
ChessEngine - SOS 5.1 for Arena        &#58; 1.5/25 1-23-1 &#40;00000000000=0000000100000&#41;   6%  -478
ChessEngine - Spike 1.4                &#58; 12.0/25 10-11-4 &#40;0101=10100=10101010101==0&#41;  48%   -14
-----------------ChessEngineX-----------------
ChessEngineX - AnMon 5.75              &#58; 11.0/25 10-13-2 &#40;001010100000101=0=1011101&#41;  44%   -42
ChessEngineX - Chess_cpu               &#58; 17.0/25 15-6-4 &#40;010=011=11=111=1110101110&#41;  68%  +131
ChessEngineX - ChessEngine             &#58; 12.0/25 12-13-0 &#40;0101010101010101010101010&#41;  48%   -14
ChessEngineX - Hermann 2.8 64 bit      &#58; 12.0/25 11-12-2 &#40;0000=000110011101=1010111&#41;  48%   -14
ChessEngineX - Ruffian 1.0.5           &#58; 3.0/25 2-21-2 &#40;0100000001000000000=000=0&#41;  12%  -346
ChessEngineX - SOS 5.1 for Arena       &#58; 8.0/25 8-17-0 &#40;0100000101010001001100010&#41;  32%  -131
ChessEngineX - Spike 1.4               &#58; 7.0/25 5-16-4 &#40;0000100000100=000=101=0=1&#41;  28%  -164
-----------------Hermann 2.8 64 bit-----------------
Hermann 2.8 64 bit - AnMon 5.75        &#58; 10.0/25 7-12-6 &#40;11=1101000=000==01=0001=0&#41;  40%   -70
Hermann 2.8 64 bit - Chess_cpu         &#58; 7.5/25 7-17-1 &#40;11111100=0000000001000000&#41;  30%  -147
Hermann 2.8 64 bit - ChessEngine       &#58; 8.5/25 7-15-3 &#40;1=11010100010=00=00000010&#41;  34%  -115
Hermann 2.8 64 bit - ChessEngineX      &#58; 13.0/25 12-11-2 &#40;1111=111001100010=0101000&#41;  52%   +14
Hermann 2.8 64 bit - Ruffian 1.0.5     &#58; 0.0/25 0-25-0 &#40;0000000000000000000000000&#41;   0% -1200
Hermann 2.8 64 bit - SOS 5.1 for Arena &#58; 2.0/25 1-22-2 &#40;00100=000=000000000000000&#41;   8%  -424
Hermann 2.8 64 bit - Spike 1.4         &#58; 8.0/25 7-16-2 &#40;0111110=001000=0000000010&#41;  32%  -131
-----------------Ruffian 1.0.5-----------------
Ruffian 1.0.5 - AnMon 5.75             &#58; 23.5/25 23-1-1 &#40;111111111110111111111111=)  94%  +478
Ruffian 1.0.5 - Chess_cpu              &#58; 23.0/25 22-1-2 &#40;1111111101111111=111111=1&#41;  92%  +424
Ruffian 1.0.5 - ChessEngine            &#58; 23.0/25 23-2-0 &#40;1111111111111111110111011&#41;  92%  +424
Ruffian 1.0.5 - ChessEngineX           &#58; 22.0/25 21-2-2 &#40;1011111110111111111=111=1&#41;  88%  +346
Ruffian 1.0.5 - Hermann 2.8 64 bit     &#58; 25.0/25 25-0-0 &#40;1111111111111111111111111&#41; 100% +1200
Ruffian 1.0.5 - SOS 5.1 for Arena      &#58; 18.5/25 18-6-1 &#40;10011101=1111111100111101&#41;  74%  +182
Ruffian 1.0.5 - Spike 1.4              &#58; 24.0/25 24-1-0 &#40;1110111111111111111111111&#41;  96%  +552
-----------------SOS 5.1 for Arena-----------------
SOS 5.1 for Arena - AnMon 5.75         &#58; 20.0/25 19-4-2 &#40;111111111100111111==01101&#41;  80%  +241
SOS 5.1 for Arena - Chess_cpu          &#58; 23.5/25 23-1-1 &#40;111111110111111=111111111&#41;  94%  +478
SOS 5.1 for Arena - ChessEngine        &#58; 23.5/25 23-1-1 &#40;11111111111=1111111011111&#41;  94%  +478
SOS 5.1 for Arena - ChessEngineX       &#58; 17.0/25 17-8-0 &#40;1011111010101110110011101&#41;  68%  +131
SOS 5.1 for Arena - Hermann 2.8 64 bit &#58; 23.0/25 22-1-2 &#40;11011=111=111111111111111&#41;  92%  +424
SOS 5.1 for Arena - Ruffian 1.0.5      &#58; 6.5/25 6-18-1 &#40;01100010=0000000011000010&#41;  26%  -182
SOS 5.1 for Arena - Spike 1.4          &#58; 22.0/25 21-2-2 &#40;10111111111111110=11=1111&#41;  88%  +346
-----------------Spike 1.4-----------------
Spike 1.4 - AnMon 5.75                 &#58; 13.0/25 12-11-2 (=101000111=11010101100001&#41;  52%   +14
Spike 1.4 - Chess_cpu                  &#58; 20.5/25 20-4-1 &#40;1011=11111111011111111100&#41;  82%  +263
Spike 1.4 - ChessEngine                &#58; 13.0/25 11-10-4 &#40;1010=01011=01010101010==1&#41;  52%   +14
Spike 1.4 - ChessEngineX               &#58; 18.0/25 16-5-4 &#40;1111011111011=111=010=1=0&#41;  72%  +164
Spike 1.4 - Hermann 2.8 64 bit         &#58; 17.0/25 16-7-2 &#40;1000001=110111=1111111101&#41;  68%  +131
Spike 1.4 - Ruffian 1.0.5              &#58; 1.0/25 1-24-0 &#40;0001000000000000000000000&#41;   4%  -552
Spike 1.4 - SOS 5.1 for Arena          &#58; 3.0/25 2-21-2 &#40;01000000000000001=00=0000&#41;  12%  -346
the non hashed version is ChessEngineX , the hashed version is ChessEngine,the hashed version performed better against most engines but it's performance dropped significantly playing against Chess_Cpu and SOS ,is this normal or does this indicate a bug (the engines are restarted after every game so there is no hash table entries from previous games searches ) ?