Computer Chess Club Archives


Search

Terms

Messages

Subject: Re: High performance move generation

Author: Dan Newman

Date: 01:00:37 11/26/99

Go up one level in this thread


On November 24, 1999 at 17:06:54, Bas Hamstra wrote:

>On November 20, 1999 at 17:26:48, Dan Newman wrote:
>
>>On November 20, 1999 at 08:59:11, Bas Hamstra wrote:
>>
>>>Hi Dan,
>>>
>>>Let me give you an idea of my current speed: it is comparable with yours, the
>>>same order of magnitude, I think (also Celeron 450). Indeed make/unmake slow
>>>down considerably, other things speed up, like you mentioned. I don't think it
>>>is much faster or slower on the whole than the more conventional approaches.
>>>Another interesting figure: with only material eval my profiler says my make is
>>>7% as wel as the unmake. NextCapture() is 10%. Blocks() is 3%.
>>>
>>
>>Wow.  7% on make is quite good I think.  This is the same percentage I got
>>for my 0x88 program in fact...  Of course that's all relative to what other
>>things take.  In the 0x88 program the biggest cost was the SEE which took
>>a full 25%.
>
>SEE is very cheap for me, have to look it up, but I think 4% or so. Note that
>determining if a capture is a loser is cheaper than getting the exact swap
>value... But then you can't sort SEE wise of course.

I do a SEE on every capture.  I noticed in Crafty that Bob doesn't bother
doing a SEE when the capturing piece is less valuable than the captured.
In one place he scores the capture as the difference in the values of the
two pieces.  This would give a lower bound of what the SEE would return I
guess.  I think I'll have to try this.  The last time I tested the SEE vs.
MVV/LVA the SEE was only a slight win in the relatively shallow searches
that I tested with.  (The improved move ordering offset the huge cost of
the SEE.  That, of course, means that on deeper searches it should get
even better.)

>
>Anyway keep me informed of what you have tried and are trying, I like it and am
>interested.
>
>I tried to vary lazy values based on eval, if no pawn at sixth and a safe king
>the eval becomes lazier. When I run the hardest wacs, that run for a fixed
>number of seconds, I determine the average depth. You can win a few percent >here and there, but I don't think it it spectacular.
>
>Also doing killers before the losing captures in the normal search got me a few
>percent of a ply.

I only recently started doing this (in my 0x88 program).  It was a small win,
enough to make it worth it, but I had to do a really ugly hack to fit it into
my code.  I had been doing all the captures first, then overwriting the
capture list with the non-capture list (after trying killers).  Now I had
to preserve a pointer to the start of the losing captures and put the non-
captures after the captures...

>
>Latest thing is replace certain eval terms by piece square sums. It all don't
>seem to matter very much.
>
>Strongest version so far was with a relatively big/slow and not so lazy eval.
>Very readable and debuggable, so NOT very efficient. Relatively big positional
>scores. Trying to improve speed and efficiency did me more harm than good so
>far. Centre control and "space" (simply adding up ranks) worked good. Giving
>huge penalties for oppopieces very near to the king, proportional to piece value
>works very good, with a little tuning (penalties up to a couple of pawns gave
>many correct sacrifices, only occasionally too speculative).
>
>With valuing pseudo attacks on key squares (centre, king, queen, kingformation)
>I had less luck. Trying to make it more materialistic (all scores scaled down)
>made things worse.
>
>So far what I've been busy with, lately.
>
>>>The worst case is when a queen captures a queen, of course. But that doesn't
>>>happen too often. When you just move a pawn it costs only a few ticks and you
>>>have your (peudo) captures at hand. I don't think I have squeezed all speed out
>>>of it, yet. For instance, in case of Q1xQ2 I remove attacks for the first queen,
>>>than for the second, and insert new attacks for the first queen. Clearly that is
>>>not optimal: better (I hope) would be to make a combined NOT mask for Q1 and Q2
>>>and just NOT all 64 squares in one run.
>>>
>>
>>The only improvement I've thought of is to avoid toggling the bits along
>>the diagonal or orthogonal along which a slider moves.  This would (I think)
>>cut the cost quite a bit for bishops and rooks and a smaller amount for
>>queens.  But would make the code a bit more complex.  It would also increase
>>the function call overhead and perhaps expand code that does the bit
>>twiddling.

I thought about this some more and realized it doesn't save much at all.
Probably isn't worth the overhead needed to make it work...

