Questions for BB / Zach

Code, algorithms, languages, construction...
User avatar
Rebel
Posts: 515
Joined: Wed Jun 09, 2010 7:45 pm
Real Name: Ed Schroder

Re: Questions for BB / Zach

Post by Rebel » Fri Jul 29, 2011 8:38 pm

zwegner wrote: 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.
Thank you Zach.
zwegner wrote: 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?
Sorry for undermining your work at the Rybka forum but I just found the repeated yell "read the document and compare the columns" in order to strengthen a point to be become a problem for honest information distribution.

If you find the time please replace the code in the PST section with the Fruit and Rybka PST's.

zwegner
Posts: 57
Joined: Thu Jun 10, 2010 5:38 am

Re: Questions for BB / Zach

Post by zwegner » Sat Jul 30, 2011 3:02 am

Rebel wrote:
zwegner wrote: 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.
Thank you Zach.
zwegner wrote: 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?
Sorry for undermining your work at the Rybka forum but I just found the repeated yell "read the document and compare the columns" in order to strengthen a point to be become a problem for honest information distribution.
Sure, that's no problem. I share your concern about honest information distribution, but I really doubt you'll get much of that accomplished on the Rybka forum. :) I disagree with some of what Bob says, but with the amount of nonsense coming from the other direction there, I don't blame him for sometimes going over the top. As I said there, it's probably best if everybody just stops talking about it.
If you find the time please replace the code in the PST section with the Fruit and Rybka PST's.
I don't think this is the right way to present the information. The similarities are not obvious at all to the naked eye--I didn't even notice it until I tried to decode the tables (after which I realized that Jury had already done it for Strelka 2--just not in Strelka 1.8, which is what I had been looking at). I can certainly see how my current layout can be misleading. Looking back at the current state of the documents on my hard drive, I chose to delete nearly all the code on the Rybka side and instead just put the constants, i.e. the code that must be changed in Fruit to calculate the Rybka PSTs. I think this is probably the best compromise, since it forces people to actually read all the text...

BB+
Posts: 1484
Joined: Thu Jun 10, 2010 4:26 am

Re: Questions for BB / Zach

Post by BB+ » Sat Jul 30, 2011 6:27 am

I am agreement that ZW should have explained the "Rybka code" better in the document (he had done so in forum posts, I think). If nothing else, it is an "Occam's Razor" explanation of the Rybka PST values, which can either be accepted or rejected by the reader. My own preference for presentation of this was the "templates" given in the RYBKA_FRUIT document.

My general attitude toward evidence presented by others was to let them speak in their own words, and not be overly critical about their phrasing, at least to the extent that I could understand what they meant. [I do the same with math papers: I had one incident where colleague X was annoyed that I had let co-author Y be rather cavalier in his statement for a press release -- if the press had quoted me, I would have been more careful].

On another note, I much prefer the 64-bit version, where cvtsi2sd/comisd do the loading/comparison in the xmm registers:

Code: Select all

0x0000000000406c8a:     movdqa %xmm6,-0x38(%rax)  # save the xmm6 value
0x0000000000406c8f:     xorpd  %xmm6,%xmm6        # and set it to 0.0
[...]
0x0000000000406fb9:     cvtsi2sd %ebx,%xmm0       # load "movetime" in xmm0
0x0000000000406fbd:     test   %eax,%eax          # other instructions, from previous code block
0x0000000000406fbf:     cmovne %edi,%r14d         # ...
0x0000000000406fc3:     test   %eax,%eax          # ...
0x0000000000406fc5:     cmovne %esi,%r12d         # ...
0x0000000000406fc9:     mov    0x80(%rsp),%rsi    # ...
0x0000000000406fd1:     comisd %xmm6,%xmm0        # compare to 0.0
0x0000000000406fd5:     movdqa 0x30(%rsp),%xmm6   # restore the xmm6 value
0x0000000000406fdb:     jbe    0x406ff4           # jump if below-or-equal [as Wylie said]
0x0000000000406fdd:     lea    (%rbx,%rbx,4),%eax # multiply by 5
0x0000000000406fe0:     imul   $0x3e8,%ebx,%ebx   # multiply by 1000
[...]
One can also note that the enusing (time > 0) comparison is strict in the comparison, so most likely Rick Fadden was just wrong about (movetime >= 0.0), when it should have been (movetime > 0.0) (given the technical details of tracking this down, I don't necessarily blame him).

Gerd made a comment about the floating-point comparison back in 2008: http://talkchess.com/forum/viewtopic.ph ... s&p=213809

I think the whole "0.0" question is a bit over-blown in any event (at least at this stage -- earlier, it was useful in giving investigators some sense that further investigation might not be a waste of time, somewhat like the setjmp usage, I guess).

hyatt
Posts: 1242
Joined: Thu Jun 10, 2010 2:13 am
Real Name: Bob Hyatt (Robert M. Hyatt)
Location: University of Alabama at Birmingham
Contact:

Re: Questions for BB / Zach

Post by hyatt » Sat Jul 30, 2011 6:02 pm

Rebel wrote:
BB+ wrote:Looks like an endian problem?
Yes :mrgreen:

Good thinking...
I wrote a program to search thru rybka for certain patterns. This drove me nuts. Nobody stores a 64 bit number like X86 does it. :) Sort of inside-out and sideways come to mind...

