David,

There are many variations of this technique,  but what they all have in
common is the assumption that once you have searched some number of
child moves (perhaps 2 or 3) then (with good move ordering) there is
much reduced  chance than one of the remaining moves will be
useful.      Often the remaining moves are searched with reduced
depth.   Also,  most programs have constraints on this (don't reduce
checks, out of checks,  attacking moves, etc.)     Some programs limit
the total number of reductions in a given line.   

This is sometimes called "history reductions" (not a very accurate
description in general) because some programs use the history heuristic
and prune moves using this same basic technique but  based on having low
"history scores."      Some programs only reduce a few ply from end
nodes.   

The implementation details vary significantly from program to program
and the prejudices and superstitions that we programmers carry over to
our programs. 

But this is considered one of the major recent advances in computer
chess - and just about every chess program jumped in strength 50-100
ELO  all of  sudden when this started to be used.

In my alpha/beta searcher a very simple minded version is actually
working very well - it will take weeks though to test and refine
this.      The only thing I am doing now is:

   At any given node ...
     If  less than 4 ply remaining ....
         if move is not a capture  ....
            if at least 5 moves have been tried ...
                 do not search the subtree.

This probably wouldn't work in Chess without better conditions.    And
it can probably be improved a lot GO too,   the next thing I will do is
(at the very least) include (not prune) atari moves.  

I also have a nice set of patterns inherited from Lazarus.  I set the
strongest version of Lazarus to do deep searches and kept ELO ratings of
the 20 points patterns (5x5 with corners cut off.)     This produced a
nice set of patterns and I use this mostly for finding silly moves.    
I will probably add to the conditions that all strong patterns should be
played no matter what. 

Right now I use weak patterns to "veto" moves from the tree.    If a
move is below a given rating I don't even try it if I am on the last 4
ply of the search.   All of the patterns fitting this critiera represent
moves any player would consider pretty weak 99% of the time,  such as
moving into the corner point when nothing is happening.    The most
common pattern pruned is moving to an edge when nothing is nearby. 

What I really want to find is a more general way of identifying  weak
moves.     What seems to be the case in GO is that you can be a lot more
liberal about pruning moves without hurting the search.   Amazingly,  at
the same depth, using the veto patterns along with selectivity
simultaneously made the program stronger and faster.    Normally you
don't get both at the same time because you are dealing with
trade-offs.     In this case, I think the veto patterns probably
strengthen the program because of the noisy evaluation function.   I am
basically making it impossible (at low depth levels) to play a "bad"
move.      For instance moving to a1 in the opening,  although very
unlikely is possible with a MC evaluation function but when I use the
patterns it is impossible. 

I have more comments in response to yours:

David Fotland wrote:
> Hi Don,
>
> I never heard of this technique before.  Are there any more you can share?
>   
Since you are using hash tables,  I assume you are aware of ETC 
(Enhanced Transposition Cutoffs.)  ?

For anyone unaware -  it works like this:

    1.  If a hash table entry does not exist for a given move.
    2.  Do a quick search of the children - in the hopes of finding a
cutoff.

At interior nodes it's cheap and it will provide a cutoff sometimes when
a direct cutoff is not in the table.   If it does not provide a cutoff
it might be used to narrow the alpha beta window.

> ManyFaces12 uses:
>
> -Iterative deepening, with hash table
>   
My experimental alpha/beta searcher doesn't even have hash tables
yet.     I have to think about how to implement this because scores are
probabilistic.   Even worse, they can be based on varying numbers of
play-outs since I stop play-outs early when it appears that the score
will not shrink the alpha beta window.

I will probably first try a version that pretends none of this is an issue.

Do you have "parity" issues in ManyFaces?    This is a problem in GO
with a MC evaluation function.   An odd ply search seems to return a
substantially higher score than an even ply search,  and it seems like
you cannot compare an odd to an even ply search.      This affects the
hash table implementation signficantly because you cannot take a cutoff
based on scores of a different parity.     (at least not without a
"slop" margin.)

I'm currently trying to find a workable scheme to deal with this.   It's
even a worse problem with MC evaluation because of the nature of
mini-max - the highest scoring move at end nodes tends to gravitate
towards a move with more error.     (I think this could explain why
selectivity may actually give more realistic evaluations at end nodes -
not as many choices,  so less chances to find one grossly in error.)


> -Zero-window search (beta is alpha+1, and research when fail high)
>   
Currently I'm doing straightforward alpha beta with no aspiration
search.   Again, this is more dicey with a fuzzy evaluation
function.     If a zero width window search fails high - it might not
fail high on the re-search!

I will still probably try it but I will have to "play silly games" with
the search.

