Updates
Update 1
I tried this (2nd line): I added changing node color as first instruction in alphabeta function. I am getting this result:
Green nodes are visited nodes. It looks like, algorithm is going throw nodes correctly, right? But how to output correct values in nodes — I also need to do this? Minimum of children values, maximum of children values (excluding pruned branches).
Update 2
I tried to output alpha and beta to the tree nodes and didn't get correct result. This is code (line 18 and 31 were added). This is result of the code:
On this image I show strange places:
First arrow: why minimum of 7 and 6 is 5? Second arrow: why maximum of 4, 3 and 2 is 5? Strange. Thats why I think, that it is now working correctly.
Old question
Once upon a time I created similar question here. It was like: "why I get this error?". Lets rollback and created new one. This question will be: "How to display Alpha Beta Pruning algorithm result?"
I found pseudocode of this algorithm on the wiki. It can be found here.
My realization is below (it is on JavaScript, but I don't think that to answer this question you have to know JS or Java or C++ etc). The question is how to output result of this algorithm on the graph (tree structure)? On start I have this tree structure:
NOTE: I have tree structure (some amount of linked nodes), on which I will use alpha beta pruning algorithm, and I have another tree structure (for displaying results, lets call it "graph"). Nodes of tree, which I use to display graph are connected with nodes, which I use to find result of the algorithm.
So, code of the alpha beta pruning algroithm is below. Can you clarify what and where I have to output to display process/results of the algorithm correctly, please?
My assumption is to output alpha and beta, but I think, it is wrong. I tried it, but it doesn't work.
I want to display prunings and fill in all nodes in the tree with correct values.
This is my realization of minimax with alpha beta pruning:
function alphabeta(node, depth, alpha, beta, isMax, g) {
if((depth == 0) || (node.isTerminal == true)) {
return node.value;
}
if(isMax) {
console.log('maximizing');
for (var i in node.children) {
var child = node.children[i];
console.log(child);
alpha = Math.max(alpha, alphabeta(child, depth-1, alpha, beta, false, g));
if(beta <= alpha) {
console.log('beta '+beta+' alpha '+alpha);
break;
}
}
return alpha;
} else {
console.log('minimizing');
for (var i in node.children) {
console.log('1 child');
var child = node.children[i];
console.log(child);
beta = Math.min(beta, alphabeta(child, depth-1, alpha, beta, true, g));
if (beta <= alpha) {
console.log('beta '+beta+' alpha '+alpha);
break;
}
}
return beta;
}
}
Why don't you just store the nodes that are actually visited, and colour those nodes Red. Then you will see which nodes got evaluated compared to the entire tree. E.g.
After a long discussion in the comments, I think I can now shed light on this. As the alpha beta goes around the tree, it has three values, when operating on a given node, it has the alpha and beta that were carried down to it from its parent node, and then it has the best value it has found so far. If it finds a value outside the alpha-beta window, it immediately prunes, as it knows that this node is not an optimal move, irrespective of its value. Thus, for some nodes alpha beta never works out the "true value" of the node.
Thus, when you are asked to display the "result" of alpha beta, I mistakenly thought that you meant the alpha-beta window, since the "true value" is never necessarily evaluated.
You would need to write separate code to print the "true node values". I think that the minimax algorithm will do this for you.
Also, be aware when comparing by hand that if you are using a "set" of nodes, the list iterator is not guaranteed to return the nodes in a predictable order, so if inside the nodes you are using sets rather than lists, you might find that its hard to follow by hand. List iterators return in insertion order. Set iterators have no predictable iterator.
Related
So I am not asking diagonal view of a tree, which fortunately I already know. I am asking if I view a tree from 45-degree angle only a few nodes should be visible. So there is a plane which at an angle of 45-degrees from the x-axis. so we need to print all the nodes which are visible from that plane.
For example:
1
/ \
2 3
/ \ / \
4 5 6 7
So if I look from that plane, I will only see nodes [4, 6, 7] as 5 and 6 overlaps each other. If I add another node at 6, now it will hide 7. How to do that? I searched on internet but couldn't find the answer.
Thanks!
I am giving you an abstract answer as the question is not language specific.
The problem with logging trees like this is the use of recursion.
By that I mean the traversal is going down nodes and up nodes.
What if you wrote a height helper which would return the depth of the current node.
For each depth level, you place the value in an array.
Then, write the values of the array.
Then you could grab the length of the last array and determine the amount of spaces each node needs.
Allow the arrays to hold empty values or else you will have to keep track of which nodes dont have children.
int total_depth = tree.getTotalHeight();
int arr[total_depth] = {};
for(int i = total_depth; i--;){
// there is a formula for the max number of nodes at a given depth of a binary tree
arr[i] = int arr[maximum_nodes_at_depth]
}
tree.inorderTraverse(function(node){
int depth = node.getHeightHelper();
// check if item is null
if( node!=nullptr && node.Item != NULL)
{
arr[depth].push(node.Item)
}
else
{
arr[depth].push(NULL)
}
})
So now you would have to calculate the size of your tree and then dynamically calculate how many spaces should prefix each node. The lower the depth the more prefixed spaces to center it.
I apologize but the pseudocode is a mix of javascript and c++ syntax.... which should never happen lol
As part of my project, I have to use Decision tree that I am using "fitctree" function that is the Matlab function for classified my features that extracted with PCA.
I want to control number of Tree and tree depth in fitctree function.
anyone knows how can I do this? for example changed the number of trees to 200 and tree depth to 10. How am I going to do this?
Is it possible to change these value in decision tree?
Best,
fitctree offers only input parameters to control the depth of the resulting tree:
MaxNumSplits
MinLeafSize
MinParentSize
https://de.mathworks.com/help/stats/classification-trees-and-regression-trees.html#bsw6baj
You have to play with those parameters to control the depth of your tree. Thats because the decision tree only stops growing when purity is reached.
Another possibility would be to turn on pruning. Pruning will reduce the size of your tree by removing sections of the tree that provide little power to classify instances.
Let me assume that you are using ID3 algorithm. Its pseudocode can provide a way to control the depth of the tree.
ID3 (Examples, Target_Attribute, Attributes, **Depth**)
// Check the depth of the tree, if it is 0, we are going to break
if (Depth == 0) { break; }
// Else continue
Create a root node for the tree
If all examples are positive, Return the single-node tree Root, with label = +.
If all examples are negative, Return the single-node tree Root, with label = -.
If number of predicting attributes is empty, then Return the single node tree Root,
with label = most common value of the target attribute in the examples.
Otherwise Begin
A ← The Attribute that best classifies examples.
Decision Tree attribute for Root = A.
For each possible value, vi, of A,
Add a new tree branch below Root, corresponding to the test A = vi.
Let Examples(vi) be the subset of examples that have the value vi for A
If Examples(vi) is empty
Then below this new branch add a leaf node with label = most common target value in the examples
// We decrease the value of Depth by 1 so the tree stops growing when it reaches the designated depth
Else below this new branch add the subtree ID3 (Examples(vi), Target_Attribute, Attributes – {A}, Depth - 1)
End
Return Root
What algorithm does your fictree function try to implement?
I've read a lot of documents regarding minimax algorithm and it's implementation on the game of tic-tac-toe but I'm really having a hard time applying it.
Here are links that I've read 1, 2, 3, 4, 5 and an example using java 6
Considering the pseudocode: 7
function minimax(node, depth, maximizingPlayer)
if depth = 0 or node is a terminal node
return the heuristic value of node
if (maximizingPlayer is TRUE) {
bestValue = +∞
for each child of the node {
val = minimax(child, depth-1, FALSE)
bestValue = max(bestValue, val)
}
return bestValue
} else if maximizingPlayer is FALSE {
bestValue = -∞
for each child of the node {
val = minimax(child, depth-1, TRUE)
bestValue = min(bestValue, val)
}
return bestValue
}
Here are my questions:
1. What will I pass to the signature node, is it the valid moves for the current player?
2. What is + and - infinity, What are their possible values?
3. What is the relationship between minimax and the occupied cells on the board.
4. What are child nodes how are values extracted from it?
5. How will I determine the maximum allowed depth?
Node is the grid with the information of which cells were already played
±∞ is just a placeholder, you can take int.maxValue or any other "big"/"small" value in your programming language. It is used later as a comparison to the calculated value of a node and 0 might already be a valid value. (Your pseudocode is wrong there, if we assign +∞ to bestValue, we want min(bestValue, val) and max(bestValue, val) for -∞.
Not sure what you mean.
Child nodes are possible moves that can be made. Once no move can be made the board is evaluated and score is returned.
The search space in TicTacToe is very small, in other games a heuristic score is returned, depending if the situation is is favorable to the player or not. In your scenario there should be no hard depth.
First of all, stop asking 100 questions in one question. Ask one, try to understand and figure out whether you actually need to ask another.
Now to your questions:
What will I pass to the signature node, is it the valid moves for the
current player?
No, you will pass only node, depth, maximizingPlayer (who plays - min or max). Here for each child of the node you find the possible moves from that node. In real scenario most probably you will have a generator like getChildren using which you will get your children
What is + and - infinity, What are their possible values?
minimax algorithm just tries to find the maximum value over all minimum values recursively. What is the worst possible result a maximum player can get - -infinity. The worse for minimum is when maximum will get +infinity. So these are just starting values.
What is the relationship between minimax and the occupied cells on the
board.
Not sure what do you mean here. Minimax is the algorithm, occupied cell is an occupied cell. This question is similar to what is the relation between dynamic programming and csv file.
What are child nodes how are values extracted from it?
they are all possible positions that can be reached from your current position. For example
How will I determine the maximum allowed depth?
In standard minimax it is till you will reach the end of the tree. At the end of the tree your evaluation function will give you a reward. Because the tree is most of the time too huge to fit anywhere people use a cutoff and use approximation to evaluation function (heuristics). The easiest cut of is look n moves ahead and hope that your evaluation function is good enough and your opponent think n-1 moves ahead.
Hello,
I'm trying to understand the alpha beta pruning algorithm using chess as an example from the following code:
def minimax(position, depth):
"""Returns a tuple (score, bestmove) for the position at the given depth"""
if depth == 0 or position.is_checkmate() or position.is_draw():
return (position.evaluate(), None)
else:
if position.to_move == "white":
bestscore = -float("inf")
bestmove = None
for move in position.legal_moves():
new_position = position.make_move(move)
score, move = minimax(new_position, depth - 1)
if score > bestscore: # white maximizes her score
bestscore = score
bestmove = move
return (bestscore, bestmove)
else:
bestscore = float("inf")
bestmove = None
for move in position.legal_moves():
new_position = position.make_move(move)
score, move = minimax(new_position, depth - 1)
if score < bestscore: # black minimizes his score
bestscore = score
bestmove = move
return (bestscore, bestmove)
Here's the link to the blog I got it from: LINK (you can view the code from the link if you like highlighted syntax)
What I don't understand is that in alpha beta pruning the value of alpha and beta variable must change sometimes when you go higher up in a tree. I attached a picture explaining my problem - while I understand the steps 1), 2) and 3), I don't get the 4) step. I know that the 4) step should look like on the picture but I don't know what's going on in the code at that step that the values change.
I followed the code carefully but for some reason I ended up with a = 5 and b = 5 in the 4) step which is ridiculous because that would mean that the branch on the right would get removed which is obviously wrong.
I think your reasoning in your comments is not correct. From your comments, your implicitly believe the search goes to the right branch of tree then back to the left branch of the tree, which is of course incorrect.
Your logic is wrong because at the (5) non-leaf node on the left branch of the tree, the search has only visited the nodes underneath (the leaf nodes (5) and (4). It has not visited the nodes on the right branch of the tree and therefore has no idea what the value will be. Therefore your comment
"there is a max node (a square) and the choice is made between 5 (on the left) and 4 (on the right). And a MAX node above them wants a bigger value so I think alpha should be set to 5 which is a lower bound." is not correct.
It's wrong because only the root node (the max node) knows the value 4 on the right, but it can only be done AFTER step 4. In fact, it can only be done at the end of the search, after all the nodes in the right branch of the tree are visited.
I'm currently developing a solver for a trick-based card game called Skat in a perfect information situation. Although most of the people may not know the game, please bear with me; my problem is of a general nature.
Short introduction to Skat:
Basically, each player plays one card alternatingly, and every three cards form a trick. Every card has a specific value. The score that a player has achieved is the result of adding up the value of every card contained in the tricks that the respective player has won. I left out certain things that are unimportant for my problem, e.g. who plays against whom or when do I win a trick.
What we should keep in mind is that there is a running score, and who played what before when investigating a certain position (-> its history) is relevant to that score.
I have written an alpha beta algorithm in Java which seems to work fine, but it's way too slow. The first enhancement that seems the most promising is the use of a transposition table. I read that when searching the tree of a Skat game, you will encounter a lot of positions that have already been investigated.
And that's where my problem comes into play: If I find a position that has already been investigated before, the moves leading to this position have been different. Therewith, in general, the score (and alpha or beta) will be different, too.
This leads to my question: How can I determine the value of a position, if I know the value of the same position, but with a different history?
In other words: How can I decouple a subtree from its path to the root, so that it can be applied to a new path?
My first impulse was it's just not possible, because alpha or beta could have been influenced by other paths, which might not be applicable to the current position, but...
There already seems to be a solution
...that I don't seem to understand. In Sebastion Kupferschmid's master thesis about a Skat solver, I found this piece of code (maybe C-ish / pseudo code?):
def ab_tt(p, alpha, beta):
if p isa Leaf:
return 0
if hash.lookup(p, val, flag):
if flag == VALID:
return val
elif flag == LBOUND:
alpha = max(alpha, val)
elif flag == UBOUND:
beta = min(beta, val)
if alpha >= beta:
return val
if p isa MAX_Node:
res = alpha
else:
res = beta
for q in succ(p):
if p isa MAX_Node:
succVal = t(q) + ab_tt(q, res - t(q), beta - t(q))
res = max(res, succVal)
if res >= beta:
hash.add(p, res, LBOUND)
return res
elif p isa MIN_Node:
succVal = t(q) + ab_tt(q, alpha - t(q), res - t(q))
res = min(res, succVal)
if res <= alpha:
hash.add(p, res, UBOUND)
return res
hash.add(p, res, VALID)
return res
It should be pretty self-explanatory. succ(p) is a function that returns every possible move at the current position. t(q) is what I believe to be the running score of the respective position (the points achieved so far by the declarer).
Since I don't like copying stuff without understanding it, this should just be an aid for anyone who would like to help me out. Of course, I have given this code some thought, but I can't wrap my head around one thing: By subtracting the current score from alpha/beta before calling the function again [e.g. ab_tt(q, res - t(q), beta - t(q))], there seems to be some kind of decoupling going on. But what exactly is the benefit if we store the position's value in the transposition table without doing the same subtraction right here, too? If we found a previously investigated position, how come we can just return its value (in case it's VALID) or use the bound value for alpha or beta? The way I see it, both storing and retrieving values from the transposition table won't account for the specific histories of these positions. Or will it?
Literature:
There's almost no English sources out there that deal with AI in skat games, but I found this one: A Skat Player Based on Monte Carlo Simulation by Kupferschmid, Helmert. Unfortunately, the whole paper and especially the elaboration on transposition tables is rather compact.
Edit:
So that everyone can imagine better how the score develops thoughout a Skat game until all cards have been played, here's an example. The course of the game is displayed in the lower table, one trick per line. The actual score after each trick is on its left side, where +X is the declarer's score (-Y is the defending team's score, which is irrelevant for alpha beta). As I said, the winner of a trick (declarer or defending team) adds the value of each card in this trick to their score.
The card values are:
Rank J A 10 K Q 9 8 7
Value 2 11 10 4 3 0 0 0
I solved the problem. Intead of doing weird subtractions upon each recursive call, as suggested by the reference in my question, I subtract the running score from the resulting alpha beta value, only when storing a position in the transposition table:
For exact values (the position hasn't been pruned):
transpo.put(hash, new int[] { TT_VALID, bestVal - node.getScore()});
If the node caused a beta-cutoff:
transpo.put(hash, new int[] { TT_LBOUND, bestVal - node.getScore()});
If the node caused an alpha-cutoff:
transpo.put(hash, new int[] { TT_UBOUND, bestVal - node.getScore()});
Where:
transpo is a HashMap<Long, int[]>
hash is the long value representing that position
bestVal is either the exact value or the value that caused a cutoff
TT_VALID, TT_LBOUND and TT_UBOUND are simple constants, describing the type of transposition table entry
However, this didn't work per se. After posting the same question on gamedev.net, a user named Álvaro gave me the deciding hint:
When storing exact scores (TT_VALID), I should only store positions, that improved alpha.