-
Topics on basic technologies of NLP programs
-
-
Replacement table
-
-
Bruce Moreland/Text
-
-
A multi-function Data Structure
-
-
The search tree of chess can be represented by graphs, and the replacement node can be directed to the previously searched child tree. The replacement table can be used to detect this situation, thus avoiding repeated labor. If "1. E4 D6 2. D4" has already been searched, there is no need to search for "1. D4 D6 2. E4.
-
This reason may inspire designers of early computer chess programs, but now it is actually a secondary use of table replacement. In some situations, for example, the number of replicas detected in the Wang Bing mess without a path engineer is astonishing, so that the search can reach a deep depth in a short period of time.
-
Removing repetitive work is a major feature of table replacement. However, in general, the replacement of a table is more important. Each hash item has the best method in the situation. I explained in the chapter "Iteration deepening" that first, a good search method can greatly improve the search efficiency. Therefore, if you find the best method in the hash, you should first search for this method, which will improve the order of the method and reduce the branch factor, in this way, you can search more deeply in a short period of time.
-
-
Implementation
-
-
The primary replacement table is a hash array, and each hash item looks like this:
-
-
# Define hashfexact 0
-
# Define hashfalpha 1
-
# Define hashfbeta 2
-
Typedef struct taghashe {
-
U64 key;
-
Int depth;
-
Int flags;
-
Int value;
-
Move best;
-
} Hashe;
-
-
This hash array is based on the "Zobrist key value. You can obtain the key value of the situation and divide it by the number of items in the hash list to obtain the remainder. This hash represents the situation. Because many situations may play the same role as the hash, the hash item must contain a check value, which can be used to confirm that this item is what you are looking. The check value is usually a 64-bit number, that is, the first field in the above example.
-
After you get the result from the search, save it to the hash list. If you want to use a hash to avoid repeated work, it is important to remember how deep the search is. If you search for three layers on a node and then plan to perform a 10-layer search, you cannot consider the information in the hash item as accurate. Therefore, the search depth of the subtree must be recorded.
-
In alpha-Beta Search, you rarely get the exact value of the search node. The existence of alpha and beta helps you cut out useless sub-trees, but alpha-Beta has a small drawback. You usually don't know how bad a node is or how good it is, you just know that it is bad or good enough, so you don't need to waste more time.
-
Of course, this raises a problem: what value should be saved in the hash, and how to do it when you want to obtain it. The answer is to store a value and add a flag to demonstrate its meaning. In my example above, for example, you saved 16 in the evaluation domain and "hashfexact" in the flag domain, which means that the evaluation value of this node is 16; if "hashfalpha" is saved in the flag, the node value is 16 at most. If "hashfbeta" is saved, the value is at least 16.
-
When you encounter a specific situation in your search, it is easy to decide what content should be retained by the rating and logo. However, it is very important to avoid errors. Hash is very easy to make mistakes, and it is difficult to capture errors once they are made.
-
The last domain of my hash items saves the best method when I found this situation last time. Sometimes I don't get the optimal method, for example, in any case of low outbound boundary (return a value smaller than or equal to alpha), and in other cases, there must be the best method, for example, if the boundary is higher (a value greater than or equal to Beta is returned ). [Note: only leaf nodes do not have the optimal method. Even if the Alpha node is the only one, all methods are poor. You should also find the best method, it will bring great benefits to the deeper search.]
-
If the best method is found, it should be searched first.
-
The following is a demo program modified based on the Alpha-beta function. The changes are marked with conspicuous words:
-
-
Int alphabeta (INT depth, int Alpha, int beta ){
-
Int hashf = hashfalpha;
-
If (val = probehash (depth, alpha, beta ))! = Valunknown ){
-
// [Valunknown must be smaller than-infinity or greater than infinity, otherwise it will be confused with the evaluation value .]
-
Return val;
-
}
-
If (depth = 0 ){
-
Val = evaluate ();
-
Recordhash (depth, Val, hashfexact );
-
Return val;
-
}
-
Generatelegalmoves ();
-
While (movesleft ()){
-
Makenextmove ();
-
Val =-alphabeta (depth-1,-Beta,-alpha );
-
Unmakemove ();
-
If (Val> = beta ){
-
Recordhash (depth, beta, hashfbeta );
-
Return Beta;
-
}
-
If (Val> alpha ){
-
Hashf = hashfexact;
-
Alpha = val;
-
}
-
}
-
Recordhash (depth, Alpha, hashf );
-
Return Alpha;
-
}
-
-
The code for the two new functions is as follows:
-
-
Int probehash (INT depth, int Alpha, int beta ){
-
Hashe * phashe = & hash_table [zobristkey () % tablesize ()];
-
If (phashe-> key = zobristkey ()){
-
If (phashe-> depth> = depth ){
-
If (phashe-> flags = hashfexact ){
-
Return phashe-> val;
-
}
-
If (phashe-> flags = hashfalpha) & (phashe-> Val <= alpha )){
-
Return Alpha;
-
}
-
If (phashe-> flags = hashfbeta) & (phashe-> Val> = beta )){
-
Return Beta;
-
}
-
}
-
Rememberbestmove ();
-
}
-
Return valunknown;
-
}
-
-
Void recordhash (INT depth, int Val, int hashf ){
-
Hashe * phashe = & hash_table [zobristkey () % tablesize ()];
-
Phashe-> key = zobristkey ();
-
Phashe-> Best = bestmove ();
-
Phashe-> val = val;
-
Phashe-> hashf = hashf;
-
Phashe-> depth = depth;
-
}
-
-
The code you see is not as accurate as the aerospace science, but may be wrong, and I have not discussed the details yet. If there is an error in your program, it may be a very serious error.
-
[The above Code has a speed bottleneck, that is, the expression "zobristkey () % tablesize. Because "computer division becomes a fool", "tablesize" should be 2
NOnly when the divisor is 2
NThe time division can be replaced by the right shift command. The best way is to set a variable named "tablesizemask:
-
-
Int tablesizemask = tablesize ()-1;
-
Hashe * phashe = & hash_table [zobristkey () & tablesizemask];
-
-
Here, "tablesize ()" must also be 2
N. In many chess programs that can set the size of a table to replace, the allowed value increases exponentially, or 3 M, 6 m, 12 m, 24 m, etc. (if each hash item has 12 bytes ), it can be 4 m, 8 m, 16 m, 32 m, etc. (if each hash item has 16 bytes ).]
-
-
Replacement policy
-
-
The main details include when to overwrite the hash. In the above example, I used the "always Replace" policy to simply overwrite existing values. This may not be the best strategy. In fact, there has been a lot of work trying to find out which strategy is the best.
-
Another policy is "replace when the same depth or depth is greater ". The existing endpoint is retained unless the depth of the new situation is greater than or equal to the existing value in the hash list.
-
There is still much room for experimentation. In 1994, I asked this question on the Usenet (newsgroup Network System) newsgroup Rec. Games. Chess (now Rec. Games. Chess. Computer) and got Ken Thompson's answer.
-
The answer is to use two scattered lists. One uses the "always Replace" policy, and the other uses the "same depth or deeper replacement" policy ". When you do the test, both HASH lists are tested. If one of them can produce truncation, then you can. If neither of them can produce truncation, you may get at least one optimal method. In fact, two different methods may be obtained. Both methods should first (or second) Try.
-
You only need to simply execute the Record Based on the replacement policy.
-
If you use the policy of "replacing with the same depth or depth", your hash list may eventually be filled with expired but deep nodes. The solution is to clear the hash list every time you play the game, or add the "sequence" field to the hash, so that the policy becomes "same depth, or deeper, or the old search is replaced ".
-
I used the Thompson policy in my program ferret and ran well. Another program, gerbil, also uses this policy. You can check its source code.
-
[According to the translator's research results, only the "depth-first coverage" strategy (I .e. "Replace with the same depth or deeper") is used, and the effect is much better than "always Replace, the code is not complex, but the eye-catching part is newly added:
-
-
Void recordhash (INT depth, int Val, int hashf ){
-
Hashe * phashe = & hash_table [zobristkey () & (tablesize ()-1)];
-
If (phashe-> hashf! = Hashfempty & phashe-> depth ){
-
Return;
-
}
-
Phashe-> key = zobristkey ();
-
Phashe-> Best = bestmove ();
-
Phashe-> val = val;
-
Phashe-> hashf = hashf;
-
Phashe-> depth = depth;
-
}
-
-
If you use this code, you must set all the flag items in the hash list as "hashfempty" before each step ".]
-
-
Instability
-
-
When you replace a table, if you allow the search process to be truncated Based on the hash, there will be another problem, and your search will be subject to the "instability" bundle.
-
Instability is at least caused by the following factors:
-
1. You may be doing a 6-layer search, but if you get a 10-layer search result in the hash item, it may be truncated based on this value. In subsequent searches, this hash is overwritten, so you get two different values on this node.
-
2. The Zobrist key value cannot record the line to which the node arrives. Not every line on this node has the same result. If a line encounters a duplicate situation, the value of the hash item will be related to the route. Because repeated situations may lead to different scores or at least different scores.
-
As far as I know, there is no way to deal with these problems.
-
[In addition, if the game is found during the search process, the evaluation value will be close to "infinity" or "-infinity". In this case, the evaluation value cannot be simply recorded when the list is recorded, this issue will be discussed in the "Victory situation" discussed later.]
-
-
Http://www.seanet.com /~ Brucemo/topics/hashing.htm
-
Translator: Huang Chen ()
-
Type: full translation plus comments
Previous Basic Search Method-deepening Iteration
Next Advanced Search Method-Overview (1)
Go back to the Chinese chess encyclopedia-computer chess
From: http://www.elephantbase.net/computer/search_hashing.htm