Singular extension tests

Discussion of chess software programming and technical issues.

Moderator: Ras

bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Singular extension tests

Post by bob »

Desperado wrote:
bob wrote: ...
If I fail low at any node, this is stored in the hash table as a "UPPER" position and there is obviously no best move to store. In Crafty, as a search is carried out, I save the first move searched (which may be the hash move, or the first capture tried, or the first killer (if there is no hash or safe capture move) or just the first move generated in the worst case. When I discover that this is a "UPPER" position with no best move, I store the first move searched as the best move. Why? The next time I hit this position, I will search that move without a move generation, and without a best move that is the move I would end up searching first anyway, so why not?
...
However, this now means that _every_ hash hit will have a best move (the EXACT/LOWER positions obviously would, and now UPPER also).
...
i agree that having a move available will improve the search,
and results in positive elo gain.

i dont agree that is has to be the first move given by the moveselector.
(as we all know,which tries: tMove,captures ...)

i am prettey sure, that using the move with the highest fail-lo score
is the better choice, at least it is more dynamic.Further i believe
that will result in smaller trees, and speed up the search more
than your approach.
The problem is in your terminology. You do not think of "highest fail-lo score" as that makes no sense. For each fail-low move/score you get back, are you _certain_ that your opponent found the _best_ refutation? Or did a killer just happen to be good enough? The point is, the scores you get back are not scores, they are all bounds. And you can't compare bounds to figure out which one might be best, because these are _very_ loose bounds at best.

Simple test. Ed Schroeder did exactly what you are doing years ago. We had this same discussion. He removed that code and found his trees got _smaller_. Easy to test.
Chan Rasjid wrote:Hello Michael,

Your scheme differs from that of Bob and it is not what he wants.

In an all-node, Bob's scheme either stores the original tt-move or the first move done,ie the move with the highest original ordering. In your scheme, the move stored might be way down in the original ordering. Such a move, if first searched in a hash hit in a subsequent search, will not be searching a move with the highest ordering and it would be a bad move to try.

Rasjid.
yes, i try a move a move which might be way down in _original_ move ordering. But there is no argument (for now),
that is telling us, it would be worse (both moves failed lo, the first
and move-n with the higher fail-lo score)

At the end, if we have a real allNode, which is now and for all revisits
an allNode, we might store a move by random.That would not hurt.
But my opinion is, if we dont do it by random then we need a _formular_
to pick a (best)move.

bobs formular: (1)
first move given by moveselection code

my formular: (2)
the value with the highest fail-lo score.(btw the most unimportant
thing is not to have _any_ extra code as advantage)

why should (1) be better than (2) ? :o

Michael
1. has zero extra code. Only considering ALL nodes, you have two possibilities when you arrive at one. (a) you have a hash hit but the bounds or score doesn't let you stop searching, but you do have a hash move to try first. (b) you do not have a hash move, so you try the move your move generator pops out first.

My approach does both. If you have an existing hash move, it will be preserved when we store the hash entry for this ALL node after we finish. If not, we will store the first move we searched, which is as good as any place to start since that is what we would do with no hash move at all. Requires no tweaking in the hash store code to preserve an existing hash move either... So simple _and_ very effective.

And, of course, verified with a "few" games on our cluster. :)
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Singular extension tests

Post by bob »

Desperado wrote:...

and there is another issue on Bobs implementation.
Normally the transValue and the transMove are corresponding.
I mean the upperBound Bob stores must not belong to the
move he stores. (i dont know if or how it matters, but imo the move
and the value stored, should belong together.So,it might be viewed
as bug, or not?).

:?: :!:
I do not follow that at all. The best move comes from the search at the current ALL node. Or it came from the hash hit that failed to terminate the current search. How does that move not belong???
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Singular extension tests

Post by bob »

Antonio Torrecillas wrote:Hello,
Just to add other ideas...

For the defer move generation trick I store in the transposition table for ALL nodes the move with the bigger sub-tree (node count).

The idea is to save work in the most expensive sub-tree.

Regards, Antonio.
This doesn't make any sense to me. You are not saving a score for that move, you are saving a bound for the current position.
User avatar
Desperado
Posts: 879
Joined: Mon Dec 15, 2008 11:45 am

