The Problem
class is a wrapper for PlanningProblem
with some additional functionality and data-structures to handle real-world planning problems that involve time and resource constraints.
The Problem
class includes everything that the PlanningProblem
class includes.
Additionally, it also includes the following attributes essential to define a real-world planning problem:
jobs
to be doneresources
It also overloads the act
method to call the do_action
method of the HLA
class,
and also includes a new method refinements
that finds refinements or primitive actions for high level actions.
hierarchical_search
and angelic_search
are also built into the Problem
class to solve such planning problems.
from planningv2 import *
from notebook import psource
psource(Problem)
To be able to model a real-world planning problem properly, it is essential to be able to represent a high-level action (HLA) that can be hierarchically reduced to primitive actions.
Note: I have modified planningv2.py to include the debug decorator for HLA do_action
psource(debug)
psource(HLA)
In addition to preconditions and effects, an object of the HLA
class also stores:
duration
of the HLAcompleted
denoting if the HLA
has been completedThe class also has some useful helper methods:
do_action
: checks if required consumable and reusable resources are available and if so, executes the action.has_consumable_resource
: checks if there exists sufficient quantity of the required consumable resource.has_usable_resource
: checks if reusable resources are available and not already engaged.inorder
: ensures that all the jobs that had to be executed before the current one have been successfully executed.This is a simple problem involving the assembly of two cars simultaneously.
The problem consists of two jobs, each of the form [AddEngine
, AddWheels
, Inspect
] to be performed on two cars with different requirements and availability of resources.
Let's look at how the job_shop_problem
has been defined on the module.
psource(job_shop_problem)
The states of this problem are:
Has(x, y): Car 'x' has 'y' where 'y' can be an Engine or a Wheel.
~Has(x, y): Car 'x' does not have 'y' where 'y' can be an Engine or a Wheel.
Inspected(c): Car 'c' has been inspected.
~Inspected(c): Car 'c' has not been inspected.
In the initial state, C1
and C2
are cars and neither have an engine or wheels and haven't been inspected.
E1
and E2
are engines.
W1
and W2
are wheels.
Our goal is to have engines and wheels on both cars and to get them inspected. We will discuss how to achieve this.
Let's define an object of the job_shop_problem
.
jobShopProblem = job_shop_problem()
Before taking any actions, we will check if jobShopProblem
has reached its goal.
print(jobShopProblem.goal_test())
We now define a possible solution that can help us reach the goal.
The actions are then carried out on the jobShopProblem
object.
The following actions are available to us:
AddEngine1: Adds an engine to the car C1. Takes 30 minutes to complete and uses an engine hoist.
AddEngine2: Adds an engine to the car C2. Takes 60 minutes to complete and uses an engine hoist.
AddWheels1: Adds wheels to car C1. Takes 30 minutes to complete. Uses a wheel station and consumes 20 lug nuts.
AddWheels2: Adds wheels to car C2. Takes 15 minutes to complete. Uses a wheel station and consumes 20 lug nuts as well.
Inspect1: Gets car C1 inspected. Requires 10 minutes of inspection by one inspector.
Inspect2: Gets car C2 inspected. Requires 10 minutes of inspection by one inspector.
solution = [jobShopProblem.jobs[1][0],
jobShopProblem.jobs[1][1],
jobShopProblem.jobs[1][2],
jobShopProblem.jobs[0][0],
jobShopProblem.jobs[0][1],
jobShopProblem.jobs[0][2]]
for action in solution:
jobShopProblem.act(action)
The above output is due to the debug decorator. If you remove debug, there is no output.
print(jobShopProblem.goal_test())
This is a valid solution and one of many correct ways to solve this problem.
This problem is a simple case of a multiactor planning problem, where two agents act at once and can simultaneously change the current state of the problem.
A correct plan is one that, if executed by the actors, achieves the goal.
In the true multiagent setting, of course, the agents may not agree to execute any particular plan, but atleast they will know what plans would work if they did agree to execute them.
In the double tennis problem, two actors A and B are playing together and can be in one of four locations: LeftBaseLine
, RightBaseLine
, LeftNet
and RightNet
.
The ball can be returned only if a player is in the right place.
Each action must include the actor as an argument.
Let's first look at the definition of the double_tennis_problem
in the module.
psource(double_tennis_problem)
The states of this problem are:
Approaching(Ball, loc): The Ball
is approaching the location loc
.
Returned(Ball): One of the actors successfully hit the approaching ball from the correct location which caused it to return to the other side.
At(actor, loc): actor
is at location loc
.
~At(actor, loc): actor
is not at location loc
.
Let's now define an object of double_tennis_problem
.
doubleTennisProblem = double_tennis_problem()
Before taking any actions, we will check if doubleTennisProblem
has reached the goal.
print(doubleTennisProblem.goal_test())
As we can see, the goal hasn't been reached.
We now define a possible solution that can help us reach the goal of having the ball returned.
The actions will then be carried out on the doubleTennisProblem
object.
The actions available to us are the following:
Hit(actor, ball, loc): returns an approaching ball if actor
is present at the loc
that the ball is approaching.
Go(actor, to, loc): moves an actor
from location loc
to location to
.
We notice something different in this problem though,
which is quite unlike any other problem we have seen so far.
The goal state of the problem contains a variable a
.
This happens sometimes in multiagent planning problems
and it means that it doesn't matter which actor is at the LeftNet
or the RightNet
, as long as there is atleast one actor at either LeftNet
or RightNet
.
solution = [expr('Go(A, RightBaseLine, LeftBaseLine)'),
expr('Hit(A, Ball, RightBaseLine)'),
expr('Go(A, LeftNet, RightBaseLine)')]
for action in solution:
doubleTennisProblem.act(action)
doubleTennisProblem.goal_test()
Oops! It did not work! There is a bug in the code. Find the bug and report it in polleverywhere.
dir(doubleTennisProblem)
doubleTennisProblem.goals
doubleTennisProblem.init