What is meant here by use of the phrase "smoking gun"? Is BB suggesting that the similarity here is so peculiarly close that this is evidence of code copying? Thus, a "smoking gun"? BB's commentary is a bit terse and vague. The section title "smoking gun" is obviously suggestive, but what exactly is being suggested here?5.3.1 IPPOLIT peculiarly has a leftover condition in the updating of positional gain,
in that it first checks whether a move is a capture, and if not, it then checks
whether it is a capture (again!) and the captured piece is a pawn; the latter is
exactly a condition (among many) in Rybka’s code, though it does appear in
the same place (at the start). Also, Rybka does (many) other things here when
a move is a capture, whereas IPPOLIT does nothing in this case.
This “could” be harmless: for instance, the IPPOLIT testers might have
been just trying many different combos here, and didn’t make the last deletion
of redundant code. Perhaps humourously, this “copied” code (if it is that) never
actually does anything in the end...
A Smoking Gun?
A Smoking Gun?
From BB report, Section 5.3.1:
Re: A Smoking Gun?
He is saying that this particular structure of code is unlikely to be written from scratch. The fact that Rybka has the same "mistake" means it's likely that the person writing Ippolit looked at the Rybka code in detail, and in this case, copied a mistake over.
From BB's analysis in general though, it looks pretty obvious that it's not a copy of the code. It has a similar structure, more similar than two random chess programs, but it's also quite different. To me, it looks like the person(s) writing it had an excellent understanding of chess programming, and didn't simply copy the ideas.
From BB's analysis in general though, it looks pretty obvious that it's not a copy of the code. It has a similar structure, more similar than two random chess programs, but it's also quite different. To me, it looks like the person(s) writing it had an excellent understanding of chess programming, and didn't simply copy the ideas.
Re: A Smoking Gun?
Then, it's all the more mysterious. It's not a clone, but there maybe there's some copying, but not wholesale copying, or perhaps copying with substantial changes. It hurts my brain.glinscott wrote:He is saying that this particular structure of code is unlikely to be written from scratch. The fact that Rybka has the same "mistake" means it's likely that the person writing Ippolit looked at the Rybka code in detail, and in this case, copied a mistake over.
From BB's analysis in general though, it looks pretty obvious that it's not a copy of the code. It has a similar structure, more similar than two random chess programs, but it's also quite different. To me, it looks like the person(s) writing it had an excellent understanding of chess programming, and didn't simply copy the ideas.
Re: A Smoking Gun?
No, I was just saying that this bit of code is exactly the same as a condition in Rybka (though what happens when the condition evaluates to true is different), and that the code does nothing in IPPOLIT, due to a prior condition. This could be evidence of something, or it could be that it once did something in IPPOLIT (before the prior conditions were added) and that it just wasn't removed in the final version. I'm sorry if my phrasing was a bit infelicitous to the non-Anglophone.He is saying that this particular structure of code is unlikely to be written from scratch.
Oops, now that I look at the original IPP_ENG.c, it seems that the condition actually does do something at that juncture, but that the prior condition was added by the time of RobboLito (at some point, I switched to using RL and later renditions as the base of comparison, as they are more readable, and only spot-checked versus the original). Shame on me for not double-checking.
Code: Select all
static void
white_gaining_updated (int move)
{
int itog, sh, d;
if (tower_dynamics->captured && position_fixed.square[((move) & 077)] != enumerated_black_pawns)
return;
sh = position_fixed.square[((move) & 077)];
d = move & 07777;
itog = ((tower_dynamics - 1)->positional) - tower_dynamics->positional;
if (increment_maximal[sh][d] < itog)
increment_maximal[sh][d] = itog;
else if (increment_maximal[sh][d] > itog)
increment_maximal[sh][d]--;
}
Code: Select all
static void
truffa_bianca (int mossa)
{
int v, p, m;
if (DINAMICO->cattura)
return;
if (DINAMICO->cattura && QU[AI (mossa)] != conto_pedone_nero)
return;
p = QU[AI (mossa)];
m = mossa & 07777;
v = ((DINAMICO - 1)->valu_posizionale) - DINAMICO->valu_posizionale;
if (massimo_posizionale_guadagno[p][m] < v)
massimo_posizionale_guadagno[p][m] = v;
else if (massimo_posizionale_guadagno[p][m] > v)
massimo_posizionale_guadagno[p][m]--;
}
Re: A Smoking Gun?
This is actually quite an interesting thing. This exact piece of code is one of the very few things that SF1.7 took verbatim from Ippo. They took just capture condition (not the pawn one) and added promotion and castling.
While promotion condition has sense, I don't see a point of castling condition.
The idea would be to update positional gain only if material has not been changed.
Including paws captures also doesn't look sound.
While promotion condition has sense, I don't see a point of castling condition.
The idea would be to update positional gain only if material has not been changed.
Including paws captures also doesn't look sound.
Re: A Smoking Gun?
OTOH, I don't see any compulsion to make the promotion comparison in this function, as the "positional gain" of e7e8q or the like is never going to become relevant, as the "special move" indicator should kick out promotions in any event. So I guess making the comparison at the point just means that you return immediately, rather than update something that will always(?) be unused, maybe saving some cycles.They took just capture condition (not the pawn one) and added promotion and castling.
While promotion condition has sense,
Stockfish 1.7 code:
Code: Select all
if ( m != MOVE_NULL
&& before != VALUE_NONE
&& after != VALUE_NONE
&& pos.captured_piece() == NO_PIECE_TYPE
&& !move_is_castle(m)
&& !move_is_promotion(m))
H.set_gain(pos.piece_on(move_to(m)), move_to(m), -(before + after));
}
Re: A Smoking Gun?
Since promotions are so rare, and gain is updated at every eval, I would say even with one cmp instruction, in total you are loosing cycles .BB+ wrote:OTOH, I don't see any compulsion to make the promotion comparison in this function, as the "positional gain" of e7e8q or the like is never going to become relevant, as the "special move" indicator should kick out promotions in any event. So I guess making the comparison at the point just means that you return immediately, rather than update something that will always(?) be unused, maybe saving some cycles.
Re: A Smoking Gun?
Is this condition described below one that would likely be discovered and replicated through disassembly of Rybka? Or is it more probable that this particular section of code was copied outright, the ippolit programmer having access to the Rybka source?
BB+ wrote:No, I was just saying that this bit of code is exactly the same as a condition in Rybka (though what happens when the condition evaluates to true is different), and that the code does nothing in IPPOLIT, due to a prior condition. This could be evidence of something, or it could be that it once did something in IPPOLIT (before the prior conditions were added) and that it just wasn't removed in the final version. I'm sorry if my phrasing was a bit infelicitous to the non-Anglophone.He is saying that this particular structure of code is unlikely to be written from scratch.
Oops, now that I look at the original IPP_ENG.c, it seems that the condition actually does do something at that juncture, but that the prior condition was added by the time of RobboLito (at some point, I switched to using RL and later renditions as the base of comparison, as they are more readable, and only spot-checked versus the original). Shame on me for not double-checking.Code: Select all
static void white_gaining_updated (int move) { int itog, sh, d; if (tower_dynamics->captured && position_fixed.square[((move) & 077)] != enumerated_black_pawns) return; sh = position_fixed.square[((move) & 077)]; d = move & 07777; itog = ((tower_dynamics - 1)->positional) - tower_dynamics->positional; if (increment_maximal[sh][d] < itog) increment_maximal[sh][d] = itog; else if (increment_maximal[sh][d] > itog) increment_maximal[sh][d]--; }
I might emphasise that I think (from making a rudimentary comparison and extrapolating) that there are only about 10 or 20 (minor) differences between IPP_ENG.c and RobboLito 0.084, but it seems that this is one of them. So in the end, the original IPP_ENG.C did have the same condition as Rybka (though a different action upon it being true), and it looks like it was only in RobboLito that the code became "redundant".Code: Select all
static void truffa_bianca (int mossa) { int v, p, m; if (DINAMICO->cattura) return; if (DINAMICO->cattura && QU[AI (mossa)] != conto_pedone_nero) return; p = QU[AI (mossa)]; m = mossa & 07777; v = ((DINAMICO - 1)->valu_posizionale) - DINAMICO->valu_posizionale; if (massimo_posizionale_guadagno[p][m] < v) massimo_posizionale_guadagno[p][m] = v; else if (massimo_posizionale_guadagno[p][m] > v) massimo_posizionale_guadagno[p][m]--; }
Re: A Smoking Gun?
I guess I'm still not saying this correctly: the condition in both Rybka and IPP_ENG.c is that the capturing piece is not a pawn. It seems I fouled this up more than once.
In Rybka, there is perhaps a reason for this, as instead of piece-to-from being an array of size 16*64*64, it is of size 7*64*64, with the 7 sets being: pawns, white king, black king, white queen, black queen, white RBN, black RBN (I forget what the order is). [This is table 0x5859a8 that appears in the code below]. So there is some sense to put captures by pawns in this table, as their style of movement will still be unique. One could make the same argument with IPPOLIT (that the (wP/bP)-to-from entries for caps and noncaps will be distinct), though it seems less satisfactory somehow, to me at least.
On the other hand, IPP_ENG.c just returns when the capture is by a non-pawn, while Rybka does much more (updating a different set of posgain-like arrays). Here is a sampling:
function WhiteEval 0x479610:
I tend to agree with Sentinel that doing "positional gain" for noncaptures and captures by pawns is not the first thing I would think of. I would think that simply noncaptures would be more obvious of a choice.Is this condition described below one that would likely be discovered and replicated through disassembly of Rybka? Or is it more probable that this particular section of code was copied outright, the ippolit programmer having access to the Rybka source?
In Rybka, there is perhaps a reason for this, as instead of piece-to-from being an array of size 16*64*64, it is of size 7*64*64, with the 7 sets being: pawns, white king, black king, white queen, black queen, white RBN, black RBN (I forget what the order is). [This is table 0x5859a8 that appears in the code below]. So there is some sense to put captures by pawns in this table, as their style of movement will still be unique. One could make the same argument with IPPOLIT (that the (wP/bP)-to-from entries for caps and noncaps will be distinct), though it seems less satisfactory somehow, to me at least.
On the other hand, IPP_ENG.c just returns when the capture is by a non-pawn, while Rybka does much more (updating a different set of posgain-like arrays). Here is a sampling:
function WhiteEval 0x479610:
Code: Select all
0x0047c4ff: mov 0x168(%rsp),%edi # black's last move
0x0047c506: test %edi,%edi # if NULL, then jump
0x0047c508: je 0x47c73f
0x0047c50e: mov 2418615(%rip),%r9d # 0x6caccc # cap piece from last move
0x0047c515: test %r9d,%r9d
0x0047c518: je 0x47c61b # if not a cap, jump
0x0047c51e: mov 0xe8(%rsp),%rcx # to-square
0x0047c526: mov 0x2cab20(%r13,%rcx,4),%eax # 6cab20 is the board
0x0047c52e: cmp $0x3,%eax # piece 3 is black pawn
0x0047c531: je 0x47c623 # if cap of pawn, jump
0x0047c537: mov 0x1859a8(%r13,%rax,4),%ecx # code for caps by nonpawns
0x0047c548: shl $0xc,%ecx # shift capturing piece by 12
0x0047c544: shl $0x6,%r9d # shift captured piece by 6
0x0047c53f: movzwl 0x[ffffff]ac(%rbp),%r10d # previous pos-gain
0x0047c54b: sub %r8w,%r10w # subtract current pos-gain
0x0047c54f: and $0x3f,%edi # to-square of move
[...] # omit about 50 lines
0x0047c601: movsbl 0x186e00(%rcx,%r13,1),%eax # 0x586e00 table reduces size of arg
0x0047c60a: sub %ax,%dx # subtract from running total
0x0047c60d: mov %dx,0x2ccd20(%r13,%rbx,4) # store 2 bytes in 0x6ccd20 table
0x0047c616: jmpq 0x47c786 # code for caps by piece done!
0x0047c61b: mov 0xe8(%rsp),%rcx # code for noncaps or caps by P
[...]