[Entertainment] When tuning goes wrong...

Discussion of chess software programming and technical issues.

Moderator: Ras

Pablo Vazquez
Posts: 155
Joined: Thu May 31, 2007 9:05 pm
Location: Madrid, Spain

Re: [Entertainment] When tuning goes wrong...

Post by Pablo Vazquez »

ZirconiumX wrote:I've been tuning my PST array in Durandal (based on Sungorus 1.4) - and CLOP has given me some absurd values - and part of me says to ignore the values because the Sungorus eval was $*%# and needs replacing.

For your entertainment - find a copy of Sungorus 1.4 read through the PST init code and replace the values of line[] with this:

Code: Select all

{ 0, 46, 2076, 2595, 2890, 2312, 320, 0 }
Yes, those were the values that I was given by CLOP. I really think I should redo the search and eval to my liking - the Sungorus author has forgotten the rule of 'Premature optimization is the root of all evil'.

Matthew:out
The evaluation is not very good because I tried to focus more on the search. I didn't actually optimize the evaluation at all. I just wrote something as small as I could with the most essential features. If you want to improve it, you will most likely have to rewrite the evaluation completely. Rodent is a good example of how to do this.
mar
Posts: 2675
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: [Entertainment] When tuning goes wrong...

Post by mar »

Ron Murawski wrote: Hi Martin,

I have the same square numbering and I do not consider it a mistake. I wrote a simple macro
#define CHESS_RANK(rank) (7 - (rank))
using the macro, I can compare CHESS_RANKs directly.

If you write:
if ( CHESS_RANK(a) < CHESS_RANK(b) )
the macro expands to:
if ( (7 - (a)) < (7 - (b)) )
and now, when you compile, a good optimizer will eliminate the useless subtraction transforming it to:
if ( -a < -b )
and now the optimizer is smart enough to realize that this can be transformed (ie: optimized again) into:
if ( a > b )
which means that the macro will execute with no delay. Best of all, your original source code is now clear and agrees with normal chess convention.

Ron
Hi Ron, that's an interesting remark and an elegant solution. I wouldn't expect optimizers to be that good today.
If I used A1=0 and H8 = 63, I wouldn't have to bother at all.
I got rid of rank comparisons like a < b and only use equality/inequality comparisons now.
The only hack I have now is relative rank conversion is passer eval, where I do something ugly now like rr = relrank(square) ^ rank1, I will probably hide it and write a separate function for that.
@Lucas: I too considered using operators as my code is C++, but I don't really want to do that for a simple enum. That's like using a hammer to kill a mosquitto IMHO. It makes sense for 3d vectors for example, but in this case I just don't know. On the other hand, using strong typing is good in that it prevents you from bugs at compile time.
I'm using full warning levels now and it too helped to catch some bugs even before I had to debug the program. It's also good to use two different compilers from time to time.
The only problem is that I had to disable one silly warning specific to msc, namely "conditional expression is constant warning" because of templates.
Also I absolutely love valgrind, which helped me to get rid of other potential problems.

Martin
Ron Murawski
Posts: 397
Joined: Sun Oct 29, 2006 4:38 am
Location: Schenectady, NY

Re: [Entertainment] When tuning goes wrong...

Post by Ron Murawski »

mar wrote:
Ron Murawski wrote: Hi Martin,

I have the same square numbering and I do not consider it a mistake. I wrote a simple macro
#define CHESS_RANK(rank) (7 - (rank))
using the macro, I can compare CHESS_RANKs directly.

If you write:
if ( CHESS_RANK(a) < CHESS_RANK(b) )
the macro expands to:
if ( (7 - (a)) < (7 - (b)) )
and now, when you compile, a good optimizer will eliminate the useless subtraction transforming it to:
if ( -a < -b )
and now the optimizer is smart enough to realize that this can be transformed (ie: optimized again) into:
if ( a > b )
which means that the macro will execute with no delay. Best of all, your original source code is now clear and agrees with normal chess convention.

Ron
Hi Ron, that's an interesting remark and an elegant solution. I wouldn't expect optimizers to be that good today.
Trust your compiler! It optimizes much better than you think.
mar wrote: If I used A1=0 and H8 = 63, I wouldn't have to bother at all.
But then you need to stand on your head and flip things around so you can understand the bitboard layout. I prefer code that uses the most easily understood data structures.
mar wrote: I got rid of rank comparisons like a < b and only use equality/inequality comparisons now.
But now you can use them again! ;-)
mar wrote: The only hack I have now is relative rank conversion is passer eval, where I do something ugly now like rr = relrank(square) ^ rank1, I will probably hide it and write a separate function for that.
It's pretty easy to flip the board square
#define FLIP(sq) ((sq) ^ 0x38) // vertical swap
and then calculate the rank of the FLIPped square.

