from planning import *
from notebook import psource
In the Air Cargo problem, we start with cargo at two airports, SFO and JFK. Our goal is to send each cargo to the other airport. We have two airplanes to help us accomplish the task. The problem can be defined with three actions: Load, Unload and Fly. Let us look how the air_cargo problem has been defined in the module.
psource(air_cargo)
At(c, a): The cargo 'c' is at airport 'a'.
~At(c, a): The cargo 'c' is not at airport 'a'.
In(c, p): Cargo 'c' is in plane 'p'.
~In(c, p): Cargo 'c' is not in plane 'p'.
Cargo(c): Declare 'c' as cargo.
Plane(p): Declare 'p' as plane.
Airport(a): Declare 'a' as airport.
In the initial_state
, we have cargo C1, plane P1 at airport SFO and cargo C2, plane P2 at airport JFK.
Our goal state is to have cargo C1 at airport JFK and cargo C2 at airport SFO. We will discuss on how to achieve this. Let us now define an object of the air_cargo
problem:
airCargo = air_cargo()
airCargo.goal_test()
airCargo.init
airCargo.goals
It returns False because the goal state is not yet reached. Now, we define the sequence of actions that it should take in order to achieve the goal.
The actions are then carried out on the airCargo
PlanningProblem.
The actions available to us are the following: Load, Unload, Fly
Load(c, p, a): Load cargo 'c' into plane 'p' from airport 'a'.
Fly(p, f, t): Fly the plane 'p' from airport 'f' to airport 't'.
Unload(c, p, a): Unload cargo 'c' from plane 'p' to airport 'a'.
This problem can have multiple valid solutions. One such solution is shown below.
solution = [expr("Load(C1 , P1, SFO)"),
expr("Fly(P1, SFO, JFK)"),
expr("Unload(C1, P1, JFK)"),
expr("Load(C2, P2, JFK)"),
expr("Fly(P2, JFK, SFO)"),
expr("Unload (C2, P2, SFO)")]
for action in solution:
airCargo.act(action)
airCargo.goal_test()
airCargo.init
Let's consider the problem of changing a flat tire of a car. The goal is to mount a spare tire onto the car's axle, given that we have a flat tire on the axle and a spare tire in the trunk.
psource(spare_tire)
At(obj, loc): object 'obj' is at location 'loc'.
~At(obj, loc): object 'obj' is not at location 'loc'.
Tire(t): Declare a tire of type 't'.
Let us now define an object of spare_tire
problem:
spareTire = spare_tire()
spareTire.goal_test()
As we can see, it hasn't completed the goal.
We now define a possible solution that can help us reach the goal of having a spare tire mounted onto the car's axle.
The actions are then carried out on the spareTire
PlanningProblem.
The actions available to us are the following: Remove, PutOn
Remove(obj, loc): Remove the tire 'obj' from the location 'loc'.
PutOn(t, Axle): Attach the tire 't' on the Axle.
LeaveOvernight(): We live in a particularly bad neighborhood and all tires, flat or not, are stolen if we leave them overnight.
solution = [expr("Remove(Flat, Axle)"),
expr("Remove(Spare, Trunk)"),
expr("PutOn(Spare, Axle)")]
for action in solution:
spareTire.act(action)
spareTire.goal_test()
Here is another way to solve the problem:
spareTire = spare_tire()
solution = [expr('Remove(Spare, Trunk)'),
expr('Remove(Flat, Axle)'),
expr('PutOn(Spare, Axle)')]
for action in solution:
spareTire.act(action)
spareTire.goal_test()
spareTire.init
Notice that both solutions work, which means that the problem can be solved irrespective of the order in which the Remove actions take place, as long as both Remove actions take place before the PutOn action.
We have successfully mounted a spare tire onto the axle.
This problem's domain consists of a set of cube-shaped blocks sitting on a table. The blocks can be stacked, but only one block can fit directly on top of another. A robot arm can pick up a block and move it to another position, either on the table or on top of another block. The arm can pick up only one block at a time, so it cannot pick up a block that has another one on it. The goal will always be to build one or more stacks of blocks. In our case, we consider only three blocks. The particular configuration we will use is called the Sussman anomaly after Prof. Gerry Sussman.
psource(three_block_tower)
On(b, x): The block 'b' is on 'x'. 'x' can be a table or a block.
~On(b, x): The block 'b' is not on 'x'. 'x' can be a table or a block.
Block(b): Declares 'b' as a block.
Clear(x): To indicate that there is nothing on 'x' and it is free to be moved around.
~Clear(x): To indicate that there is something on 'x' and it cannot be moved.
Let us now define an object of three_block_tower
problem:
threeBlockTower = three_block_tower()
threeBlockTower.goal_test()
threeBlockTower.init
threeBlockTower.goals
As we can see, it hasn't completed the goal.
We now define a sequence of actions that can stack three blocks in the required order.
The actions are then carried out on the threeBlockTower
PlanningProblem.
The actions available to us are the following: MoveToTable, Move
MoveToTable(b, x): Move box 'b' stacked on 'x' to the table, given that box 'b' is clear.
Move(b, x, y): Move box 'b' stacked on 'x' to the top of 'y', given that both 'b' and 'y' are clear.
solution = [expr("MoveToTable(C, A)"),
expr("Move(B, Table, C)"),
expr("Move(A, Table, B)")]
for action in solution:
threeBlockTower.act(action)
threeBlockTower.init
threeBlockTower.goal_test()
This problem requires us to acquire a carton of milk, a banana and a drill.
Initially, we start from home and it is known to us that milk and bananas are available in the supermarket and the hardware store sells drills.
Let's take a look at the definition of the shopping_problem
in the module.
psource(shopping_problem)
At(x): Indicates that we are currently at 'x' where 'x' can be Home, SM (supermarket) or HW (Hardware store).
~At(x): Indicates that we are currently not at 'x'.
Sells(s, x): Indicates that item 'x' can be bought from store 's'.
Have(x): Indicates that we possess the item 'x'.
shoppingProblem = shopping_problem()
shoppingProblem.init
shoppingProblem.goal_test()
Let's look at the possible actions
Buy(x, store): Buy an item 'x' from a 'store' given that the 'store' sells 'x'.
Go(x, y): Go to destination 'y' starting from source 'x'.
We now define a valid solution that will help us reach the goal.
The sequence of actions will then be carried out onto the shoppingProblem
PlanningProblem.
solution = [expr('Go(Home, SM)'),
expr('Buy(Milk, SM)'),
expr('Buy(Banana, SM)'),
expr('Go(SM, HW)'),
expr('Buy(Drill, HW)')]
for action in solution:
shoppingProblem.act(action)
shoppingProblem.goal_test()
shoppingProblem.init
This is a simple problem of putting on a pair of socks and shoes. The problem is defined in the module as given below.
psource(socks_and_shoes)
LeftSockOn: Indicates that we have already put on the left sock.
RightSockOn: Indicates that we have already put on the right sock.
LeftShoeOn: Indicates that we have already put on the left shoe.
RightShoeOn: Indicates that we have already put on the right shoe.
socksShoes = socks_and_shoes()
socksShoes.goal_test()
solution = [expr('RightSock'),
expr('RightShoe'),
expr('LeftSock'),
expr('LeftShoe')]
for action in solution:
socksShoes.act(action)
socksShoes.goal_test()
This problem requires us to reach the state of having a cake and having eaten a cake simlutaneously, given a single cake.
Let's first take a look at the definition of the have_cake_and_eat_cake_too
problem in the module.
psource(have_cake_and_eat_cake_too)
Since this problem doesn't involve variables, states can be considered similar to symbols in propositional logic.
Have(Cake): Declares that we have a 'Cake'.
~Have(Cake): Declares that we don't have a 'Cake'.
cakeProblem = have_cake_and_eat_cake_too()
cakeProblem.goal_test()
Let us look at the possible actions.
Bake(x): To bake ' x '.
Eat(x): To eat ' x '.
We now define a valid solution that can help us reach the goal.
The sequence of actions will then be acted upon the cakeProblem
PlanningProblem.
solution = [expr("Eat(Cake)"),
expr("Bake(Cake)")]
for action in solution:
cakeProblem.act(action)
cakeProblem.goal_test()
One might wonder if the order of the actions matters for this problem. It did not matter in the spare tire problem. Let's see for ourselves.
cakeProblem = have_cake_and_eat_cake_too()
solution = [expr('Bake(Cake)'),
expr('Eat(Cake)')]
for action in solution:
cakeProblem.act(action)
It raises an exception. Indeed, according to the problem, we cannot bake a cake if we already have one. In planning terms, '~Have(Cake)' is a precondition to the action 'Bake(Cake)'. Hence, this solution is invalid.