Page 1 of 2

Questions for BB / Zach

Posted: Fri Jul 29, 2011 7:34 am
by Rebel
Fruit - eval.cpp
static const int KingAttackWeight[16] = {
0, 0, 128, 192, 224, 240, 248, 252, 254, 255, 256, 256 ,256, 256, 256, 256,

Strelka - consts.c
const int KingAttackWeight[16] = {
0,-1,37,71,100,100,100,100,100,100,100,100,100,100,100,100

How does the Rybka table look like ?

I am missing that in the Zach document.

---------------------

Now that we are talking perhaps you could explain something else to me about the PST's in Fruit / Strelka. It's about this fragment in the Zach document:

Code: Select all

 Also, note that here too that the PST values are hardcoded into the Rybka executable file, they are not calculated at startup like Fruit's. The code shown here is simply the functional equivalent; it calculates the Rybka PSTs.
This reads as that there is no PST calculation code in Rybka at all, correct ?

That the PST tables are ready to use, pre-calculated and stored into the C-source.

Do I have this right ?

----------------------

Third question, the notorious "0.0" in the Time Control. Can you show me the offsets in the executables of Fruit and Rybka 1.0 beta (32-bit) ?

Re: Questions for BB / Zach

Posted: Fri Jul 29, 2011 7:59 am
by BB+
Strelka - consts.c
const int KingAttackWeight[16] = {
0,-1,37,71,100,100,100,100,100,100,100,100,100,100,100,100
How does the Rybka table look like ?
The same. The is quasi-documented in the ICGA datadump, in that the R1/R232a differences PDF lists:

Code: Select all

   Rybka 1.0 Beta: {0, -1, 37, 71, 100, 100, 100, ...}
   Rybka 2.3.2a:   {0,  0  30, 57,  81,  81,  81, ...}
I can chase down the executable locations, if you want.
This reads as that there is no PST calculation code in Rybka at all, correct ?
That the PST tables are ready to use, pre-calculated and stored into the C-source.
Do I have this right ?
This is correct. Rybka just has tables. I'm not even sure they are even in the C source -- presumably one could link them in at a later stage if desired. 8-)
Third question, the notorious "0.0" in the Time Control. Can you show me the offsets in the executables of Fruit and Rybka 1.0 beta (32-bit) ?
I'm not sure there is a "canonical" Fruit executable. In any event, the instruction should be fnstsw. For Rybka, this appears in Rick Fadden's disassembly at 0x4097F0. Running objdump on the Fruit 2.1 executable turned up about 5 places in parse_go with this instruction. The relevant source code is:

Code: Select all

   if (movetime >= 0.0) { // fixed time
      SearchInput->time_is_limited = true;
      SearchInput->time_limit_1 = movetime * 5.0; // HACK to avoid early exit
      SearchInput->time_limit_2 = movetime;
I have never looked at the 32-bit dumps too closely, so Zach would know more.

Re: Questions for BB / Zach

Posted: Fri Jul 29, 2011 8:38 am
by Rebel
Mark, thanks so much for answers and all your work.

Just one thing,
Ed wrote:This reads as that there is no PST calculation code in Rybka at all, correct ?
That the PST tables are ready to use, pre-calculated and stored into the C-source.
Do I have this right ?
This is correct. Rybka just has tables. I'm not even sure they are even in the C source -- presumably one could link them in at a later stage if desired. 8-)
The latter could be true as well, I agree.

But the point I want to make here is that the document for the layman reader is pretty misleading then. People are reading that left column (Fruit) and then the right column (Rybka), see the similarities in a glance and conclude: Vas indeed is a thief. Reality is that the right column in the PST chapter should be totally empty because there is no such code at all in Rybka.

I think the document needs a rewrite regarding the PST chapter to be creditable.

Re: Questions for BB / Zach

Posted: Fri Jul 29, 2011 9:27 am
by Rebel
BB+ wrote:

Code: Select all

   Rybka 1.0 Beta: {0, -1, 37, 71, 100, 100, 100, ...}
   Rybka 2.3.2a:   {0,  0  30, 57,  81,  81,  81, ...}
Can't find 0, -1, 37 in the Rybka 1.0 beta W32 executable, not in 32 bit, nor in 16 bit.

Searched for: 00000000 ffffffff 00000025
And: 0000 ffff 0025

My bad ?
BB+ wrote: I can chase down the executable locations, if you want.
If needed to clarify, please yes.

Re: Questions for BB / Zach

Posted: Fri Jul 29, 2011 9:51 am
by BB+
Looks like an endian problem?

Here's what I got from the 64-bit version when loaded:

Code: Select all

(gdb) x/16bx 0x662e80
0x662e80:	0x00	0x00	0x00	0x00	0xff	0xff	0xff	0xff
0x662e88:	0x25	0x00	0x00	0x00	0x47	0x00	0x00	0x00
And from the R1w32.exe binary:

Code: Select all

00260CB0                             00 00 00 00  FF FF FF FF  ................
00260CC0   25 00 00 00  47 00 00 00  64 00 00 00  64 00 00 00  %...G...d...d...
00260CD0   64 00 00 00  64 00 00 00  64 00 00 00  64 00 00 00  d...d...d...d...
00260CE0   64 00 00 00  64 00 00 00  64 00 00 00  64 00 00 00  d...d...d...d...
00260CF0   64 00 00 00  64 00 00 00

Re: Questions for BB / Zach

Posted: Fri Jul 29, 2011 10:09 am
by Rebel
BB+ wrote:Looks like an endian problem?
Yes :mrgreen:

Good thinking...

Re: Questions for BB / Zach

Posted: Fri Jul 29, 2011 10:50 am
by marcelk
Rebel wrote:Mark, thanks so much for answers and all your work.

Just one thing,
Ed wrote:This reads as that there is no PST calculation code in Rybka at all, correct ?
That the PST tables are ready to use, pre-calculated and stored into the C-source.
Do I have this right ?
This is correct. Rybka just has tables. I'm not even sure they are even in the C source -- presumably one could link them in at a later stage if desired. 8-)
The latter could be true as well, I agree.

But the point I want to make here is that the document for the layman reader is pretty misleading then. People are reading that left column (Fruit) and then the right column (Rybka), see the similarities in a glance and conclude: Vas indeed is a thief. Reality is that the right column in the PST chapter should be totally empty because there is no such code at all in Rybka.

I think the document needs a rewrite regarding the PST chapter to be creditable.
This was discussed during the investigation phase. From my point of view as a reader,
and within the context of the deliberations and other documents at the time, it has
always been my understanding of the PST comparison (which as I remember was
already contained in the documents that prompted the programmer's letter to the icga)
that Rybka's tables are derived from Fruit's (or a common ancestor, but no defense was
made in that direction). It was not about the code to instantiate these tables which is
irrelevant at that abstraction level, which should be clear by the panel members at the
time. One expression is just a translation of the other. Code = data and data = code,
Niklaus Wirth popularized this insight almost half a century ago.

Mind that the technical documents are not to be read 'at a glance' by a 'layman', not
even so by engine programmers. Of course you are free to rewrite them as you desire
to address other audiences as well.

Your question is approaching some of the detail of the deliberations that were made
within the panel, which is nice but you might consult the discussions of the time then
as well to get up to speed (better would have been to have joined them as they were
happening). For example, the comparison of the king attack array was noted and discussed
specifically and I would even say that that discussion alone led to the quantification
exercise and also the discussion regarding rule #2 vs. copyright, which was emphasized
as to be separate issues.

Re: Questions for BB / Zach

Posted: Fri Jul 29, 2011 11:05 am
by Rebel
BB+ wrote: I'm not sure there is a "canonical" Fruit executable. In any event, the instruction should be fnstsw. For Rybka, this appears in Rick Fadden's disassembly at 0x4097F0. Running objdump on the Fruit 2.1 executable turned up about 5 places in parse_go with this instruction. The relevant source code is:

Code: Select all

   if (movetime >= 0.0) { // fixed time
      SearchInput->time_is_limited = true;
      SearchInput->time_limit_1 = movetime * 5.0; // HACK to avoid early exit
      SearchInput->time_limit_2 = movetime;
I have never looked at the 32-bit dumps too closely, so Zach would know more.
The Rick Fadden post was helpful, it actually states the below block of assembly should represent the notorious integer compare with 0.0

Code: Select all

 text:004097E6 loc_4097E6:                             ; CODE XREF: Start_Go+2BCj 
.text:004097E6                 fild    [esp+2Ch+movetime] 
.text:004097EA                 fcomp   ds:dbl_6623D0 
.text:004097F0                 fnstsw  ax 
.text:004097F2                 test    ah, 41h         ; 41h = 65 Decimal 
.text:004097F5                 jnz     short loc_40980E 
.text:004097F7                 lea     ecx, [esi+esi*4] 
.text:004097FA                 imul    esi, 3E8h       ; 3E8h = 1000 Decimal 
.text:00409800                 mov     time_limit_1, ecx 
.text:00409806                 mov     time_limit_2, esi 
.text:0040980C                 jmp     short loc_409846 
With all the best will in the world, it does not read as if (movetime >= 0.0)

Perhaps Gerd can shed his light on this one.

Also I made a simple program:

main (argc,argv)
int argc; char *argv[];
{ int test=0;
if (test >= 0.0) { };
}

My compiler simply returned:

public _main
_TEXT segment
assume CS:_TEXT
_main:
xor EAX,EAX
ret

How nice, no complicated fnstsw stuff.

Re: Questions for BB / Zach

Posted: Fri Jul 29, 2011 2:18 pm
by wgarvin
Rebel wrote:
BB+ wrote: I'm not sure there is a "canonical" Fruit executable. In any event, the instruction should be fnstsw. For Rybka, this appears in Rick Fadden's disassembly at 0x4097F0. Running objdump on the Fruit 2.1 executable turned up about 5 places in parse_go with this instruction. The relevant source code is:

Code: Select all

   if (movetime >= 0.0) { // fixed time
      SearchInput->time_is_limited = true;
      SearchInput->time_limit_1 = movetime * 5.0; // HACK to avoid early exit
      SearchInput->time_limit_2 = movetime;
I have never looked at the 32-bit dumps too closely, so Zach would know more.
The Rick Fadden post was helpful, it actually states the below block of assembly should represent the notorious integer compare with 0.0

Code: Select all

 text:004097E6 loc_4097E6:                             ; CODE XREF: Start_Go+2BCj 
.text:004097E6                 fild    [esp+2Ch+movetime] 
.text:004097EA                 fcomp   ds:dbl_6623D0 
.text:004097F0                 fnstsw  ax 
.text:004097F2                 test    ah, 41h         ; 41h = 65 Decimal 
.text:004097F5                 jnz     short loc_40980E 
.text:004097F7                 lea     ecx, [esi+esi*4] 
.text:004097FA                 imul    esi, 3E8h       ; 3E8h = 1000 Decimal 
.text:00409800                 mov     time_limit_1, ecx 
.text:00409806                 mov     time_limit_2, esi 
.text:0040980C                 jmp     short loc_409846 
With all the best will in the world, it does not read as if (movetime >= 0.0)

Perhaps Gerd can shed his light on this one.
I can take a stab at it.

Here's the comparison instructions, and I have added a comment after each one describing what it does:

Code: Select all

.text:004097E6     fild    [esp+2Ch+movetime]        ; Load the movetime variable onto FP stack
.text:004097EA     fcomp   ds:dbl_6623D0             ; Compare ST(0) (the top of FP stack) with a constant from memory
                                                     ; (at ds:0x6623D0 you'll presumably find the binary value for 0.0)
.text:004097F0     fnstsw  ax                        ; Copy FPU status word into AX
.text:004097F2     test    ah, 41h                   ; test the C0 and C3 bits of the FPU status word
.text:004097F5     jnz     short loc_40980E 
Note that FILD loads a 32-bit integer value and converts it into a float.

I found this table that shows what the bits of the FPU status word mean. The AH register being tested is the upper 8-bits of the 16-bit AX register.

The 41h constant tested is a combination of the "C0" flag (bit 8 of the 16-bit status word) and the "C3" flag (bit 14). So basically the JNZ branch is taken if either C0 or C3 was set by the FCOMP. C0 will be set if (ST(0) < source) or the result of the comparison was undefined (i.e. NaN). C3 will be set if (ST(0) == source) or the result was undefined.

So basically, the FCOMP, FNSTSW, TEST and JNZ are equivalent to this code:

Code: Select all

if (movetime <= 0.0 || (movetime is NaN)))
    goto loc_40980E;
It looks equivalent to:

Code: Select all

if (movetime > 0.0)
{
    // ... do stuff
}
loc_40980E:;
Notice that it looks to me like the Rybka code is equivalent to "if (movetime > 0.0)", not like "if (movetime >= 0.0)". Unless I made a mistake when parsing it.. I don't know why it would have been changed. I think if the compiler really wanted to test (movetime >= 0.0) it could have tested AH against 21h instead of 41h to accomplish that.

Rebel wrote: Also I made a simple program:

main (argc,argv)
int argc; char *argv[];
{ int test=0;
if (test >= 0.0) { };
}

My compiler simply returned:

public _main
_TEXT segment
assume CS:_TEXT
_main:
xor EAX,EAX
ret

How nice, no complicated fnstsw stuff.
The explanation is simple! :lol: Your compiler is smarter than the one that was used to compile Rybka 1.0 Beta. My guess is that it was compiled with either the ancient Microsoft VC 6 compiler (from last century), or VC 7.0 (which is from 2002) or VC 7.1 (which is from 2003). [Edit: actually, even VC 6 might have optimized away your if-test. You didn't put any code inside the curly brackets, and movetime is not volatile, so the compiler knows that there's no side effects at all from the comparison or the if-statement body. It knows that its dead code, and it optimizes it away. The assembly it outputted just does "return 0;". ]

Compiler options can also have an effect on what gets generated. For example, there are other ways of testing the result of a floating-point comparison done in the x87 registers; but you would have to tell the compiler that your targeted CPU was at least a Pentium II or it would not be allowed to use them. I'm not sure whether it would even use them anyway; I don't have a copy of any of those three really old compilers anymore.

We did see signs that at least some of the initialization code in the Rybka 1.0 Beta appeared to have been compiled for Debug. Not just with a really stupid compiler, but with optimizations turned off. I can't imagine why though.
If you look at these disassembly listings on the ICGA wiki, you'll see a bunch of redundant instructions, and stuff like that. Here is a comment I posted when we were discussing it:
Wylie wrote:I just noticed the Rybka-Crafty Evidence III page that has been put up, and looked at the whole snippet. That has to have been compiled for debug. There's no loop induction var for (pawn_hash_table+i), there's a totally useless lea at 0x4520ea, and of course those retarded redundant loading of constants. It reloads the count to stop at from 0x6b8990 on every iteration.

I'm surprised that a chess engine would have debug-compiled code in it! Weird.
But Mark Watkins pointed out the purpose of the "totally useless lea at 0x4520ea" -- it is a multi-byte nop to align the first instruction of the loop.

Re: Questions for BB / Zach

Posted: Fri Jul 29, 2011 5:32 pm
by zwegner
Rebel wrote:Mark, thanks so much for answers and all your work.

Just one thing,
Ed wrote:This reads as that there is no PST calculation code in Rybka at all, correct ?
That the PST tables are ready to use, pre-calculated and stored into the C-source.
Do I have this right ?
This is correct. Rybka just has tables. I'm not even sure they are even in the C source -- presumably one could link them in at a later stage if desired. 8-)
The latter could be true as well, I agree.

But the point I want to make here is that the document for the layman reader is pretty misleading then. People are reading that left column (Fruit) and then the right column (Rybka), see the similarities in a glance and conclude: Vas indeed is a thief. Reality is that the right column in the PST chapter should be totally empty because there is no such code at all in Rybka.

I think the document needs a rewrite regarding the PST chapter to be creditable.
Point well taken. I had done most of a rewrite of my document to clean it up, be more specific in cases like this, and include Rybka disassembly as a middle column (or actual table values in cases like this). I put it on hold because, well, I'm lazy. :) Don't have much time for this these days.

This should definitely be cleaned up, but those that are claiming that the evidence is all fabricated and it's been magically debunked are rather ridiculous, to say the least. I mean, does the code on the right calculate the Rybka PSTs or not?