Download Megan Reichlen

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts

Gene expression programming wikipedia , lookup

Existential risk from artificial general intelligence wikipedia , lookup

Computer chess wikipedia , lookup

Philosophy of artificial intelligence wikipedia , lookup

History of artificial intelligence wikipedia , lookup

Collaborative information seeking wikipedia , lookup

Artificial intelligence in video games wikipedia , lookup

Minimax wikipedia , lookup

Computer Go wikipedia , lookup

Transcript
Megan Reichlen
Artificial Intelligence
Assignment Five
10/14/08
Lecture One
Lecture One included a basic history of the Artificial Intelligence field. The
ancient history section discussed the ideas of the ancient Greeks that were similar to AI,
such as golems, mechanical toys, and some Greek myths, including Pygmalion and
Hephaestus. Mechanical toys comprised the bulk of artificial intelligence up until the
20th century. In the 1950s and 1960s, some new ideas were introduced. Asimov created
his three laws of robotics, and Claude Shannon performed an analysis of chess as a search
function.
The 50s and 60s were also the starting point for artificially intelligent programs.
Samuel’s checker playing program used learning techniques to become a better chess
player, and Newell and Simon’s General Problem Solver was able to solve any
formalized problem. The late 60s and the early 70s brought difficulties, as people began
to find the problems and limitations of some basic AI structures and as promises were not
fulfilled. The later 70s, however, brought expert systems into use, programs and robots
designed to do one thing extremely well. DENDRAL could generate “explanatory
hypotheses in organic chemistry”, and the Mycin program could diagnose blood
infections in patients. The use of expert systems continued in the 80s, exploding in
number and funding. In 1986, however, the difficulties of expanding these systems for
more general use became apparent, and the demand for them began to drop off.
The 1990s and 2000s brought further developments in the AI field, most notably
machine learning and a new approach to creating systems, a more holistic approach that
emphasized focusing on a bigger picture rather than the small segment the earlier expert
systems focused on. The internet brought a great deal of opportunity for artificial
intelligence as well, allowing for giant search programs like web crawlers.
After this history of AI, the core of artificial intelligence was the next topic
discussed in Lecture One. At the core of AI applications are problem-solving
components; the core of the solutions are search functions. The 8-puzzle, chess, and
checkers are all examples of problems solvable through search functions.
A search function begins with one state and a successor function – a function that
finds the next state. By using the successor function on each node found until the goal
state is found or all states have been explored, a search function can easily solve a
problem that would take much longer for a human to solve. Any well-defined search
function has five components: states, an initial state, a successor function, a goal test, and
a path cost. The basic algorithm for a search function is to create a node with the initial
state, find all successive nodes using the successor function, put the successor nodes on
the fringe, pull one off the fringe, check if it’s the goal state, and repeat using the
successor function. An informed search has a method to determine what order to put
nodes on the fringe such that the more likely nodes are searched first.
The textbook also contained some information that was not covered in the lecture.
The Turing Test, although mentioned in lecture, was discussed more thoroughly in the
textbook. Alan Turing proposed a simple test to determine if an agent should be
considered intelligent. Most theorists up to this point attempted to use many separate
qualifications to define intelligence, but Turing suggested a comparison with humans
instead. If a human, while interacting with the machine, were unable to tell that the
machine was not human, the machine would be considered intelligent. The basic Turing
Test does not require physical interaction, only written conversations; the total Turing
Test, however, also includes some physical interaction. For a machine to pass the Turing
Test it would need to be able to communicate in English (or another human language), it
would need to be able to represent what it knows, it would need reasoning, and it would
need learning. A lack of any of these features would be detectable by a person.
Lecture Two
Lecture Two covered various types of search functions. Breadth-first search
explores each node in sequence, always putting new nodes at the end of the fringe, and
never expanding a node at a deeper level until all the nodes on the current level have been
explored. Depth-first search is the opposite; it will expand a node, immediately expand
one of its children nodes, and continue moving deeper until it reaches a leaf node. At this
point it backs up to the deepest unexpanded node on the fringe.
Any algorithm can be evaluated using four measures: completeness, optimality,
time complexity, and space complexity. A complete algorithm is one that will always
find a solution, when one exists. If the search is optimal, this means it will always find
the best solution available. Time complexity is a measure of how long it takes for the
algorithm to produce an answer, and space complexity is determined by the amount of
memory an algorithm needs to complete. Neither breadth-first search nor depth-first
search perform well within these measures. Both are often slow to find a solution, and
breadth-first search often needs a lot of memory.
Depth-limited search performs somewhat better. When a bound can be
determined for a problem, there is no need to search past a certain point. This allows a
depth-first search that is more efficient in both time and space. It does not guarantee an
optimal solution, however. When no bound can be determined, an iterative-deepening
search can be used instead: a depth-limited search with an incrementing depth boundary
until the goal state is found.
Informed searches generally perform better than uninformed searches. An
informed search uses a guess, or heuristic, to decide which path seems most likely to
contain the solution. The heuristic determines the order nodes are put onto the fringe,
ensuring that the best guess is the first one taken. An example of an informed search is
using the estimated cost of the state to the goal state. In a route-planning algorithm, this
would be the straight-line distance between the next city and the goal city. This ensures
that the closest to the goal state is the next one searched.
The textbook discussed bidirectional search, a method that performs a search from
the initial state to the goal state at the same time as searching from the goal state to the
initial state. Each half of the search function checks the fringe of the other for the state
it’s currently expanding; if it is found, the solution can be returned. This search works
best when there is a single goal state and a single initial state. Otherwise, the successor
function for the backwards search (the predecessor function) would become more
complex. With a large number of possible goal states, the backwards search would have
to be performed from all of them, or from some intermediate state. This could negate the
benefit of performing a bidirectional search in the first place. A bidirectional search,
when both searches are breadth-first, is both optimal and complete, and takes less time
than other informed searches. However, since two search trees must be stored in
memory, the space complexity is higher.
Lecture Three
Best-first search a better form of informed search. With best first, the heuristic
guess of the remaining path cost is always added to the path cost so far. This creates an
estimation of the total path as the measure of each node. As long as the heuristic is
admissible, or never overestimates the actual cost of the path, this is called an A* search.
A* is complete, so it will always find a solution if one is available; it is also optimal,
since the solution it finds will always be the best one. An example of A* search for a
route-planning problem uses the same heuristic mentioned above, the straight-line
distance to the goal state, to determine the order nodes are put onto the fringe.
A suboptimal path cannot be selected with an A* search. Since the heuristic gives
a value to each path that includes the path traveled so far and the estimated remaining
path, the value of a suboptimal path will always be greater than the value of the optimal
path. Even if a suboptimal path appears better for a while, at some point the cost of the
path traveled so far plus the remaining estimate will be greater than that of the optimal
path, and the search function will return to the node in the optimal path for expansion.
A* is the fastest search function that is both optimal and complete.
Some further examples of admissible heuristics can be seen with the 8-puzzle.
Just 0, in fact, is one such heuristic; the number of misplaced tiles is another, and the total
Manhattan distance of all the tiles is a third. The Manhattan distance of a tile is the
number of ‘blocks’ that tile would have to move if there were no tiles in the way.
Although all three of these are admissible, the last one is the best one. Since it provides a
greater estimated cost than the other two, but necessarily remains below the actual cost of
the solution, it brings the search function closer to the solution with each iteration than
the first two heuristics would. Heuristics can be found through relaxing the problem,
making it simpler than the actual problem. The Manhattan distance heuristic simplifies it
by pretending that multiple tiles can occupy the same space. The number of misplaced
tiles assumes that a tile can ‘jump’ to its final location, and 0 simply assumes that there is
nothing to do. Learning functions can also be used to find heuristics.
Although A* is the fastest complete and optimal solution, it requires a great deal
of memory for large problems, sometimes too much for the algorithm to complete. IDA*
is a form of A* that reduces the amount of space needed, but it takes more time and can
still run out of memory. Iterative Deepening A* is a depth-limited A* search, with the
depth growing until a solution is found. Another way to limit the space used is a
simplified memory-bounded A*, a search function that deletes the worst nodes from
memory when it nears its memory limits. These nodes can be returned to later if the
solution is not found within the remaining nodes. This function also avoids repeating
nodes. As long as the shortest solution path fits into the allotted memory space, this
function is still optimal and complete.
Another successor function often used is exemplified in a hill-climbing search.
With this function, the algorithm climbs a hill, formed with the heuristic function. Rather
than keeping track of all nodes on a fringe, a hill-climbing search simply chooses the best
successor, if the successor is better than the current state, and expands it; then repeats.
When no successors are found that are better than the current one, it will return the
current state. This function is often used when the goal state is unknown. The initial
state is randomly chosen. A stochastic hill-climbing function follows the same idea, but
the successor is chosen randomly out of all successors better than the current state, rather
than choosing the best one. First-choice hill-climbing generates random successors until
one is found that is better than the current state, rather than attempting to generate all
successors. This is often used when there are large numbers of successor states.
All the searches discussed in lecture were offline search agents. The textbook
defined this term, and began talking about online search agents as well. An offline agent
is one that computes a solution before applying it; an online search, on the other hand,
takes one action at a time and re-computes between actions. The example mentioned in
the book to explain this is a chess-playing program: waiting to compute the entire game
before playing a move would take far too long. Instead, the program should compute
enough to figure out what the first move should be, make the move, and continue
computing after knowing the opponent’s response.
The learning real-time A* search was also discussed in the book, although only
mentioned in lecture. LRTA* builds an environment map as it searches, updating the
cost estimates for nodes as it leaves them. The next move is then chosen according to
which node is the best one, using the cost estimates to decide. Nodes that have not yet
been visited are always assumed to be the best nodes, encouraging new exploration. A
LRTA* search is complete, for finite spaces, but can be caught in an infinite space and
may never reach it’s goal. This search function is often used for online search agents,
because of its ability to update values.
Lecture Four
Simulated annealing was the first item on the docket for Lecture Four, since it
was only lightly discussed in Lecture Three. Simulated annealing is another search
function, one that is quite complicated but often finds the best solution when other
algorithms cannot. In simulated annealing, the initial state is chosen randomly.
Successor states are also chosen randomly; if the successor is better than the current state,
then go to it. If it is worse, go to it with some amount of probability. Otherwise, stay in
place and generate another successor. The probability of going to a worse state is
proportional to the temperature of the function, so that as the temperature cools, worse
states are less likely to be explored. A simulated annealing algorithm can be randomly
restarted, and can also be ‘heated up’ again in the middle.
The rest of Lecture Four was dedicated to Python. Python is an interpreted
language, one that does not need to be compiled (although it runs slower than other
languages as a result.) Other advantages to interpreted languages include the ability to
run programs from source code, or through a command prompt. Outside functions can
easily be imported with Python.
One major advantage to Python is the basic structure. Where most languages use
brackets of some sort to separate loops and decision structures, Python simply uses
indentation to determine decision levels. For example, anything to be contained within
an ‘if’ statement simply needs to be indented to one level past the if statement. This
enforces readability. Python’s dynamic type checking is another advantageous structural
difference from C and C++; variables do not need to be defined before use, and
operations can be performed on any type of variable. Python also supports objectoriented programming, with all the usual object-oriented features: inheritance, class
constructors, and class methods and member variables.
The built-in container types in Python are powerful and useful. Like Java and
C++, Python has a list type, essentially an indexed array. Tuples are similar to lists,
except the values within them cannot be changed. However, Python allows the
programmer to cast between types, and a tuple can be changed into a list for editing.
Python also uses sets, a type similar to a list, except that the order of elements within a set
is not preserved, and no element can have a duplicate in a set. Python also has
‘dictionaries’, similar to keyed arrays in other languages. Each value within a dictionary
is paired with a key. Although a value may be repeated, a key may only appear once in a
dictionary. Python’s for statement iterates over all these container types. Each type has
additional functions, such as sort for lists, len for lists, tuples, strings, and sets, and del for
dictionaries.
One useful feature Python has that was not discussed in class is the ability to
compile code. This allows for closed-source applications based on Python, something
many interpreted languages cannot handle. Ruby and PHP, for example, two other
commonly used interpreted languages, cannot be used for closed-source applications,
because they cannot easily be compiled into bytecode that the computer can run. Other
advantages of Python include the wide range of platforms it runs on and how easily it can
be integrated with C and C++. With this integration, sections of a program that would
run slowly in an interpreted language can be compiled in C or C++, and then plugged into
Python as a module. Using Python as the framework allows for easy readability, and
adding C/C++ for bottleneck portions can significantly speed up the program. Python
also provides GUI programming capabilities.
Lecture Five
Game playing and analysis comprises the bulk of Lecture Five. Adversarial
games make up the bulk of games played, especially zero-sum games, games where one
player wins and one loses. There are several different types of adversarial games,
including deterministic ones such as chess and checkers, random games with perfect
information such as backgammon and Monopoly (perfect information meaning both
players know the same information), and random games with imperfect information such
as card games and Scrabble. The only practical way for a computer to play these games
is to assume that the opponent is a perfect player and will always take the best move
available; otherwise, the number of states to be explored increases to a level that it
becomes impossible for the computer to play in a reasonable amount of time. Even
though this leaves open the possibility of the opponent ‘tricking’ the computer with
unexpected moves, after one such move the computer will be able to recalculate and
again be able to beat its opponent.
Computers search through the possible sequences to find the best move. A game
tree is generated that contains all the possibilities, and at each level the best move is
assumed to be taken by the player. This is called a minimax analysis – max is the move
that produces the maximum result for the computer, and min is the one that produces the
minimum (east desirable) move for the computer. Min is assumed to be the move the
opponent will take. Throughout the game tree, the players switch moves. The computer
will choose the max move for its turns, and the min move for its opponent’s turns,
thereby creating possible paths for the game to follow. The computer will then take the
move that results in the best win for itself.
The main problem with this analysis is its complexity. It is impossible to use for
chess, due to the large amounts of time and memory the computer would need to
calculate all the moves. Instead, - pruning is used to help keep complexity down.
This method keeps track of the best move so far for each opponent, and if a move looks
like it is worse than that best move, it is not explored. Max’s best move is stored in ,
and min’s in ;  has an initial value of -, and  holds +. For each move, the values
of the nodes to be explored are compared to  and  to determine how good the move is
and if it is worth exploring. For max’s moves, a node is only explored if min’s
subsequent move is greater than or equal to . If the node has a value greater than ,
then  becomes the value of that move. The opposite is true for min’s move: a new 
value is stored if that node’s value is less than the current , and a node is explored only
when max’s subsequent move is greater than .
- pruning does not affect the final result, and the space complexity drops
noticeably by not exploring nodes that will not happen. Complexity can decrease further
if the nodes can be ordered well through a heuristic function. Even with improved
complexity, though, chess cannot be calculated fully, and instead must rely upon
evaluation functions for the nodes and the end of the program’s depth limit. A good
evaluation function estimates how good a state is for the computer. Chess generally
utilizes a weighted sum of features for it’s evaluation function; the weights and features
can be tuned through repeated game play.
Computers are generally good at deterministic games; Othello, chess, and
checkers programs usually beat human opponents. Go, on the other hand, is far too
complex for a computer to even play decently. Non-deterministic games include random
estimators to aid computer gameplay. For bridge, as an example, the GIB program won
the 2000 championship by generating 100 random deals and choosing the best plays from
those.
In class, the discussion was centered on deterministic games. Games that include
chance, such as card games and dice games, are explored more thoroughly in the book.
The difference between deterministic games and games of chance is that the search tree
cannot be fully filled out for chance games. Without knowing what a dice roll will be, or
knowing what card will be drawn, a program cannot compute the course of the game, and
must have a different algorithm to decide the best moves. The problem is exacerbated for
imperfect knowledge games, where the two players have different information. As an
example, the book discusses a game of bridge in which the cards are face up, and
compares that to a hand with hidden cards. The example shows that not knowing a
certain piece of information changes the play – what would make sense with all available
knowledge may not make sense without that knowledge, even if the hand does not
change.