Do you know about MTD(F) ?      Although hardly any programs use it,  it
is a win.   All searches are zero width and you have a driver that
"zero's in on the correct score"  so it's rather like a best first
search.   You must have hash tables for this to work but it's quite
effective and it has always given me about 10 - 15 % over even PVS
search.   

I think it's not used much in chess because it can be tricky.   It's
conceptually trivial,  but it ends up being a little tricky to get
right.    One problem is that it can be tricky getting a nice looking
principal variation because EVERY search is a search failure.    That
problem is solvable but there is trickiness.   In PVS your principal
variation is always formed from scores inside the alpha beta window.  

Another reason it may not be used in chess is tradition.   You don't get
the conventional display of information since each iteration is composed
of many re-searches.    So you don't get move list countdowns and the
same move may get selected many times even during the same
iteration.      So it's definitely not traditional chess program
friendly.     It's probably less human friendly reporting information as
a result.

CilkChess used this and it was actually implemented by the Aske Plaat,
the researcher who formulated the idea and was a postdoc at MIT when I
was developing the program.  

MTD(F) may actually work pretty well with the way I'm "cheating" with
the evaluation function in the experimental alpha beta searcher - we
will see ....

> -Null move (reduce depth by one, only try null when beta is not infinite,
> only one null move allowed per variation)
>   
How is this working?     My sense of this is that it would work well in
GO if your program is not overly dependent on life and death via global
searching.    In other words, if it has good life and death in the
evaluation function.  

I haven't tried this yet the MC searcher.     There really isn't much to
try until I can get reasonable depths and deal with the parity problem. 

> -Try null first, then the best move from the previous iteration (from the
> hash table), then moves in the order suggested by the move generator.  The
> move generator gives a pretty good ordering since it estimates the number of
> points gained by the move.
>   
I'm sorting moves by the pattern scores and I think it works well with
the pruning algorithm I described - it increases the chances that the
strongest patterns are tried first.

I also use the killer heuristic which seems very effective.    I haven't
really gotten into heavy tuning - I suspect my move ordering is far from
optimal but I will get into this more when I implement hash tables.

> -Full ply extension when there is one forced move
> -Fractional ply extensions
>   
I will experiment with extensions for atari moves and perhaps captures.

I want to identify serious atari and capture moves from unimportant
ones.   It seems silly to extend an atari  or capture move of a group
that is clearly dead anyway.   

So one thing I have in mind that I am pretty hopeful of is to do a
preliminary small "play-out" analysis  at parent nodes to do the
"territory mapping thing"  which will provide great help for move
extensions,  pruning and move ordering.   
> I plan to add:
> -2 killer moves, then history heuristic
>   
Killers seem to work very well.   History, not as well - but each
implementation is different,   perhaps it will work well for you.     I
have found that global table with good moves in the right order works
very well - and you can just modify this original move list.      I'm
not yet doing it here in the specific program, but it worked well in a
previous go alpha beta searcher.
> -This pruning idea from Don.
> -Internal iterative deepening
> -Some kind of iterative widening
> -narrow search window based on result of previous iteration
>
> Today I search 20 to 40 moves at the root, then 10 moves per ply during the
> main search, then a tapering quiescence search with no maximum depth.
>
> I find developing search code less satisfying then working on the evaluation
> function.  If I add knowledge to the evaluation function I know the program
> is stronger.  When I make a change to the search parameters I can only test
> to see what happened.  It's a much more trial-and-error process.
>   
I hate tuning the move ordering.   It's just busy-work for me.   You are
mostly just running timing tests and trying things in different
combinations - what a pain.    But you have to do it.

> Still, I have to do it because global search makes the program much, much
> stronger.
>   
I have often wondered if it would be possible to take a more
conventional evaluation function (like in ManyFaces) and apply the basic
principles of best first searching, perhaps a hybrid of UCT.   Instead
of playing random games to the end you just apply the evaluation
function in a straightforward way and handle the tree portion pretty
much like UCT.    You still balance exploitation and exploration like
UCT.    Have you considered such an approach?  

- Don


> David
>
>
> -----Original Message-----
> [EMAIL PROTECTED] On Behalf Of Don Dailey
>
>
> The various versions I'm testing are selective, I use a technique
> similar to that used in modern chess programs of aborting the search
> at a given node after only a few children nodes have been tried when
> the expectation remains below alpha.  
>
> There are many potential tricks that can speed up the search greatly
> and I've barely scratched the surface, but I have done a couple of
> simple basic things that appear to be working very well.
>
>
>
> _______________________________________________
> computer-go mailing list
> computer-go@computer-go.org
> http://www.computer-go.org/mailman/listinfo/computer-go/
>
>   
_______________________________________________
computer-go mailing list
computer-go@computer-go.org
http://www.computer-go.org/mailman/listinfo/computer-go/

Reply via email to