>>
>>>Another thing to consider that I have never tried is to make a copy of the
>>>attackboard so saving the undoing of attacks. No idea if that's faster.
>>>
>>
>>That sounds more expensive, but it's worth a try.
>>
>>>The fastest purely material (fully SEE sorted) program I wrote yet was a
>>>bitboard approach. But then when I added some eval and some InCheck checking and
>>>attack detection the difference became quite small.
>>>
>>
>>Same here.  I had thought (after a few experiments with bitboards) that
>>0x88 would be faster (on Intel machines), but now the fastest thing I've
>>written is my current non-rotated bitboard program...
>
>Me also non rotated. Yep, you can operate on groups of pieces, which can be
>fast. Plus eval advantages (which I have not used yet). Gives good compensation
>for the relatively slow fiddling with the big ints.

The thing that made this a big win for me was the MS compiler.  I had been
using Watcom, and on the 0x88 program MSVC only gave me a 17% speedup.  But
on the bitboard program it gives me > 50% !!!  If I compiled only with
Watcom, I'd have come to the conclusion that 0x88 is probably better, but
that 50% is a real boost.  I suspect Watcom is doing something ugly in the
optimization that prevents the P6 from doing two int ops at the same time...

>
>>>I am looking for ways to exploit my datastructures more. One example is: if a
>>>pawn is at seventh I can easily determine wat the oppo has to sacrifice to
>>>prevent promotion, by a SEE. Works quite well. Any ideas of where to use more
>>>SEE's in eval succesfully? I am currently fiddling with counting pseudoattacks,
>>>and assign a bonus for that (ignoring blocks) but without much success so far.
>>>
>>
>>I haven't done much work on eval.  Mostly I've been writing up to the
>>point of getting a working program and then becoming dissatisfied with
>>its performance or other characteristics (ease of programming, bugginess,
>>lack of support by the basic data structures for some feature or important
>>element, etc.).  So I try something new.
>
>Sounds familiar :)
>
>>One thing I'm doing now is giving a slight bonus for sliders bearing on
>>the king with the hope that the search will occasionally see something
>>that leads it to a (successful) king attack.  I have no idea whether it
>>helps or not.  With the pseudo-attacks one could also easily (cheaply) factor
>>in attacks on squares surrounding the king too.
>
>Keep me informed, if it isn't too much trouble.
>
>>As for the SEE, I only use it to order moves and trim losing captures in
>>the quiescence search.  I have though of trying to make it more
>>sophisticated so that it can be used to replace the qsearch, but that may
>>not be too practical...
>
>I agree. In my case if you would ask me what is the biggest factor for playing
>strength, I would say eval. Nothing else comes close. Just my experience, of
>course. At some point I found a good way to come to a reasonable tuning: just
>adjust terms slightly, say 10%. I play a couple of games and when it gets run
>over by pieces I add 10% to centre control. When it wants to fight with a couple
>of pieces on the back rank: development gets 10%. And after a while it started
>working and whacking GNU.

I would have said the search.  But of course a search with no eval at all is
worthless.  Once you've got as fast a search as you can get (to depth), I
guess mostly what's left to improve things is eval.  To a certain extent eval
and search are complementary and act together in a synergistic fashion, but
they also fight each other over cpu time.  Getting the right balance is
extremely tricky.

I've recently been thinking of trying to get away with a minimum of eval,
mostly material with a little pawn structure and king safety thrown in, and
concentrating more on trying to guide the search into profitable regions of
the search tree using extensions and reductions.  The idea is that I'd rather
the program do something on the basis of something discovered by the search
than to to it because of some rule-of-thumb eval term that probably has many
(unhandled) exceptions.

For instance, putting a rook on the 7th is quite often a good idea.  But
perhaps not, if the king isn't confined by it.  I've noticed with my most
current program that it quite often ends up putting a rook there even
though I don't have such an eval term.  The search is synthesizing this
"term" when it can see the value of doing this.  Of course at the horizon
there is no search to tell you this is good, but if the search were several
plies deeper it could.  Actually, having this in the eval probably only costs
a little cpu time.  Much less than searching deeper.  But it is much less
acurate than the search and has some ad hoc weight attached to it that
may not refect what a detailed analysis would give.  I guess the danger
is that a move will be selected that will somehow preclude putting the
rook there later if there isn't an eval term for this.

-Dan.

>
>
>Regards,
>Bas Hamstra.
>
>
>
>
>
>
>
>>>Regards,
>>>Bas Hamstra.



This page took 0 seconds to execute

Last modified: Thu, 15 Apr 21 08:11:13 -0700

Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.