Dr. Hyatt, I think I really need your cluster here
I have read your interested thread of some time ago regarding the historical reasons why the ordering at ply one is done (when score is equal) counting the nodes searched by each move subtree during the previous iteration.
I think I have come up with a different idea that seems better in my tests but needs confirmation.
The idea is to count the beta-cut offs instead of the nodes.
The advantage is that you can differentiate between _our_ beta cutoffs and _opponent_ cutoffs. So you actually have two counters:
int64_t betaCounter[2];
That are reset to zero before searching each root move. When a beta cutoff occurs you increment the counter:
betaCounter[pos.sideToMove()]++;
When root search returns you store the two values:
ourBeta = betaCounter[us];
oppBeta = betaCounter[them];
At the beginning of the next iteration you sort root moves as usually but using betaCounter instead of nodes. So here we have different schemes both for sorting and for increment the counter:
SORTING POLICY:
- Sort on ourBeta value
- Sort on oppBeta value (seems the best!)
- Sort on sum of betas, i.e. on total beta number
INCREMENT POLICY
When a beta cutoff occurs
- Increment the counter (as seen previously)
- Add depth ( betaCounter[threadID][pos.sideToMove()] += depth; )
- Add negated depth (betaCounter[threadID][pos.sideToMove()] += 20-depth;)
- Add the ply (this gives advantage to subtrees that goes further in the search).
I really hope you find this idea interesting because I would like you give it a try on your big iron and post the results.
Thanks in advance
Marco
Move order at ply one: a new idea
Moderators: hgm, Rebel, chrisw
-
- Posts: 4052
- Joined: Thu May 15, 2008 9:57 pm
- Location: Berlin, Germany
- Full name: Sven Schüle
Re: Move order at ply one: a new idea
I have not tried this yet, but I have two questions regarding your very interesting idea:
- For move ordering at the root, sorting criteria must be applied to each single move in the root move list, so I guess one single pair of "beta counters" would not be sufficient. How do you manage this? How do you compare the number of beta cutoffs move A produced with the number of beta cutoffs of move B? I'm pretty sure you do this correctly but I just don't see it from your code example.
- How do you handle the best move, and all other root moves that do not fail low and therefore possibly do not produce a high number of cutoffs? Even when the best move will be sorted first for the next iteration since it becomes the hash move, other moves that don't fail low might become a problem since their number of cutoffs might be less comparable to that of other moves.
Sven
- For move ordering at the root, sorting criteria must be applied to each single move in the root move list, so I guess one single pair of "beta counters" would not be sufficient. How do you manage this? How do you compare the number of beta cutoffs move A produced with the number of beta cutoffs of move B? I'm pretty sure you do this correctly but I just don't see it from your code example.
- How do you handle the best move, and all other root moves that do not fail low and therefore possibly do not produce a high number of cutoffs? Even when the best move will be sorted first for the next iteration since it becomes the hash move, other moves that don't fail low might become a problem since their number of cutoffs might be less comparable to that of other moves.
Sven
-
- Posts: 2684
- Joined: Sat Jun 14, 2008 9:17 pm
Re: Move order at ply one: a new idea
If you already have an implementation based on searched nodes, simply add two fields (ourBeta and theirBeta) to the same struct you use to store searched nodes for each move. In Stockfish/Glauring is struct RootMove. Then copy the results to them.Sven Schüle wrote:I have not tried this yet, but I have two questions regarding your very interesting idea:
- For move ordering at the root, sorting criteria must be applied to each single move in the root move list, so I guess one single pair of "beta counters" would not be sufficient. How do you manage this? How do you compare the number of beta cutoffs move A produced with the number of beta cutoffs of move B? I'm pretty sure you do this correctly but I just don't see it from your code example.
Conceptually and also technically it is almost the same of how you handle searched nodes for each move. Modifications in this regards are at a bare minimum. Actually you can implement the whole idea with about 10-20 lines of code.
I am not sure that a move that do not fail low does not produce an high number of cutoffs.Sven Schüle wrote: - How do you handle the best move, and all other root moves that do not fail low and therefore possibly do not produce a high number of cutoffs? Even when the best move will be sorted first for the next iteration since it becomes the hash move, other moves that don't fail low might become a problem since their number of cutoffs might be less comparable to that of other moves.
Sven
Actually I would be not surprised of the contrary: if a move doesn't fail low it means the search goes very deep before to return so an high number of cutoffs are produced in the secondary branches of the search.
Marco
-
- Posts: 4052
- Joined: Thu May 15, 2008 9:57 pm
- Location: Berlin, Germany
- Full name: Sven Schüle
Re: Move order at ply one: a new idea
O.k., now I got it.mcostalba wrote:If you already have an implementation based on searched nodes, simply add two fields (ourBeta and theirBeta) to the same struct you use to store searched nodes for each move. In Stockfish/Glauring is struct RootMove. Then copy the results to them.Sven Schüle wrote:How do you compare the number of beta cutoffs move A produced with the number of beta cutoffs of move B? I'm pretty sure you do this correctly but I just don't see it from your code example.
Conceptually and also technically it is almost the same of how you handle searched nodes for each move. Modifications in this regards are at a bare minimum. Actually you can implement the whole idea with about 10-20 lines of code.
Maybe you are right. I did a very quick test with my engine and saw a close relation between node count and number of cutoffs regarding their ordering, for each single root move. This includes also the best move and others that do not get refuted.mcostalba wrote:I am not sure that a move that do not fail low does not produce an high number of cutoffs.Sven Schüle wrote: - How do you handle the best move, and all other root moves that do not fail low and therefore possibly do not produce a high number of cutoffs?
Actually I would be not surprised of the contrary: if a move doesn't fail low it means the search goes very deep before to return so an high number of cutoffs are produced in the secondary branches of the search.
However, to get a significant improvement would require at least to get a different ordering based on cutoffs in "enough" cases, as compared to the ordering based on node counts. I doubt that currently but of course this can only be examined by trying it, which was your main intent here.
Sven
-
- Posts: 20943
- Joined: Mon Feb 27, 2006 7:30 pm
- Location: Birmingham, AL
Re: Move order at ply one: a new idea
When I have time, I will try to test this. It will take a bit of changing to the current code to both measure the cutoffs and then use them to sort the moves. I am not sure it will do better, although it might help in tactical test suites in some way. The one thing the current node count does not "capture" is "why is the sub-tree for this node larger than most others?" This could be because the cutoffs are not happening with the same frequency because at the new depth it is getting harder and harder to refute key branches. It could be because there are lots of checks that make the branh bushier than normal, even though the branch is not a real candidate to become best. It could be that the current move ordering is just not working very well, which makes the tree explode but again with no real chance to become the best move.Sven Schüle wrote:O.k., now I got it.mcostalba wrote:If you already have an implementation based on searched nodes, simply add two fields (ourBeta and theirBeta) to the same struct you use to store searched nodes for each move. In Stockfish/Glauring is struct RootMove. Then copy the results to them.Sven Schüle wrote:How do you compare the number of beta cutoffs move A produced with the number of beta cutoffs of move B? I'm pretty sure you do this correctly but I just don't see it from your code example.
Conceptually and also technically it is almost the same of how you handle searched nodes for each move. Modifications in this regards are at a bare minimum. Actually you can implement the whole idea with about 10-20 lines of code.
Maybe you are right. I did a very quick test with my engine and saw a close relation between node count and number of cutoffs regarding their ordering, for each single root move. This includes also the best move and others that do not get refuted.mcostalba wrote:I am not sure that a move that do not fail low does not produce an high number of cutoffs.Sven Schüle wrote: - How do you handle the best move, and all other root moves that do not fail low and therefore possibly do not produce a high number of cutoffs?
Actually I would be not surprised of the contrary: if a move doesn't fail low it means the search goes very deep before to return so an high number of cutoffs are produced in the secondary branches of the search.
However, to get a significant improvement would require at least to get a different ordering based on cutoffs in "enough" cases, as compared to the ordering based on node counts. I doubt that currently but of course this can only be examined by trying it, which was your main intent here.
Sven
I am not quite sure how your idea will pick up on the last two cases and leave them low in the list, while picking up on the first one and moving it up as we do now.
I even want to run a cluster test with the node-sort disabled as I now (and have for a long while) sort the root moves with a q-search call after making each move which is more accurate than static ordering I had used in the past. It might well be best now to just leave the move list alone and let the best moves bubble to the top naturally...
-
- Posts: 2251
- Joined: Wed Mar 08, 2006 8:47 pm
- Location: Hattingen, Germany
Re: Move order at ply one: a new idea
Poor Dr. Hyatt, so much to trymcostalba wrote:Dr. Hyatt, I think I really need your cluster here
The idea of node counts is based on the assumption that those moves with huge counts are more likely to become the new pv. The scheme somehow penalizes moves with "well ordered" sub-trees
What about further statistics for instance how often re-searches at pv-nodes occur, and how often it was a false "alarm". For zero window nodes, one may consider the parity of the ply-distance to the pv-node above (expected cut-nodes are odd, expected all-nodes even). And how often they behave not as expected (for each root move).
Another thing to consider - if best so far > drawscore, and some other move returns a true draw score with a very small subtree - scoring this move high makes sense. If the first move suddenly fails low far below draw score in the next iteration, it is good to find a fast draw early, before searching for something better.
-
- Posts: 3196
- Joined: Fri May 26, 2006 3:00 am
- Location: WY, USA
- Full name: Michael Sherwin
Re: Move order at ply one: a new idea
My very first attempt at a chess program was in 6502 assembler on an Atari 800 and it could make a list of moves if given a position.mcostalba wrote:Dr. Hyatt, I think I really need your cluster here
I have read your interested thread of some time ago regarding the historical reasons why the ordering at ply one is done (when score is equal) counting the nodes searched by each move subtree during the previous iteration.
I think I have come up with a different idea that seems better in my tests but needs confirmation.
The idea is to count the beta-cut offs instead of the nodes.
The advantage is that you can differentiate between _our_ beta cutoffs and _opponent_ cutoffs. So you actually have two counters:
int64_t betaCounter[2];
That are reset to zero before searching each root move. When a beta cutoff occurs you increment the counter:
betaCounter[pos.sideToMove()]++;
When root search returns you store the two values:
ourBeta = betaCounter[us];
oppBeta = betaCounter[them];
At the beginning of the next iteration you sort root moves as usually but using betaCounter instead of nodes. So here we have different schemes both for sorting and for increment the counter:
SORTING POLICY:
- Sort on ourBeta value
- Sort on oppBeta value (seems the best!)
- Sort on sum of betas, i.e. on total beta number
INCREMENT POLICY
When a beta cutoff occurs
- Increment the counter (as seen previously)
- Add depth ( betaCounter[threadID][pos.sideToMove()] += depth; )
- Add negated depth (betaCounter[threadID][pos.sideToMove()] += 20-depth;)
- Add the ply (this gives advantage to subtrees that goes further in the search).
I really hope you find this idea interesting because I would like you give it a try on your big iron and post the results.
Thanks in advance
Marco
Then years later I got an IBM 8086 machine dirt cheap and translated the Atari assembler to IBM 16 bit assembler. But, before I could finish making it play chess (a long time had passed) I got an 80386. I translated the code to 32 bit and managed with some effort to create a working but not quite legal engine.
This engine could hold it's own against Chessmaster 5000 untill the endgame. Now here follows the interesting part.
It was a material only engine, except that it kept track of the beta cutoffs for the root moves like you describe. It then played the best material score that had the largest number of beta cutoffs. The play was 'inspired', however, it always made captures when it could as those get the highest number of cutoffs.
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
-
- Posts: 2684
- Joined: Sat Jun 14, 2008 9:17 pm
Re: Move order at ply one: a new idea
Thanks !bob wrote: When I have time, I will try to test this.
Actually I would foreseen (with a big margin of error) that the ordering on the total number betas, us + opponent, would not differ to much form node counts.
The plus of this scheme is the flexibility and the possibility to tweak that you don't have for plain node counts.
As example I was surprised that first results show an advantage when you order on opponent beta (not on your good moves but on opponent good moves) this is somehow unexpected. Perhaps an explanation could be that when you find a real good move all the other moves of your ply will get a cutoff from the opponent becasue are sensibly lower then your first choice move.
Another promising tweak is the weighted increment on negated depth (betaCounter +=20-depth) or on ply number (betaCounter += ply). This gives bias to searches that go deeper. Note that also node count gives an indirect bias to deeper searches becasue number of nodes at low depths is bigger then at high depths. Weighting on ply just gives another push in the same direction.
Marco