Once more, with feeling
Let's continue the example for a bit. We have a hot hexapawn
game going, in which white made a move:
W W W
start - - -
B B B
/
/
/
/
/
/
- W W
white moves W - -
B B B
and then we (playing black) applied the minimax procedure to
find our best move from the board that our opponent had left
for us:
W W W
start - - -
B B B
/
/
/
/
/
/
- W W
white moves W - -
B B B
/ | \
/ | \
/ | \
our / | \
best / | \
move / | \
/ | \
- W W - W W - W W
0 B - - -10 W B - -10 W - B
B - B B - B B B -
/ | \ / \ / | \
/ | \ / \ / | \
/ | \ / \ / | \
/ | \ / \ / | \
- - W - - W - W - - W - - W - - W W - - W - - W
W - - B W - B - W W B W W W - - - B W W B W - W
B - B B - B B - B B - B B - B B W - B B - B B -
0 1 1 -10 -1 -10 0 -1
So we make our move, and then white counters with a move:
W W W
start - - -
B B B
/
/
/
/
/
/
- W W
white moves W - -
B B B
/
/
/
/
/
/
/
we - W W
move B - -
B - B
|
|
|
|
white - - W
moves B W
B - B
Note that white didn't make the move that we predicted would
be the best move for white. That happens a lot, but we don't
care. Regardless of the move that white made, we'd have to
go through the whole minimax thing again to decide our next
best move. So let's go through it one more time just to make
sure we follow how this all works. We start with the board
that was left after white's last move:
- - W
B W -
B - B
Then we generate the state space that results from all the
moves we could make followed by all the moves that our
opponent could make in response. (Remember that we've
arbitrarily set our search limit at two moves ahead...we
could have set that limit higher if we wanted to expend the
resources.)
- - W
B W -
B - B
/ ^ \
/ / \ \
/ / \ \
/ / \ \
/ / \ \
/ / \ \
B - W - - W - - W - - W
- W - B B - B B - B W B
B - B - - B B - - B - -
/ \ / \ / \
/ \ / \ / \
/ \ / \ / \
/ \ / \ / \
- - - - - - - - - - - - - - W - - W
B W - B B W B W - B B W B - B B - B
- - B - - B B - - B - - W - - B W -
Then we use our static board evaluation function to determine
the goodness of the "terminal boards":
- - W
B W -
B - B
/ ^ \
/ / \ \
/ / \ \
/ / \ \
/ / \ \
/ / \ \
B - W - - W - - W - - W
- W - B B - B B - B W B
B - B - - B B - - B - -
/ \ / \ / \
10 / \ / \ / \
/ \ / \ / \
/ \ / \ / \
- - - - - - - - - - - - - - W - - W
B W - B B W B W - B B W B - B B - B
- - B - - B B - - B - - W - - B W -
2 4 1 3 -10 -10
Then we propagate the minimums up from the result of white's
move (this is the "minimizing level"):
- - W
B W -
B - B
/ ^ \
/ / \ \
/ / \ \
/ / \ \
/ / \ \
/ / \ \
B - W - - W - - W - - W
- W - 2 B B - 1 B B - -10 B W B
B - B - - B B - - B - -
/ \ / \ / \
10 / \ / \ / \
/ \ / \ / \
/ \ / \ / \
- - - - - - - - - - - - - - W - - W
B W - B B W B W - B B W B - B B - B
- - B - - B B - - B - - W - - B W -
2 4 1 3 -10 -10
And then we would propagate the maximum value up and select
the best move to make. In this case, that move would be the
one on the left, with the board value of 10, which indicates
a win for us. Yippee!!
Alpha-beta pruning
If you think about it for a minute, we didn't really have to
go through all that board generation and evaluation and
propagation of values to figure out what to do on that last
move. As soon as we generated that move on the left side of
the state space above and realized that it was a winning move
(which is why we didn't generate any moves beyond that),
there was no reason to generate the rest of the state space
to the right. The first move that we looked at was so good
that it didn't matter what the other possibilities were. We
didn't recognize that because we were following our minimax
procedure blindly. But if we make our minimax procedure a
little bit smarter, we could reduce the cost of doing this
search by "pruning" our state space tree and getting rid of
some of the board generation, evaluation, and propagation,
all of which eat up computational resources.
Let's take a look at a simple abstract example of how this
might work. Let's say we start with some board:
start
board
And from that starting board, I have two possible moves. But
instead of generating all my moves in the sort of breadth-first
fashion that's implied by the examples above and in last week's
notes, I'm going to fall back on my old depth-first search
technique and generate just one of my moves, and explore all
of my opponent's moves in response to my move before I go and
look at my other move:
start
board
/
/
/
/
/
my
move
Now, again following my depth-first approach, and remembering
that I'm still cutting off my search at two moves ahead, I
look at one of my opponent's moves and apply the static board
evaluation function:
start
board
/
/
/
/
/
my
move
/
/
/
/
/
opp's
move
2
Let's say that my opponent has two possible moves after
either of my moves. We've just looked at one of the
opponent's possible moves, now well explore the other:
start
board
/
/
/
/
/
my
move
/ \
/ \
/ \
/ \
/ \
opp's opp's
move move
2 7
I then propagate the minimum value up from that level, and
begin to explore the possible outcomes of my other move:
start
board
/ \
/ \
/ \
/ \
/ \
2 my my
move move
/ \ /
/ \ /
/ \ /
/ \ /
opp's opp's opp's
move move move
2 7 1
The question now is "do I get any useful information from
exploring my opponent's remaining possible move?" And the
answer is "no". Why? Let's look at what could possibly
happen here. If I generate that last remaining board and
apply the board evaluation function to it, the value of that
board is either going to be greater than or equal to 1, or
it's going to be less than 1. In the former case, the value
that will be propagated up from this level is 1, a value that
I already knew. In the latter case, the value less than 1
would be propagated up, and I didn't know about that value
already. But, and this is the important but, either of those
values will be less than 2, which is the minimum value that
was propagated up from the other side of the tree. So based
on what I know from only exploring three of my opponent's
four possible moves, I can determine that the fourth possible
move will have no bearing on my decision about what move I
should make. I know I'm going to choose the move to the
left---the one where the worst my opponent can do to me is
leave me with a board with a value of 2. I know that I'm not
going to choose the move to the right, because my incomplete
exploration of the state space has already convinced me that
the best I can do if I go that direction is end up with a
board that has a value of 1. Oh, sure, maybe there's a
possibility that my opponent would do something stupid if I
took that move to the right and leave me with a +10 board and
I'd win, but I can't count on that. I have to assume that my
opponent is playing smart and playing to win. If I didn't
assume that, I wouldn't have to go through all this stuff in
the first place.
This is the informal description of what's called "minimax
with alpha-beta pruning". It's called alpha-beta because
traditionally, procedures which use this technique have a
paramater called alpha which holds the biggest of the maximum
value found and a parameter called beta which holds the
smallest of the minimum values found.
The usefulness of alpha-beta pruning is dependent upon the
order in which you generate and search the possible moves.
In some worst cases, there are orderings of the branches of
the tree for which alpha-beta provides no help. (What if the
two subtrees in the above example were explored in the
reverse order?) In more common cases, alpha-beta pruning
temporarily reduces the impact of exponentially increasing
amounts of search, but it does not prevent that exponential
increase. As the depth of the state space grows, the amount
of work required may still increase exponentially, but at a
reduced rate.
Let's take one more look at our real hexapawn game in this
context:
- W W
W - -
B B B
/ | \
/ | \
/ | \
/ | \
/ | \
/ | \
/ | \
- W W - W W - W W
0 B - - -10 W B - -10 W - B
B - B B - B B B -
/ | \ / \ / | \
/ | \ / \ / | \
/ | \ / \ / | \
/ | \ / \ / | \
- - W - - W - W - - W - - W - - W W - - W - - W
W - - B W - B - W W B W W W - - - B W W B W - W
B - B B - B B - B B - B B - B B W - B B - B B -
0 1 1 -10 -1 -10 0 -1
Could alpha-beta pruning have saved us some work in deciding
which move to make here? Sure. There are three moves we
didn't have to look at. They are marked with an X below:
X X X
- - W - - W - W - - W - - W - - W W - - W - - W
W - - B W - B - W W B W W W - - - B W W B W - W
B - B B - B B - B B - B B - B B W - B B - B B -
0 1 1 -10 -1 -10 0 -1
If you figured out that these were the moves that alpha-beta
pruning would have discarded without looking at them, and you
can explain why, then you know everything you need to know
about alpha-beta pruning.
Issue in knowledge representation
Way back in the early days of computing, folks were fascinated by
the possibility that computers might be able to exhibit intelligent
behavior if given the right kinds of knowledge. Problems like
solving puzzles and playing games were thought to be great domains
of study in the world of artificial intelligence, as only an entity
as intelligent as a human could solve a tile puzzle or play
checkers. As time went on, artificial intelligence researchers
realized that solving puzzles and playing games could be mastered
with relatively little intelligence, while more mundane tasks such
as reading a newspaper article or frying an egg without setting
the house on fire required much more intelligence than they
previously thought necessary. Along the way, however, AI folks
have devoted a lot of thought to how to represent the various
kinds of knowledge required to get a computer to do something
that at least looks like intelligent behavior. The ideas that
have resulted from those efforts, while by no means conclusive,
are now a part of mainstream computer science; you may never
do any AI work once you get out of Georgia Tech, but you may
find these ideas worth knowing, regardless of where your personal
voyage through computing takes you.
As we venture into the world of game playing, we're now faced
with questions about what kinds of knowledge are necessary to
play the game and how we're going to represent that knowledge.
As noted above, these are the same kinds of questions that AI
folks have been wrestling with for years. Resorting to broad
sweeping generalizations, we can use five questions to drive the
analysis of a complex problem, most of which involve knowledge:
1) What exactly is the activity that you want from the system
you're going to create to solve this complex problem?
2) What does your system need to know in order to perform
that activity?
3) How are you going to encode or represent that knowledge
inside your system? (e.g., What will the language of
symbols be? What will the symbols map to? etc.)
4) How will the system know which piece(s) of knowledge to use
at a given time, and how will the system get at the appropriate
knowledge without looking at all the knowledge?
5) Once the system finds the appropriate knowledge, how will it
use the knowledge?
You can think of item 1 as "defining the task or function of the
system", items 2 and 3 as "defining the knowledge representation
of the system", and items 4 and 5 as "defining the process of the
system":
Task: what the system does (i.e., what's the goal of the system?)
Knowledge: what the system needs to know to perform the task
Process: how the system performs the task
Good news, bad news
The good news (according to AI guru Elaine Rich, from whom most of
this knowledge representation stuff is borrowed) is that once a
problem is described using an appropriate representation, the
problem is almost solved. The bad news, however, is that describing
the knowledge correctly is pretty darn hard. Why? First, the
knowledge to perform some complex task well is usually fairly huge.
Second, that knowledge is probably pretty difficult to characterize
accurately. Third, if the system using that knowledge is going to
be flexible, that knowledge is probably not going to remain
constant; it'll probably change constantly.
If we were to try to draw inspiration from how humans represent
knowledge, we might first think of how humans traditionally
represent knowledge externally, for posterity. A quick look
at the library tells us that humans use languages common to
their respective cultures as well as pictures. But while those
representations might be useful for transferring knowledge
between individuals or between generations (within limits...a lot
of languages have died over the past few thousand years), they're
probably not what humans use to represent large amounts of knowledge
inside their heads. For example, while there is undoubtedly some
text in your head, it would be easy to demonstrate that you don't
record everything you hear or read as if you were a tape recorder.
Similarly, while there's certainly imagery in your head, the images
are by no means exact duplicates of what you saw...just ask any
criminal lawyer who depends on eyewitness testimony to make or
break a case.
Text and pictures aren't very good representations for computers,
either. Why? They tend to be open to interpretation: they're
ambiguous (the same expression can mean many things), they're
vague (sometimes it's hard to find any meaning), and the
"vocabulary" of representation tends to be huge and open-ended.
So what makes a good knowledge representation scheme for a computer?
The specifics of knowledge representation
Before we get into the attributes of a good knowledge representation
scheme, let's get a little bit more specific about what a knowledge
representation scheme actually is. A knowledge representation
scheme is a set of conventions about how to describe a class of
things. A description makes use of the conventions of a
representation to describe some particular thing within that class
of things. A given representation needs a set of symbols (i.e.,
a vocabulary) with some understood mapping between the symbols
and primitives in the "world" being represented (e.g., objects,
attributes, relationships, etc.). The representation also needs
some rules or conventions for how to order or combine symbols into
more complex expressions which then become descriptions; these
rules can be thought of as a syntax or grammar for the
representation language. Finally, a representation scheme needs
a set of operators or procedures which permit the creation and
manipulation of descriptions. Got it? Good.
What makes a good knowledge representation scheme?
There are a number of desirable characteristics of a knowledge
scheme. It's never possible to maximize all the attributes;
some will be sacrificed for others. But it's always good to know
what the trade-offs are so that you can make better informed
decisions.
1. The representation should capture generalities that exist in the
world that's being modelled.
2. The representation should be easily modifiable to reflect
changes so that new knowledge can be derived from old knowledge
(AI folks call this "inference") or so that entirely new
information can be added (this is "acquisition" or, sometimes,
"learning").
3. It should be understandable by the people who provide the
knowledge as well as those who may have to look at it later (so
that they don't have to convert the knowledge to or from some weird
form they don't understand). This attribute is also known as
"transparency".
4. It should be usable even if it is not entirely accurate or
complete.
5. The important objects and relationships should be explicitly
represented.
6. Any natural constraints on how one object or relation influences
another should be obvious.
7. Irrelevant detail should be suppressed (but it would be nice if
you could get at the details when necessary). Does the word
"abstraction" ring a bell?
8. The representation should be complete---you should be able to
represent everything that needs to be represented.
9. It should be concise, in that you can say what needs to be said
efficiently.
10. It should be fast, in that you can store and retrieve
information quickly.
So now you're knowledge representation experts. Well, no, not
really. But you know all the right kinds of questions to ask, and
you know how to tell if some possible answers to those questions are
better than others. And that makes you smarter, so what more could
you ask for?
Copyright 1998 by Kurt Eiselt. All rights reserved.
Last revised: November 10, 1998