Incremental update of PST values slower than not incremental?

Discussion of chess software programming and technical issues.

Moderator: Ras

JVMerlino
Posts: 1396
Joined: Wed Mar 08, 2006 10:15 pm
Location: San Francisco, California

Incremental update of PST values slower than not incremental?

Post by JVMerlino »

Finally got around to converting the PST portion of my eval to be incrementally updated with make/unmake, rather than doing it all from scratch whenever Evaluate() is called. And my engine is now about 10% slower.... :(

Results from three test positions with incremental update - note the KNPS numbers:

Code: Select all

23    474   3415     71176154 g3g5 h6g5 f4g6 g5g4 e3g3 d8d5 g3h4 d5e5 h4h8 g8f7 g6e5 f7e7 h8g7 e7d6 g7f8 d6d5 e5g6 b5b4 g6e7 d5d4 e7c8 b6b8 f8f6 d4d3 f6e6 d3c2 e1e2 c2c1 c8d6 b4a3 b2a3 (2083 KNPS)

22     74   5506    108999113 f4f5 e6f5 d4f5 g6f5 f1f5 d6d5 b3d5 b7d5 f5d5 b8d7 d1d4 e4f6 e3g5 f8e7 g5f6 e7f6 a1e1 e8f8 d4b4 f6e7 b4g4 f8e8 a4c5 a8a7 (1979 KNPS)

18    355   4993    104743953 e3h3 h7g8 f5g6 f7g6 f1f8 g8f8 h3h8 f8e7 h8g7 a2f7 d3d7 e7d7 g7f7 c6e7 b2a3 b7d5 f7f6 d5e6 h1g1 c5c4 f6f3 d7c7 a3a4 e7d5 (2097 KNPS)
Same three test positions without incremental update:

Code: Select all

22    474   3124    71176154 g3g5 h6g5 f4g6 g5g4 e3g3 d8d5 g3h4 d5e5 h4h8 g8f7 g6e5 f7e7 h8g7 e7d6 g7f8 d6d5 e5g6 b5b4 g6e7 d5d4 e7c8 b6b8 f8f6 d4d3 f6e6 d3c2 e1e2 c2c1 c8d6 b4a3 b2a3 (2277 KNPS)

22     74   5169    108999113 f4f5 e6f5 d4f5 g6f5 f1f5 d6d5 b3d5 b7d5 f5d5 b8d7 d1d4 e4f6 e3g5 f8e7 g5f6 e7f6 a1e1 e8f8 d4b4 f6e7 b4g4 f8e8 a4c5 a8a7 (2108 KNPS)

18    355   4480    1047443953 e3h3 h7g8 f5g6 f7g6 f1f8 g8f8 h3h8 f8e7 h8g7 a2f7 d3d7 e7d7 g7f7 c6e7 b2a3 b7d5 f7f6 d5e6 h1g1 c5c4 f6f3 d7c7 a3a4 e7d5 (2337 KNPS)
Does this make sense? Given the speed of engines these days, is it possible that updating the mg/eg values of a branch with each make/unmake is more expensive than just fully calculating them at evaluation time? Has this been known for a while and I didn't notice?

jm
JoAnnP38
Posts: 253
Joined: Mon Aug 26, 2019 4:34 pm
Location: Clearwater, Florida USA
Full name: JoAnn Peeler

Re: Incremental update of PST values slower than not incremental?

Post by JoAnnP38 »

Gosh, now you are going to make me measure this in Pedantic. I'm not best programmer in the world when it comes to shaving cpu cycles, so I'm pretty sure I not doing this in the most efficient way possible:

Inside AddPiece()

Code: Select all

opPcSquare[(int)color] += Evaluation.OpeningPieceSquareTable(piece, Index.NormalizedIndex[(int)color][square]);
egPcSquare[(int)color] += Evaluation.EndGamePieceSquareTable(piece, Index.NormalizedIndex[(int)color][square]);
Inside RemovePiece()

Code: Select all

opPcSquare[(int)color] -= Evaluation.OpeningPieceSquareTable(piece, Index.NormalizedIndex[(int)color][square]);
egPcSquare[(int)color] -= Evaluation.EndGamePieceSquareTable(piece, Index.NormalizedIndex[(int)color][square]);
So when I move a piece from square a to square b, I remove the piece from the square it is on and then add it back on the new square. C# is probably even doing bounds check on every array indexing, although sometimes the JIT optimizer does away with that if it can ensure that no bounds will be exceeded. One more thing to add to my v0.3 release plan: MEASURE INCREMENTAL PST UPDATES.
User avatar
hgm
Posts: 28353
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Incremental update of PST values slower than not incremental?

Post by hgm »

JVMerlino wrote: Thu May 11, 2023 1:22 amDoes this make sense? Given the speed of engines these days, is it possible that updating the mg/eg values of a branch with each make/unmake is more expensive than just fully calculating them at evaluation time? Has this been known for a while and I didn't notice?
I don't think this should be possible, unless your branching factor is below 1.05 or so. Because the Make/UnMake close to the root would serve many leaves, and its impact on speed should be divided by that number. So with an average branching factor of 2 each leaf would only require the equivalent of 2 Make/UnMakes (BF/(BF-1)) for the update.

Your observation begs an explanation, but it might all be due to compiler optimization, which accidentally did a better job in one case than the other. Note that I have once seen a slowdown of ~10% in qperft by deleting unreachable code!
JVMerlino
Posts: 1396
Joined: Wed Mar 08, 2006 10:15 pm
Location: San Francisco, California

Re: Incremental update of PST values slower than not incremental?

Post by JVMerlino »

hgm wrote: Thu May 11, 2023 9:00 am
JVMerlino wrote: Thu May 11, 2023 1:22 amDoes this make sense? Given the speed of engines these days, is it possible that updating the mg/eg values of a branch with each make/unmake is more expensive than just fully calculating them at evaluation time? Has this been known for a while and I didn't notice?
I don't think this should be possible, unless your branching factor is below 1.05 or so. Because the Make/UnMake close to the root would serve many leaves, and its impact on speed should be divided by that number. So with an average branching factor of 2 each leaf would only require the equivalent of 2 Make/UnMakes (BF/(BF-1)) for the update.

Your observation begs an explanation, but it might all be due to compiler optimization, which accidentally did a better job in one case than the other. Note that I have once seen a slowdown of ~10% in qperft by deleting unreachable code!
What you say of course makes a lot of sense, and is what I understood to be the obvious reason for implementing incremental PST updates. However, I'm sure that the benefit goes down, and might even become counter-productive, as more pieces come off the board. When a call to evaluate comes at depth 30+ and there are only 10 or fewer pieces on the board, surely the number of makes/unmakes before the call to evaluate is far larger than the number of pieces left on the board.

But, either way, the positions I posted were either early or middlegame positions. So I still have no real explanation. Just for fun, though, I'll play with some optimization settings. :-)
User avatar
hgm
Posts: 28353
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Incremental update of PST values slower than not incremental?

Post by hgm »

Well, it is very easy to put two counters in your engine, one counting MakeMoves, and the other counting Evals. Then you know for sure ho much more expensive an Eval can be than a MakeMove update before it no longer competitive to calculate it from scratch.
JVMerlino
Posts: 1396
Joined: Wed Mar 08, 2006 10:15 pm
Location: San Francisco, California

Re: Incremental update of PST values slower than not incremental?

Post by JVMerlino »

Well, I found the problem. I was using PutPiece() and RemovePiece() for more than just make/unmake, but also for checking the legality of moves, since Myrddin uses a fully legal move generator. So, I fixed that, and now the speeds are very similar - although non-incremental is still a little less than 2% faster. :(

Incremental:

Code: Select all

18    803   7842    163736455 e3h3 h7g8 h3h6 a2a1 f1a1 c6e5 f5g6 f7g6 d3a3 a7a6 a1e1 f8f5 (2087 KNPS)

23     76   5710    109610460 e1c1 c7b7 h2h4 g5h4 g3g6 h4g5 e3g3 g5f4 g3f4 g8h7 f4g3 d8f8 c1c8 f8c8 g6h6 g7h6 g3g6 h7h8 e5f7 b7f7 g6f7 b6d6 f7f6 h8g8 f6g6 g8f8 g6h6 f8f7 h6e3 d6d7 d3d4 (1919 KNPS)

20     50   2742     50076447 f4f5 e6f5 d4f5 g6f5 f1f5 d6d5 a4b6 f8g7 b6a8 b7a8 e3d4 g7d4 d1d4 e8g8 b3d5 a8d5 f5d5 d8h4 d5e5 f7f5 d4b4 f8f5 (1826 KNPS)
Non-Incremental:

Code: Select all

18    803   7698    163736455 e3h3 h7g8 h3h6 a2a1 f1a1 c6e5 f5g6 f7g6 d3a3 a7a6 a1e1 f8f5 (2126 KNPS)

23     76   5607    109610460 e1c1 c7b7 h2h4 g5h4 g3g6 h4g5 e3g3 g5f4 g3f4 g8h7 f4g3 d8f8 c1c8 f8c8 g6h6 g7h6 g3g6 h7h8 e5f7 b7f7 g6f7 b6d6 f7f6 h8g8 f6g6 g8f8 g6h6 f8f7 h6e3 d6d7 d3d4 (1954 KNPS)

20     50   2701     50076447 f4f5 e6f5 d4f5 g6f5 f1f5 d6d5 a4b6 f8g7 b6a8 b7a8 e3d4 g7d4 d1d4 e8g8 b3d5 a8d5 f5d5 d8h4 d5e5 f7f5 d4b4 f8f5 (1853 KNPS)
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Incremental update of PST values slower than not incremental?

Post by Mike Sherwin »

I have an answer but it is probably more of a question. My focus is on Qsearch. So my incremental update is designed with Qsearch in mind. In Qsearch the moves are 99+% captures. So incremental captures are optimised for Qsearch. In MakeMove() I have this code.

Code: Select all

  case WB:
    ctype = board[m->ts];
    mat[BLACK] -= value[ctype];
    pos[WHITE] += (pcePST[WB][m->ts] - pcePST[WB][m->fs]);
    pos[BLACK] -= pcePST[ctype][m->ts];
    piece[BLACK] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = WB;
    break;
If ctype is an empty square then zero is subtracted from mat[BLACK]. However in Qsearch() it will be rare that it will be an empty square. Therefore virtually no cost for zero being subtracted. On the other hand evaluating an if statement is going to have a cost. And the idea is the same for the removal of the black piece as ZERO << m->ts is no change.

I don't know if this helps but I would appreciate comments on this idea. Thanks.
User avatar
hgm
Posts: 28353
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Incremental update of PST values slower than not incremental?

Post by hgm »

Indeed, if a branch can be avoided by always doing a modest amount of work, making that a dummy when it is not needed, that is usually faster.

This is why I am surprised you switch by piece type. This also seems unnecessary, as there is nothing piecetype or color dependent in the code, other than that you do the same thing to other elements of the array. So it should be faster to directly use variables atype, stm and xstm (=1-stm) for WB, WHITE and BLACK, rather than switching on atype.
Mike Sherwin
Posts: 965
Joined: Fri Aug 21, 2020 1:25 am
Location: Planet Earth, Sol system
Full name: Michael J Sherwin

Re: Incremental update of PST values slower than not incremental?

Post by Mike Sherwin »

I use a switch on piece type because I have pseudo piece types and even pseudo move types.
Here they are enumerated.

Code: Select all

enum {
  OO, WP, WN, WB, WR, WRC, WQ, WK, WC, BP, BN, BB, BR, BRC, BQ, BK, BC,
  Wd, We, Wb, Wr, Wn, Wq, Bd, Be, Bb, Br, Bn, Bq, WS, WL, BS, BL
};
And here is the complete MakeMove().

Code: Select all

void MakeMove(Thread* t, Move* m) {
  s32 ctype = 0, sq;

  possav[WHITE][ply] = pos[WHITE];
  possav[BLACK][ply] = pos[BLACK];
  matsav[WHITE][ply] = mat[WHITE];
  matsav[BLACK][ply] = mat[BLACK];

  nodes++;

  board[m->fs] = 0;
  piece[wtm] ^= one << m->fs;
  piece[wtm] ^= one << m->ts;

  switch (m->type) {
  case OO: break;
  case WP:
    ctype = board[m->ts];
    pos[WHITE] += (pcePST[WP][m->ts] - pcePST[WP][m->fs]);
    pos[BLACK] -= pcePST[ctype][m->ts];
    mat[BLACK] -= value[ctype];
    piece[BLACK] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = WP;
    break;
  case WN:
    ctype = board[m->ts];
    mat[BLACK] -= value[ctype];
    pos[WHITE] += (pcePST[WN][m->ts] - pcePST[WN][m->fs]);
    pos[BLACK] -= pcePST[ctype][m->ts];
    piece[BLACK] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = WN;
    break;
  case WB:
    ctype = board[m->ts];
    mat[BLACK] -= value[ctype];
    pos[WHITE] += (pcePST[WB][m->ts] - pcePST[WB][m->fs]);
    pos[BLACK] -= pcePST[ctype][m->ts];
    piece[BLACK] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = WB;
    break;
  case WR:
    ctype = board[m->ts];
    mat[BLACK] -= value[ctype];
    pos[WHITE] += (pcePST[WR][m->ts] - pcePST[WR][m->fs]);
    pos[BLACK] -= pcePST[ctype][m->ts];
    piece[BLACK] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = WR;
    break;
  case WRC:
    ctype = board[m->ts];
    mat[BLACK] -= value[ctype];
    pos[WHITE] += (pcePST[WR][m->ts] - pcePST[WR][m->fs]);
    pos[BLACK] -= pcePST[ctype][m->ts];
    piece[BLACK] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = WR;
    break;
  case WQ:
    ctype = board[m->ts];
    mat[BLACK] -= value[ctype];
    pos[WHITE] += (pcePST[WQ][m->ts] - pcePST[WQ][m->fs]);
    pos[BLACK] -= pcePST[ctype][m->ts];
    piece[BLACK] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = WQ;
    break;
  case WK:
    ctype = board[m->ts];
    mat[BLACK] -= value[ctype];
    pos[WHITE] += (pcePST[WK][m->ts] - pcePST[WK][m->fs]);
    pos[BLACK] -= pcePST[ctype][m->ts];
    piece[BLACK] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = WK;
    king[WHITE] ^= one << m->fs;
    king[WHITE] ^= one << m->ts;
    break;
  case WC:
    ctype = board[m->ts];
    mat[BLACK] -= value[ctype];
    pos[WHITE] += (pcePST[WK][m->ts] - pcePST[WK][m->fs]);
    pos[BLACK] -= pcePST[ctype][m->ts];
    piece[BLACK] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = WK;
    king[WHITE] ^= one << m->fs;
    king[WHITE] ^= one << m->ts;
    break;
  case BP:
    ctype = board[m->ts];
    mat[WHITE] -= value[ctype];
    pos[BLACK] += (pcePST[BP][m->ts] - pcePST[BP][m->fs]);
    pos[WHITE] -= pcePST[ctype][m->ts];
    piece[WHITE] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = BP;
    break;
  case BN:
    ctype = board[m->ts];
    mat[WHITE] -= value[ctype];
    pos[BLACK] += (pcePST[BN][m->ts] - pcePST[BN][m->fs]);
    pos[WHITE] -= pcePST[ctype][m->ts];
    piece[WHITE] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = BN;
    break;
  case BB:
    ctype = board[m->ts];
    mat[WHITE] -= value[ctype];
    pos[BLACK] += (pcePST[BB][m->ts] - pcePST[BB][m->fs]);
    pos[WHITE] -= pcePST[ctype][m->ts];
    piece[WHITE] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = BB;
    break;
  case BR:
    ctype = board[m->ts];
    mat[WHITE] -= value[ctype];
    pos[BLACK] += (pcePST[BR][m->ts] - pcePST[BR][m->fs]);
    pos[WHITE] -= pcePST[ctype][m->ts];
    piece[WHITE] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = BR;
    break;
  case BRC:
    ctype = board[m->ts];
    mat[WHITE] -= value[ctype];
    pos[BLACK] += (pcePST[BR][m->ts] - pcePST[BR][m->fs]);
    pos[WHITE] -= pcePST[ctype][m->ts];
    piece[WHITE] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = BR;
    break;
  case BQ:
    ctype = board[m->ts];
    mat[WHITE] -= value[ctype];
    pos[BLACK] += (pcePST[BQ][m->ts] - pcePST[BQ][m->fs]);
    pos[WHITE] -= pcePST[ctype][m->ts];
    piece[WHITE] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = BQ;
    break;
  case BK:
    ctype = board[m->ts];
    mat[WHITE] -= value[ctype];
    pos[BLACK] += (pcePST[BK][m->ts] - pcePST[BK][m->fs]);
    pos[WHITE] -= pcePST[ctype][m->ts];
    piece[WHITE] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = BK;
    king[BLACK] ^= one << m->fs;
    king[BLACK] ^= one << m->ts;
    break;
  case BC:
    ctype = board[m->ts];
    mat[WHITE] -= value[ctype];
    pos[BLACK] += (pcePST[BK][m->ts] - pcePST[BK][m->fs]);
    pos[WHITE] -= pcePST[ctype][m->ts];
    piece[WHITE] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = BK;
    king[BLACK] ^= one << m->fs;
    king[BLACK] ^= one << m->ts;
    break;
  case Wd:
    ctype = board[m->ts];
    mat[BLACK] -= value[ctype];
    pos[WHITE] += (pcePST[WP][m->ts] - pcePST[WP][m->fs]);
    piece[BLACK] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = WP;
    epbb[ply + 1] = (u64)(m->fs + 16 == m->ts) << (m->fs + 8);
    break;
  case We:
    sq = m->ts - ((epbb[ply] == (one << m->ts)) << 3);
    ctype = board[sq];
    mat[BLACK] -= value[ctype];
    pos[WHITE] += (pcePST[WP][m->ts] - pcePST[WP][m->fs]);
    pos[BLACK] -= pcePST[ctype][sq];
    piece[BLACK] ^= (u64)(ctype != OO) << sq;
    board[sq] = OO;
    board[m->ts] = WP;
    break;
  case Wb:
    ctype = board[m->ts];
    mat[BLACK] -= value[ctype];
    pos[WHITE] += (pcePST[WB][m->ts] - pcePST[WP][m->fs]);
    pos[BLACK] -= pcePST[ctype][m->ts];
    piece[BLACK] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = WB;
    mat[WHITE] += Vb;
    break;
  case Wr:
    ctype = board[m->ts];
    mat[BLACK] -= value[ctype];
    pos[WHITE] += (pcePST[WR][m->ts] - pcePST[WP][m->fs]);
    pos[BLACK] -= pcePST[ctype][m->ts];
    piece[BLACK] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = WR;
    mat[WHITE] += Vr;
    break;
  case Wn:
    ctype = board[m->ts];
    mat[BLACK] -= value[ctype];
    pos[WHITE] += (pcePST[WN][m->ts] - pcePST[WP][m->fs]);
    pos[BLACK] -= pcePST[ctype][m->ts];
    piece[BLACK] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = WN;
    mat[WHITE] += Vn;
    break;
  case Wq:
    ctype = board[m->ts];
    mat[BLACK] -= value[ctype];
    pos[WHITE] += (pcePST[WQ][m->ts] - pcePST[WP][m->fs]);
    pos[BLACK] -= pcePST[ctype][m->ts];
    piece[BLACK] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = WQ;
    mat[WHITE] += Vq;
    break;
  case Bd:
    ctype = board[m->ts];
    mat[WHITE] -= value[ctype];
    pos[BLACK] += (pcePST[BP][m->ts] - pcePST[BP][m->fs]);
    piece[WHITE] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = BP;
    epbb[ply + 1] = (u64)(m->fs - 16 == m->ts) << (m->fs - 8);
    break;
  case Be:
    sq = m->ts + ((epbb[ply] == (one << m->ts)) << 3);
    ctype = board[sq];
    mat[WHITE] -= value[ctype];
    pos[BLACK] += (pcePST[BP][m->ts] - pcePST[BP][m->fs]);
    pos[WHITE] -= pcePST[ctype][sq];
    piece[WHITE] ^= (u64)(ctype != OO) << sq;
    board[sq] = OO;
    board[m->ts] = BP;
    break;
  case Bb:
    ctype = board[m->ts];
    mat[WHITE] -= value[ctype];
    pos[BLACK] += (pcePST[BB][m->ts] - pcePST[BP][m->fs]);
    pos[WHITE] -= pcePST[ctype][m->ts];
    piece[WHITE] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = BB;
    mat[BLACK] += Vb;
    break;
  case Br:
    ctype = board[m->ts];
    mat[WHITE] -= value[ctype];
    pos[BLACK] += (pcePST[BR][m->ts] - pcePST[BP][m->fs]);
    pos[WHITE] -= pcePST[ctype][m->ts];
    piece[WHITE] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = BR;
    mat[BLACK] += Vr;
    break;
  case Bn:
    ctype = board[m->ts];
    mat[WHITE] -= value[ctype];
    pos[BLACK] += (pcePST[BN][m->ts] - pcePST[BP][m->fs]);
    pos[WHITE] -= pcePST[ctype][m->ts];
    piece[WHITE] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = BN;
    mat[BLACK] += Vn;
    break;
  case Bq:
    ctype = board[m->ts];
    mat[WHITE] -= value[ctype];
    pos[BLACK] += (pcePST[BQ][m->ts] - pcePST[BP][m->fs]);
    pos[WHITE] -= pcePST[ctype][m->ts];
    piece[WHITE] ^= (u64)(ctype != OO) << m->ts;
    board[m->ts] = BQ;
    mat[BLACK] += Vq;
    break;
  case WS:
    ctype = 0;
    board[G1] = WK;
    board[H1] = OO;
    board[F1] = WR;
    king[WHITE] ^= one << E1;
    king[WHITE] ^= one << G1;
    piece[WHITE] ^= one << H1;
    piece[WHITE] ^= one << F1;
    pos[WHITE] += (wkPST[G1] - wkPST[E1]);
    pos[WHITE] += (wrPST[F1] - wrPST[H1]);
    break;
  case WL:
    ctype = 0;
    board[C1] = WK;
    board[A1] = OO;
    board[D1] = WR;
    king[WHITE] ^= one << E1;
    king[WHITE] ^= one << C1;
    piece[WHITE] ^= one << A1;
    piece[WHITE] ^= one << D1;
    pos[WHITE] += (wkPST[C1] - wkPST[E1]);
    pos[WHITE] += (wrPST[D1] - wrPST[A1]);
    break;
  case BS:
    ctype = 0;
    board[G8] = BK;
    board[H8] = OO;
    board[F8] = BR;
    king[BLACK] ^= one << E8;
    king[BLACK] ^= one << G8;
    piece[BLACK] ^= one << H8;
    piece[BLACK] ^= one << F8;
    pos[BLACK] += (bkPST[G8] - bkPST[E8]);
    pos[BLACK] += (brPST[F8] - brPST[H8]);
    break;
  case BL:
    ctype = 0;
    board[C8] = BK;
    board[A8] = OO;
    board[D8] = BR;
    king[BLACK] ^= one << E8;
    king[BLACK] ^= one << C8;
    piece[BLACK] ^= one << A8;
    piece[BLACK] ^= one << D8;
    pos[BLACK] += (bkPST[C8] - bkPST[E8]);
    pos[BLACK] += (brPST[D8] - brPST[A8]);
    break;
  }
  *pceptrs[ctype] ^= one << m->ts;
  m->type |= ctype << 6;
  wtm = 1 - wtm;
  ply++;
}
So for example a WRC is a white rook that can castle but if it moves it becomes a WR, white rook that can not castle. On TakeBack() it becomes a WRC again.

I am most proud of my We code. The code handles white capture en-passant correctly while having no idea that it is actually processing a possible cep move.

Code: Select all

  case We:
    sq = m->ts - ((epbb[ply] == (one << m->ts)) << 3);
    ctype = board[sq];
    mat[BLACK] -= value[ctype];
    pos[WHITE] += (pcePST[WP][m->ts] - pcePST[WP][m->fs]);
    pos[BLACK] -= pcePST[ctype][sq];
    piece[BLACK] ^= (u64)(ctype != OO) << sq;
    board[sq] = OO;
    board[m->ts] = WP;
    break;
    
Maybe there is something better than a switch statement but this is how I got it to work.
PK
Posts: 904
Joined: Mon Jan 15, 2007 11:23 am
Location: Warsza

Re: Incremental update of PST values slower than not incremental?

Post by PK »

C# multi dimensional tables are slow. Use some function to generate an index to a one-dimensional array, something like return 64 * (6 * x + y) + z; this will help both with incremental and non-incremental tables, and perhaps it will shift the proportion between one and the other.