about pst

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: about pst

Post by Henk »

Don't understand what's simple about piece square table. Once I wrote code to update piece square tables and it became a mess soon. But perhaps evaluation cannot be written simple.
Daniel Anulliero
Posts: 759
Joined: Fri Jan 04, 2013 4:55 pm
Location: Nice

Re: about pst

Post by Daniel Anulliero »

hgm wrote:In my new engine Simple I even store the eg and op values in the same table (pst[7][64]) of 32-bit integers, as (op-eg/3)*N + eg, where N is the constant 2^16. I have a game phase that runs from 0 (eg) to 24 (op). In the evaluation I then calculate (8*N+gamePhase)*pstEval>>19. Some algebra shows that this is equal to

({N*N*8*(op-eg)/3} + N*(gamePhase*(op-eg)/3 + 8*eg) + gamePhase*eg) >> 19

The part in braces contains a factor 2^32, and is thus clipped off the 32-bit result by overflow. Shifting right by 16 bits pushes the term gamePhase*eg (which is smaller than 2^16, eg running only upto 4000 or so even if the piece ase value is included in the PST) out of the int, and undoes the multiplication by N on the remaining term, so that it would leave you with

gamePhase/3 * (op-eg) + 8*eg

(give or take some rounding), where gamePhase/3 runs from 0 to 8 (so let us call that 8*phi). The result is then

8*(phi*op + (1-phi)*eg)

which is 8 times the sought interpolated result. Currently the factor 8 is also removed by right-shifting 3 bits extra (19 instead of 16), but it occurred to me that this is really counterproductive, and that it would be better to let the engine use units of 1/800 or 1/400 Pawn internally than have it use centiPawn. Then I can more easily reduce drawish positions (like KNKP) to sub-Pawn values by dividing the score by 2, 4 or 8 without completely losing the smaller evaluation terms like centralization to rounding, so that the engine will continue to prefer good moves in the hope for an opponent mistake, rather than throwing in the towel and running his King towards a corner to sulk, because it no longer sees the corner is worse than the center.

The evaluation parameters other than the PST (like isolated-Pawn penalty, open-file bonus for Rooks) are also defined in this (op-eg)/2*N+eg format, so that I can add them all to the pstEval value first, and then use the formula above for interpolating to the current game phase.
Thanks hg very clever !
You're full again of ideas this year ... for normal chess but
Too high level for me and I would looove some explanations in french !😉
Bests
Dany
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: about pst

Post by bob »

Daniel Anulliero wrote:Is it better (or not) to have :

Code: Select all

pst_op [7][64] = {.....}  
pst_eg [7][64]
One array for all pièces

Or

pst_pawn_op [64]
pst_knight_op [64]
...
pst_knight_eg [64]
...
Etc..
One array for each pièces (white , find the black values with a flip [64] array just like in TSCP code)

What implementation is better in your advice ?
They are essentially equivalent. Speed-wise. etc.

If you have a separate procedure for evaluating each distinct type of piece, which most do to collect related things in one place, a simple array works. Crafty uses things like pval[phase][square], nval[phase][square] and so forth. Adding a piece subscript won't make it less efficient since the piece type is known where it is used. If you use just one pst score array (pst[phase][piece][square] for example) then the piece will add a multiply/add to the subscript calculation when the compiler turns it into asm. I doubt you will be able to measure that speed loss.

In these cases, I try to use that which is most readable. Since I have procedures named EvaluatePawns(), EvaluateKnights() and such, I have a different PST array for each piece type. One less subscript makes it easier to read for me.
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: about pst

Post by bob »

matthewlai wrote:
sje wrote:It is faster to flip a square index by an inline exclusive-or calculation than by a table look-up.
Don't quite follow that. It's not XOR vs table look-up.

It's XOR + table look-up vs table-lookup. Obviously not doing the XOR is faster.
No, you missed the square problem. You have to convert e4 to the equivalent black square (e5) to use a simple one dimensional PST, rather than having one for black and one for white. Flipping a square through an array reference is going to add cache misses since it will be done in between lots of other code being executed.

My knight pst looks like this:

const int nval[EG/MG][btm/wtm][square] which is 2x2x64
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: about pst

Post by bob »

matthewlai wrote:
Aleks Peshkov wrote:
matthewlai wrote:It's XOR + table look-up vs table-lookup. Obviously not doing the XOR is faster.
It is not so obvious. Bigger table potentially lead to more cache misses. But XOR may be completely free in many cases due computational parallelism in modern processors.
That is true. However, tables this size take up negligible L1D cache, and will stay there regardless.
Are you sure? 16/32/64K bytes of L1d is not very big when you factor in all the magic move generation references, hashing, board references and such. Has a better chance of sticking in L2, and almost always shold be in L3..
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Flipping squares

Post by sje »

Code: Select all

flipsq = Flip[sq];
is slower than

Code: Select all

flipsq = sq ^ 0x38;
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Flipping squares

Post by bob »

sje wrote:

Code: Select all

flipsq = Flip[sq];
is slower than

Code: Select all

flipsq = sq ^ 0x38;
For those that use 0-63 of course. :)

There are still a few mailboxers around.
AlvaroBegue
Posts: 931
Joined: Tue Mar 09, 2010 3:46 pm
Location: New York
Full name: Álvaro Begué (RuyDos)

Re: Flipping squares

Post by AlvaroBegue »

bob wrote:
sje wrote:

Code: Select all

flipsq = Flip[sq];
is slower than

Code: Select all

flipsq = sq ^ 0x38;
For those that use 0-63 of course. :)

There are still a few mailboxers around.
It's `sq ^ 0x70' for mailboxers.
AlvaroBegue
Posts: 931
Joined: Tue Mar 09, 2010 3:46 pm
Location: New York
Full name: Álvaro Begué (RuyDos)

Re: Flipping squares

Post by AlvaroBegue »

AlvaroBegue wrote: It's `sq ^ 0x70' for mailboxers.
Oh, I meant for 0x88ers. By the way 0-63ers could use 070, which is somewhat more readable.
Daniel Anulliero
Posts: 759
Joined: Fri Jan 04, 2013 4:55 pm
Location: Nice

Re: Flipping squares

Post by Daniel Anulliero »

bob wrote:
sje wrote:

Code: Select all

flipsq = Flip[sq];
is slower than

Code: Select all

flipsq = sq ^ 0x38;
For those that use 0-63 of course. :)

There are still a few mailboxers around.
not for me lol
Flip[sq] is 200ms faster than sq ^0x38 ...
don't understand why lol