It is particularly messy if you search for a 64 bit pattern and it is not aligned on an 8 byte boundary...

hyatt
Posts: 1242
Joined: Thu Jun 10, 2010 2:13 am
Real Name: Bob Hyatt (Robert M. Hyatt)
Location: University of Alabama at Birmingham
Contact:

Re: Questions for BB / Zach

Post by hyatt » Sat Jul 30, 2011 6:08 pm

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.

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.
Two things. First, any good optimizing compiler will produce a dependency graph and notice that the result of the if test does nothing, which means that the if test itself does nothing.

I don't know if you have programmed any FP stuff on X86, but compares are ridiculous. First comes the usual FCOMP, or its cousin. But that sets the status flags in the FPU. Then the FSTSW ax takes the 16 bit floating point flag (status) register and stores it in AX. Now you have to do a normal compare or test on AX to check the bits you are interested in. About as ridiculous as it gets in computer architecture. The point being, that comparing against 0 gets rid of all the FP nonsense.. So why would a "good programmer" do it unless it was an oversight left over from previous modifications?

hyatt
Posts: 1242
Joined: Thu Jun 10, 2010 2:13 am
Real Name: Bob Hyatt (Robert M. Hyatt)
Location: University of Alabama at Birmingham
Contact:

Re: Questions for BB / Zach

Post by hyatt » Sat Jul 30, 2011 6:11 pm

wgarvin wrote:
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.

Also, the compiler did a _really_ lousy job of optimizing there. Why not do this:

FILD integer_value
FLDZ ;put 0.0 on top of stack, no 8-byte memory fetch needed.
FCMP ;which compares st(0) to st(1)..

who knows why that was not done...

hyatt
Posts: 1242
Joined: Thu Jun 10, 2010 2:13 am
Real Name: Bob Hyatt (Robert M. Hyatt)
Location: University of Alabama at Birmingham
Contact:

Re: Questions for BB / Zach

Post by hyatt » Sat Jul 30, 2011 6:17 pm

BB+ wrote:I am agreement that ZW should have explained the "Rybka code" better in the document (he had done so in forum posts, I think). If nothing else, it is an "Occam's Razor" explanation of the Rybka PST values, which can either be accepted or rejected by the reader. My own preference for presentation of this was the "templates" given in the RYBKA_FRUIT document.

My general attitude toward evidence presented by others was to let them speak in their own words, and not be overly critical about their phrasing, at least to the extent that I could understand what they meant. [I do the same with math papers: I had one incident where colleague X was annoyed that I had let co-author Y be rather cavalier in his statement for a press release -- if the press had quoted me, I would have been more careful].

On another note, I much prefer the 64-bit version, where cvtsi2sd/comisd do the loading/comparison in the xmm registers:

Code: Select all