BTW: All of these macros can be implemented as inline functions so you can enforce type-checking. I actually use inline functions rather than macros in my code, but I wanted to show comprehensible one-liners as examples.

Ron
mar
Posts: 2675
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: [Entertainment] When tuning goes wrong...

Post by mar »

Ron Murawski wrote:Trust your compiler! It optimizes much better than you think.
Yes, today's compilers are amazing. It happened to me that the compiler produced better code than my handwritten assembly inner loop (mine was 1/2 insns better but still measurably slower, not much). Wouldn't happen 10+ years ago :)
Of course one has to be careful sometimes:
Division by power of two constant is converted to right shift - only partially true. Extra work (rounding) is required when dividend is signed, -1 >>(arithmetic)n is -1, not 0. No problem for unsigned division.
I've seen cases where it was better to separate the most inner loop, otherwise the compiler tried to optimize everything together and failed (this may depend on the compiler used of course).
Ron Murawski wrote:
mar wrote: If I used A1=0 and H8 = 63, I wouldn't have to bother at all.
But then you need to stand on your head and flip things around so you can understand the bitboard layout. I prefer code that uses the most easily understood data structures.
Not really. All I'd have to flip would be the underlying 8x8 representation, which is no problem at all, I only use it to quickly lookup piece at certain square. The only problem I can see is that mask initialization code which assumes that shl moves down would have to be rewritten (and all code that assumes the same, including hardcoded constants).
Ron Murawski wrote: It's pretty easy to flip the board square
#define FLIP(sq) ((sq) ^ 0x38) // vertical swap
and then calculate the rank of the FLIPped square.
Yes, obviously. But I don't see a difference between doing a square flip, then extract rank and between extracting rank then doing the flip.
In fact, better is not to have to flip anything at all :wink:
lucasart
Posts: 3243
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: [Entertainment] When tuning goes wrong...

Post by lucasart »

mar wrote:
Ron Murawski wrote: Division by power of two constant is converted to right shift - only partially true. Extra work (rounding) is required when dividend is signed, -1 >>(arithmetic)n is -1, not 0. No problem for unsigned division.
Isn't that why they invented the SAR operand on x86 ? SHR is only OK for unsigned, you're right. On 80386 (IIRC ?) both instructions take 1 cycle. So really you shouldn't care about that.
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.
User avatar
hgm
Posts: 28464
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: [Entertainment] When tuning goes wrong...

Post by hgm »

The problem is that dividing by 2 through ASR rounds towards -infinity, while dividing by 2 through the C '/' operator is expected to round towards zero.
mar
Posts: 2675
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: [Entertainment] When tuning goes wrong...

Post by mar »

lucasart wrote: Isn't that why they invented the SAR operand on x86 ? SHR is only OK for unsigned, you're right. On 80386 (IIRC ?) both instructions take 1 cycle. So really you shouldn't care about that.
I see HGM already explained, but anyway: sar does the same as shr except that it preserves sign (=the most significant bit). So for example division by 2 would work fine using sar until you get -1. -1 sar 1 remains -1, not 0 (assuming 2's complement). But I'm not sure what does the C/C++ standard say about right shifts on signed integers.
lucasart
Posts: 3243
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: [Entertainment] When tuning goes wrong...

Post by lucasart »

hgm wrote:The problem is that dividing by 2 through ASR rounds towards -infinity, while dividing by 2 through the C '/' operator is expected to round towards zero.
You're right:
http://faydoc.tripod.com/cpu/sar.htm
So why did they invent SAR / SAL if it's exactly the same as SHR / SHL ?
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.
mar
Posts: 2675
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: [Entertainment] When tuning goes wrong...

Post by mar »

lucasart wrote:
hgm wrote:The problem is that dividing by 2 through ASR rounds towards -infinity, while dividing by 2 through the C '/' operator is expected to round towards zero.
You're right:
http://faydoc.tripod.com/cpu/sar.htm
So why did they invent SAR / SAL if it's exactly the same as SHR / SHL ?
SAL is the same as SHL (I guess it's only a different name for the same opcode), but SAR and SHR are different: SAR keeps MSBit while SHR zeroes it.