Re: Singular extension tests

Post by Desperado »

ok, i will accept what of all you are telling me. Although i cannot
measure sth. bad.

I now will do like Bob is doing, storing the first move given by
move selection code to transtable. This one might really be the
move with highest probability to be the _bestMove_.

Thx for everybodys patience. 8-)

Michael
jwes
Posts: 778
Joined: Sat Jul 01, 2006 7:11 am

Re: Singular extension tests

Post by jwes »

Desperado wrote:ok, i will accept what of all you are telling me. Although i cannot
measure sth. bad.

I now will do like Bob is doing, storing the first move given by
move selection code to transtable. This one might really be the
move with highest probability to be the _bestMove_.
I think you still don't quite understand. If the position has ever failed high, the move that failed high will be in the tt, and will be used as the first move on subsequent searches and saved in the tt until some other move fails high. Only if the position has never failed high (and is not a pv node) will the first move generated be saved in the tt.
User avatar
Desperado
Posts: 879
Joined: Mon Dec 15, 2008 11:45 am

Re: Singular extension tests

Post by Desperado »

jwes wrote:
Desperado wrote:ok, i will accept what of all you are telling me. Although i cannot
measure sth. bad.

I now will do like Bob is doing, storing the first move given by
move selection code to transtable. This one might really be the
move with highest probability to be the _bestMove_.
I think you still don't quite understand. If the position has ever failed high, the move that failed high will be in the tt, and will be used as the first move on subsequent searches and saved in the tt until some other move fails high. Only if the position has never failed high (and is not a pv node) will the first move generated be saved in the tt.
Well i think i do understand, because the move selector will give as first
move the already existing ttMove
(if it exists, and so it will be kept as first move),
and only if the first move is not a ttMove it is a _generated first one_
, which we will store... that works implicit...
Pablo Vazquez
Posts: 154
Joined: Thu May 31, 2007 9:05 pm
Location: Madrid, Spain

Re: Singular extension tests

Post by Pablo Vazquez »

bob wrote:
Desperado wrote:
bob wrote: ...
If I fail low at any node, this is stored in the hash table as a "UPPER" position and there is obviously no best move to store. In Crafty, as a search is carried out, I save the first move searched (which may be the hash move, or the first capture tried, or the first killer (if there is no hash or safe capture move) or just the first move generated in the worst case. When I discover that this is a "UPPER" position with no best move, I store the first move searched as the best move. Why? The next time I hit this position, I will search that move without a move generation, and without a best move that is the move I would end up searching first anyway, so why not?
...
However, this now means that _every_ hash hit will have a best move (the EXACT/LOWER positions obviously would, and now UPPER also).
...
i agree that having a move available will improve the search,
and results in positive elo gain.

i dont agree that is has to be the first move given by the moveselector.
(as we all know,which tries: tMove,captures ...)

i am prettey sure, that using the move with the highest fail-lo score
is the better choice, at least it is more dynamic.Further i believe
that will result in smaller trees, and speed up the search more
than your approach.
The problem is in your terminology. You do not think of "highest fail-lo score" as that makes no sense. For each fail-low move/score you get back, are you _certain_ that your opponent found the _best_ refutation? Or did a killer just happen to be good enough? The point is, the scores you get back are not scores, they are all bounds. And you can't compare bounds to figure out which one might be best, because these are _very_ loose bounds at best.

Simple test. Ed Schroeder did exactly what you are doing years ago. We had this same discussion. He removed that code and found his trees got _smaller_. Easy to test.
Chan Rasjid wrote:Hello Michael,

Your scheme differs from that of Bob and it is not what he wants.

In an all-node, Bob's scheme either stores the original tt-move or the first move done,ie the move with the highest original ordering. In your scheme, the move stored might be way down in the original ordering. Such a move, if first searched in a hash hit in a subsequent search, will not be searching a move with the highest ordering and it would be a bad move to try.

Rasjid.
yes, i try a move a move which might be way down in _original_ move ordering. But there is no argument (for now),
that is telling us, it would be worse (both moves failed lo, the first
and move-n with the higher fail-lo score)

At the end, if we have a real allNode, which is now and for all revisits
an allNode, we might store a move by random.That would not hurt.
But my opinion is, if we dont do it by random then we need a _formular_
to pick a (best)move.

bobs formular: (1)
first move given by moveselection code

my formular: (2)
the value with the highest fail-lo score.(btw the most unimportant
thing is not to have _any_ extra code as advantage)

why should (1) be better than (2) ? :o

Michael
1. has zero extra code. Only considering ALL nodes, you have two possibilities when you arrive at one. (a) you have a hash hit but the bounds or score doesn't let you stop searching, but you do have a hash move to try first. (b) you do not have a hash move, so you try the move your move generator pops out first.

My approach does both. If you have an existing hash move, it will be preserved when we store the hash entry for this ALL node after we finish. If not, we will store the first move we searched, which is as good as any place to start since that is what we would do with no hash move at all. Requires no tweaking in the hash store code to preserve an existing hash move either... So simple _and_ very effective.

And, of course, verified with a "few" games on our cluster. :)
I think you should still check that you don't overwrite a tt move so that you don't lose it when you call HashStore() with no move from a null move search.
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Singular extension tests