0x0000000000406c8a:     movdqa %xmm6,-0x38(%rax)  # save the xmm6 value
0x0000000000406c8f:     xorpd  %xmm6,%xmm6        # and set it to 0.0
[...]
0x0000000000406fb9:     cvtsi2sd %ebx,%xmm0       # load "movetime" in xmm0
0x0000000000406fbd:     test   %eax,%eax          # other instructions, from previous code block
0x0000000000406fbf:     cmovne %edi,%r14d         # ...
0x0000000000406fc3:     test   %eax,%eax          # ...
0x0000000000406fc5:     cmovne %esi,%r12d         # ...
0x0000000000406fc9:     mov    0x80(%rsp),%rsi    # ...
0x0000000000406fd1:     comisd %xmm6,%xmm0        # compare to 0.0
0x0000000000406fd5:     movdqa 0x30(%rsp),%xmm6   # restore the xmm6 value
0x0000000000406fdb:     jbe    0x406ff4           # jump if below-or-equal [as Wylie said]
0x0000000000406fdd:     lea    (%rbx,%rbx,4),%eax # multiply by 5
0x0000000000406fe0:     imul   $0x3e8,%ebx,%ebx   # multiply by 1000
[...]
One can also note that the enusing (time > 0) comparison is strict in the comparison, so most likely Rick Fadden was just wrong about (movetime >= 0.0), when it should have been (movetime > 0.0) (given the technical details of tracking this down, I don't necessarily blame him).

Gerd made a comment about the floating-point comparison back in 2008: http://talkchess.com/forum/viewtopic.ph ... s&p=213809

I think the whole "0.0" question is a bit over-blown in any event (at least at this stage -- earlier, it was useful in giving investigators some sense that further investigation might not be a waste of time, somewhat like the setjmp usage, I guess).

I have pointed out to the "bozo crowd" on the Rybka forum that the first page of Zach's report is quite clear. One program has run-time initialization, one has static (compile-time) initialization. You can't compare code and numbers. And just comparing the two PSTs is anything but intuitive. I like the current approach of "this code produces the Fruit numbers exactly and comes from Fruit (in pst.cpp). This code is the same as fruit except for the constants at the top, and it produces the RYBKA PST values. That really shows the similarity well.

Some arguments over there are intentionally disingenuous. Chris trying to divide matching numbers from each table to see what the "multiplier is" although he doesn't know what was truncated or rounded. It is all an attempt to confuse and make it appear that none of the data is the same. I doubt anyone here can fix that problem.

mjlef
Posts: 43
Joined: Thu Jun 10, 2010 6:51 pm
Real Name: Mark Lefler

Re: Questions for BB / Zach

Post by mjlef » Sun Jul 31, 2011 9:42 am

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.
For reference here is a PDF version of Zach's document:

http://icga.wikispaces.com/file/view/ZW_Rybka_Fruit.pdf

I think some here have quoted the sample code and not the whole document. I think Zach makes clear the Rybka "code" is created to show the PST value similarities. The PST section starts with:

"Piece square tables are a very simple technique used for basic evaluation. For every piece type and square, PSTs
have a value for that piece being on that square. Fruit uses a clear and simple but effective way of calculating the
tables. Looking at Rybka's PSTs, we will see that they are calculated using these exact same constants except with
different weights. 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."

hyatt
Posts: 1242
Joined: Thu Jun 10, 2010 2:13 am
Real Name: Bob Hyatt (Robert M. Hyatt)
Location: University of Alabama at Birmingham
Contact:

Re: Questions for BB / Zach

Post by hyatt » Sun Jul 31, 2011 6:35 pm

"irrelevant, confusing, therefore it should be ignored" seems to be the primary response to pointing out the first page of that report. You can tell 'em to read it all you want. But apparently most don't have the requisite skill to follow up and actually read, starting at page 1.

User avatar
Rebel
Posts: 515
Joined: Wed Jun 09, 2010 7:45 pm
Real Name: Ed Schroder

Re: Questions for BB / Zach

Post by Rebel » Mon Aug 01, 2011 11:46 am

BB+ wrote:I am agreement that ZW should have explained the "Rybka code" better in the document (he had done so in forum posts, I think). If nothing else, it is an "Occam's Razor" explanation of the Rybka PST values, which can either be accepted or rejected by the reader. My own preference for presentation of this was the "templates" given in the RYBKA_FRUIT document.

My general attitude toward evidence presented by others was to let them speak in their own words, and not be overly critical about their phrasing, at least to the extent that I could understand what they meant. [I do the same with math papers: I had one incident where colleague X was annoyed that I had let co-author Y be rather cavalier in his statement for a press release -- if the press had quoted me, I would have been more careful].

On another note, I much prefer the 64-bit version, where cvtsi2sd/comisd do the loading/comparison in the xmm registers:

Code: Select all

0x0000000000406c8a:     movdqa %xmm6,-0x38(%rax)  # save the xmm6 value
0x0000000000406c8f:     xorpd  %xmm6,%xmm6        # and set it to 0.0
[...]
0x0000000000406fb9:     cvtsi2sd %ebx,%xmm0       # load "movetime" in xmm0
0x0000000000406fbd:     test   %eax,%eax          # other instructions, from previous code block
0x0000000000406fbf:     cmovne %edi,%r14d         # ...
0x0000000000406fc3:     test   %eax,%eax          # ...
0x0000000000406fc5:     cmovne %esi,%r12d         # ...
0x0000000000406fc9:     mov    0x80(%rsp),%rsi    # ...
0x0000000000406fd1:     comisd %xmm6,%xmm0        # compare to 0.0
0x0000000000406fd5:     movdqa 0x30(%rsp),%xmm6   # restore the xmm6 value
0x0000000000406fdb:     jbe    0x406ff4           # jump if below-or-equal [as Wylie said]
0x0000000000406fdd:     lea    (%rbx,%rbx,4),%eax # multiply by 5
0x0000000000406fe0:     imul   $0x3e8,%ebx,%ebx   # multiply by 1000
[...]
One can also note that the enusing (time > 0) comparison is strict in the comparison, so most likely Rick Fadden was just wrong about (movetime >= 0.0), when it should have been (movetime > 0.0) (given the technical details of tracking this down, I don't necessarily blame him).

Gerd made a comment about the floating-point comparison back in 2008: http://talkchess.com/forum/viewtopic.ph ... s&p=213809

I think the whole "0.0" question is a bit over-blown in any event (at least at this stage -- earlier, it was useful in giving investigators some sense that further investigation might not be a waste of time, somewhat like the setjmp usage, I guess).
Thanks Mark, this makes sense. Also wgarvin comments.

Solly (as my youngest granddaughter is used to say) for the delay, Rybka forum is very time consuming nowadays.

Post Reply