Name: _____________________________________________
Student ID #: ___________________________________________
This is a closed-book examination — no notes, no books, no talking to your neighbor, no cell phone calls to Marvin Minsky and certainly no wide-ranging Web searches allowed.
2 pts Describing the test
1 Def’n of intelligence needed for AI
1 Discussing relationship between cognition and computation
2pts Humans follow instructions too (and they’re our only model)
1 pt Ability to adapt
1 pt for each and 1 pt for distinguishing goal tests
Initial state — The starting state the agent knows it is in
Operators — Actions available to an agent
Goal test — Can be either a set of states, or a property of a set of states
Path cost — Function that assigns a cost to a path
1 pt for each
Initial state — blank board, an array/matrix of size NxN
Operators — Place a marker for player i
Goal test — N markers in a row, column or diagonal for player i
Path cost — Don’t care (Number of moves isn’t right, because we don’t have to worry about cycles/infinite games)
3 pts CSP is restricted form of problem in which the operators are assignments of values to variables, states are particular assignments to variables and the goal test is stated in terms of constraints the assignments must satisfy
2 pts More efficient algorithms for CSP’s than in the general case
2 pts Search is well understood, and flexible because we can often cast many different problems as search problems (e.g., crossword puzzles, route finding, VLSI layout)
1 pt Some evidence that people engage in search themselves to solve some problems
function General-Search(problem, QUEUING-FN) returns solution or failure
nodes ß MakeQueue(Make-node(Initial-state(problem)))
loop do
if nodes is empty return failure
node ß Remove-Front(nodes)
if Goal-Test(node) then return node
nodes ß Queueing-Fn(nodes, Expand-Node(node))
end
function Depth-Limited-Search(problem, depthLimit, Optional: node)
if Goal-Test(node) then return node
if NodeDepth(node) = depthLimit then return failure
for each node in ExpandNode(node, problem)
solution ß Depth-Limited-Search(problem, limit, n)
If solution then return solution
end
function Iterative-Deepening-Search(problem) returns solution or failure
for depth = 0 to infinity
if Depth-Limited-Search(problem, depth) succeeds then return result
end
return failure
1 pt for each
When the search space is large (1) and the solution depth is not known (1)
Yes, it is efficient because even though it revisits many nodes, it revisits them in proportion to their depth, which is only log (n) where n is the total tree size. In other words, most of the nodes are at the bottom of the tree, and those nodes are visited the least frequently.
2 pts Uninformed
Initial state
Operators and their costs
Goal function
Search strategy
1 pt Informed
Problem-specific knowledge (Usu. heuristic evaluation function)
There are many reasons, but the simplest is that a good heuristic function might not be available. If the problem space is especially complex, and a heuristic function can only be very approximately estimated, then there won’t be much gain from heuristic search.
3 pts Admissible heuristics never overestimate the cost of achieving the solution (they’re optimistic)
2 pts Overestimation would skip paths that might yield the solution
Admissibility is needed for completeness, because complete algorithms must promise to find a solution. On the other hand, the more accurate your heuristic function is, the faster A* (or another best-first search) will work. Admissibility rules out functions which are always very, very close to the true cost, but sometimes exceed it. Thus, by sacrificing admissibility, you might see very large gains in efficiency.
(cons ‘a (cons (cons ‘b ‘c) ‘d))
Functional programming is modeled on the mathematical notion of function evaluation — the variable x is unchanged by the calculation of f(x). Programs are built by layering functions on top of one another (an "onion" structure), rather than a sequence of statements to execute (procedural programming). Because we have only function evaluation, and no side effects, this eliminates a common source of bugs, but also means that code can be executed in any order.
Functional programming works well with AI because it makes it easy to explore concepts by layering more complex behaviors on top of simpler ones, and the support that functional languages usually offer for symbols makes the transition from idea to code simpler.
2 pts A variable that is dynamically bound, as opposed to lexically bound. In other words, the value is resolved in the calling environment, not in the environment of definition. Global variables are always special variables.
1 pt for each way to avoid
Pass values as function arguments
Use closures
The Make-Cannibal-Problem procedure is automatically defined by the defstruct that creates cannibal problems, as are the slot accessors and other functions.
(defmethod initialize ((env grid-environment))
(unless (environment-initialized env)
(setf (grid-environment-grid env)
(make-array (grid-environment-size env)
:initial-element '()))
(parse-specs env (grid-environment-aspec env))
(parse-specs env (grid-environment-bspec env))
(parse-specs env (grid-environment-cspec env))
(call-next-method)))
The code initializes a grid environment (but only once) by creating an array to represent the grid squares. The code then creates the requested agents (aspec), basic objects (bspec) and changing objects (cspec) within the environment.
As its first step, the function RunEnvironment initializes the environment.
3 pts
(defmethod initialize ((env grid-environment))
(if (not (environment-initialized env))
(progn ; unless has an implicit progn
(setf (grid-environment-grid env)
(make-array (grid-environment-size env)
:initial-element '()))
(mapc #'(lambda (x)
(parse-specs env (funcall x env)))
'(grid-environment-aspec
grid-environment-bspec
grid-environment-cspec))
(call-next-method))))
1 pt I used mapc() because it doesn’t bother to cons up a list (as mapcar() does). Since the value of initialize will be the value of call-next-method(), there’s no point in returning a list — in other words, we’re only calling the aspec, bspec and cspec functions for their side effects.
2 pts Call-next-method() invokes the next most specific method of the applicable methods. When
call-next-method is called with no arguments, it passes the current method's original arguments to the next method.1 pt In this case, call-next-method() invokes initialize ((env environment)), which is specialized for any environment, not just the grid-environment.