I. Planning and search Everything we've seen so far (and everything we will see, for that matter) can be characterized as search. But as the kinds of problems being solved get bigger, the nature of the solution changes: the knowledge required to do the job increases dramatically, the operators become more complex, and the representation schemes are mixed together. If we add to all that the notion that there's an intelligent agent (e.g., a robot) acting in and making changes to the world...especially if we add the possibility that the agent's actions might be irrevocable, expensive, and maybe even fatal...then solutions to problems like this are often given the more specific name of "planning" instead of search. The name "planning" indicates a desire on the part of the agent to compute several, if not all, the steps of a problem- solving procedure before executing any of them. Planning requires lots of knowledge, especially about the operators that are available to the agent. To do planning well, the agent also needs comprehensive knowledge of the problem domain in advance...a map of the terrain, if you will. The need to have voluminous knowledge of the domain leads to a fundamental issue in planning: the frame problem. The frame problem is essentially this: given that the agent may move about in the domain and change things within the domain, how can we keep track of what changes and, more importantly, what doesn't change in the domain as time goes by? If you have an artificially small domain, like the tile puzzle, then the solution is simple: just make a copy of the entire domain with the changes explicitly shown. But if your domain is Meridiani Planum on Mars or 150 miles of dirt path in the Southern California desert, making copies of everything you know about the domain just to reflect relatively tiny changes can be very very expensive. II. The STRIPS solution One elegant solution to the frame problem was put forward back in the early 1970s in a program called STRIPS (STanford Research Institute Problem Solver). STRIPS was the planning software for the robot known as Shakey...you saw Shakey in the AI documentary. Shakey was the robot that "thought" for 15 minutes before moving one meter. STRIPS had an internal model of where it was in its world (the initial state) and knowledge of where it wanted to be (the goal state), and it found a sequence of operators (a plan) to get it from the initial state to the goal. So far, that's not exactly novel. What's novel is how STRIPS represented the intermediate states. Instead of making a copy of the previous state with changes explicitly represented, STRIPS subsequent states as the sequence of actions that would get it from the initial state to the state in question. To facilitate this, each operator in STRIPS carried with it the following information: preconditions: what must be true about the state of the world to use the operator add list: what becomes true about the world when the operator is applied delete list: what is no longer true when the operator is applied In the PowerPoint slides we walk through an example of how STRIPS solves an extremely simple problem in the blocks world domain. The example shows, step by step, how the simple STRIPS planner written in CILOG (Chapter 8.3, page 302) works when trying to stack one block on top of another. Here's the actual code after I tweaked it a bit: /* This is an implementation of the simple STRIPS planner shown on page 302 of the Computational Intelligence text. The domain is a very simple blocks world problem, and the representations of state and actions, while described in chapter 8 of the text, are adapted from a more complicated sample program and knowledge base found at http://www.cs.ubc.ca/spider/poole/ci/code/cilog/cilog_code/cilog_code.html (click on delrob_strips.pl). launch it with the query: cilog: ask goals(G) & achieve_all(G,init,Plan). Note that the add list is denoted here by "achieves" instead of "add", and that the add and delete lists aren't exactly lists. */ /* stack action */ preconditions(stack(X,Y),[cleartop(Y),holding(X)]). achieves(stack(X,Y),armempty). achieves(stack(X,Y),on(X,Y)). deletes(stack(X,Y),cleartop(Y)). deletes(stack(X,Y),holding(X)). /* unstack action */ preconditions(unstack(X,Y),[on(X,Y),cleartop(X),armempty]). achieves(unstack(X,Y),holding(X)). achieves(unstack(X,Y),cleartop(Y)). deletes(unstack(X,Y),on(X,Y)). deletes(unstack(X,Y),armempty). /* pickup action */ preconditions(pickup(X),[cleartop(X),ontable(X),armempty]). achieves(pickup(X),holding(X)). deletes(pickup(X),ontable(X)). deletes(pickup(X),armempty). /* putdown action */ preconditions(putdown(X),[holding(X)]). achieves(putdown(X),ontable(X)). achieves(putdown(X),armempty). deletes(putdown(X),holding(X)). /* initial situation */ holds(ontable(a),init). holds(ontable(b),init). holds(cleartop(a),init). holds(cleartop(b),init). holds(armempty,init). holds(ontable(c),init). holds(cleartop(c),init). achieves(init,X) <- holds(X,init). goals([ontable(b),cleartop(a),armempty,on(a,b)]). /* the simple STRIPS planner */ remove(X,[X|Y],Y). achieve_all([],W0,W0). achieve_all(Goals,W0,W2) <- remove(G,Goals,Rem_Gs) & achieve(G,W0,W1) & achieve_all(Rem_Gs,W1,W2). achieve(G,W,W) <- holds(G,W). achieve(G,W0,do(Action,W1)) <- achieves(Action,G) & preconditions(Action,Pre) & achieve_all(Pre,W0,W1).
Last revised: December 7, 2004