Post by bob »

Pablo Vazquez wrote:
bob wrote:
Desperado wrote:
bob wrote: ...
If I fail low at any node, this is stored in the hash table as a "UPPER" position and there is obviously no best move to store. In Crafty, as a search is carried out, I save the first move searched (which may be the hash move, or the first capture tried, or the first killer (if there is no hash or safe capture move) or just the first move generated in the worst case. When I discover that this is a "UPPER" position with no best move, I store the first move searched as the best move. Why? The next time I hit this position, I will search that move without a move generation, and without a best move that is the move I would end up searching first anyway, so why not?
...
However, this now means that _every_ hash hit will have a best move (the EXACT/LOWER positions obviously would, and now UPPER also).
...
i agree that having a move available will improve the search,
and results in positive elo gain.

i dont agree that is has to be the first move given by the moveselector.
(as we all know,which tries: tMove,captures ...)

i am prettey sure, that using the move with the highest fail-lo score
is the better choice, at least it is more dynamic.Further i believe
that will result in smaller trees, and speed up the search more
than your approach.
The problem is in your terminology. You do not think of "highest fail-lo score" as that makes no sense. For each fail-low move/score you get back, are you _certain_ that your opponent found the _best_ refutation? Or did a killer just happen to be good enough? The point is, the scores you get back are not scores, they are all bounds. And you can't compare bounds to figure out which one might be best, because these are _very_ loose bounds at best.

Simple test. Ed Schroeder did exactly what you are doing years ago. We had this same discussion. He removed that code and found his trees got _smaller_. Easy to test.
Chan Rasjid wrote:Hello Michael,

Your scheme differs from that of Bob and it is not what he wants.

In an all-node, Bob's scheme either stores the original tt-move or the first move done,ie the move with the highest original ordering. In your scheme, the move stored might be way down in the original ordering. Such a move, if first searched in a hash hit in a subsequent search, will not be searching a move with the highest ordering and it would be a bad move to try.

Rasjid.
yes, i try a move a move which might be way down in _original_ move ordering. But there is no argument (for now),
that is telling us, it would be worse (both moves failed lo, the first
and move-n with the higher fail-lo score)

At the end, if we have a real allNode, which is now and for all revisits
an allNode, we might store a move by random.That would not hurt.
But my opinion is, if we dont do it by random then we need a _formular_
to pick a (best)move.

bobs formular: (1)
first move given by moveselection code

my formular: (2)
the value with the highest fail-lo score.(btw the most unimportant
thing is not to have _any_ extra code as advantage)

why should (1) be better than (2) ? :o

Michael
1. has zero extra code. Only considering ALL nodes, you have two possibilities when you arrive at one. (a) you have a hash hit but the bounds or score doesn't let you stop searching, but you do have a hash move to try first. (b) you do not have a hash move, so you try the move your move generator pops out first.

My approach does both. If you have an existing hash move, it will be preserved when we store the hash entry for this ALL node after we finish. If not, we will store the first move we searched, which is as good as any place to start since that is what we would do with no hash move at all. Requires no tweaking in the hash store code to preserve an existing hash move either... So simple _and_ very effective.

And, of course, verified with a "few" games on our cluster. :)
I think you should still check that you don't overwrite a tt move so that you don't lose it when you call HashStore() with no move from a null move search.
Trivial to do, I'll see if it changes anything...
Mincho Georgiev
Posts: 454
Joined: Sat Apr 04, 2009 6:44 pm
Location: Bulgaria

Re: Singular extension tests

Post by Mincho Georgiev »

It gave me -5 ELO without the check for move for the new entry saving. Could be wrong result though.
User avatar
michiguel
Posts: 6401
Joined: Thu Mar 09, 2006 8:30 pm
Location: Chicago, Illinois, USA

Re: Singular extension tests

Post by michiguel »

Pablo Vazquez wrote:
bob wrote:
Desperado wrote:
bob wrote: ...
If I fail low at any node, this is stored in the hash table as a "UPPER" position and there is obviously no best move to store. In Crafty, as a search is carried out, I save the first move searched (which may be the hash move, or the first capture tried, or the first killer (if there is no hash or safe capture move) or just the first move generated in the worst case. When I discover that this is a "UPPER" position with no best move, I store the first move searched as the best move. Why? The next time I hit this position, I will search that move without a move generation, and without a best move that is the move I would end up searching first anyway, so why not?
...
However, this now means that _every_ hash hit will have a best move (the EXACT/LOWER positions obviously would, and now UPPER also).
...
i agree that having a move available will improve the search,
and results in positive elo gain.

i dont agree that is has to be the first move given by the moveselector.
(as we all know,which tries: tMove,captures ...)

i am prettey sure, that using the move with the highest fail-lo score
is the better choice, at least it is more dynamic.Further i believe
that will result in smaller trees, and speed up the search more
than your approach.
The problem is in your terminology. You do not think of "highest fail-lo score" as that makes no sense. For each fail-low move/score you get back, are you _certain_ that your opponent found the _best_ refutation? Or did a killer just happen to be good enough? The point is, the scores you get back are not scores, they are all bounds. And you can't compare bounds to figure out which one might be best, because these are _very_ loose bounds at best.

Simple test. Ed Schroeder did exactly what you are doing years ago. We had this same discussion. He removed that code and found his trees got _smaller_. Easy to test.
Chan Rasjid wrote:Hello Michael,

Your scheme differs from that of Bob and it is not what he wants.

In an all-node, Bob's scheme either stores the original tt-move or the first move done,ie the move with the highest original ordering. In your scheme, the move stored might be way down in the original ordering. Such a move, if first searched in a hash hit in a subsequent search, will not be searching a move with the highest ordering and it would be a bad move to try.

Rasjid.
yes, i try a move a move which might be way down in _original_ move ordering. But there is no argument (for now),
that is telling us, it would be worse (both moves failed lo, the first
and move-n with the higher fail-lo score)

At the end, if we have a real allNode, which is now and for all revisits
an allNode, we might store a move by random.That would not hurt.
But my opinion is, if we dont do it by random then we need a _formular_
to pick a (best)move.

bobs formular: (1)
first move given by moveselection code

my formular: (2)
the value with the highest fail-lo score.(btw the most unimportant
thing is not to have _any_ extra code as advantage)

why should (1) be better than (2) ? :o

Michael
1. has zero extra code. Only considering ALL nodes, you have two possibilities when you arrive at one. (a) you have a hash hit but the bounds or score doesn't let you stop searching, but you do have a hash move to try first. (b) you do not have a hash move, so you try the move your move generator pops out first.

My approach does both. If you have an existing hash move, it will be preserved when we store the hash entry for this ALL node after we finish. If not, we will store the first move we searched, which is as good as any place to start since that is what we would do with no hash move at all. Requires no tweaking in the hash store code to preserve an existing hash move either... So simple _and_ very effective.

And, of course, verified with a "few" games on our cluster. :)
I think you should still check that you don't overwrite a tt move so that you don't lose it when you call HashStore() with no move from a null move search.
I think it is better not to save anything at all after a nullmove search. We had a thread about it some time ago, originated but someone what was saving it with depth-R rather than R. Depth-R seemed to work better, despite it is a bug. For me, it works even better not to save anything, which may mean that saving depth-R is good because it could be overwritten faster.

Miguel