Skip to content

Commit 2f84be4

Browse files
Chipe1norvig
authored andcommitted
planning.py (aimacode#232)
* Added Action class for PDDL * Added tests for Action class * Changed doc string * Added PDLL class * Added Air-Cargo-problem * Tested Air Cargo Problem
1 parent 464ca5d commit 2f84be4

File tree

2 files changed

+163
-8
lines changed

2 files changed

+163
-8
lines changed

planning.py

Lines changed: 129 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,134 @@
11
"""Planning (Chapters 10-11)
22
"""
33

4-
# flake8: noqa
4+
from utils import Expr, expr, first
5+
from logic import FolKB
56

6-
import agents
7+
class PDLL:
8+
"""
9+
PDLL used to deine a search problem
10+
It stores states in a knowledge base consisting of first order logic statements
11+
The conjunction of these logical statements completely define a state
12+
"""
713

8-
import math
9-
import random
10-
import sys
11-
import time
12-
import bisect
13-
import string
14+
def __init__(self, initial_state, actions, goal_test):
15+
self.kb = FolKB(initial_state)
16+
self.actions = actions
17+
self.goal_test_func = goal_test
18+
19+
def goal_test(self):
20+
return self.goal_test_func(self.kb)
21+
22+
def act(self, action):
23+
"""
24+
Performs the action given as argument
25+
Note that action is an Expr like expr('Remove(Glass, Table)') or expr('Eat(Sandwich)')
26+
"""
27+
action_name = action.op
28+
args = action.args
29+
list_action = first(a for a in self.actions if a.name == action_name)
30+
if list_action is None:
31+
raise Exception("Action '{}' not found".format(action_name))
32+
if not list_action.check_precond(self.kb, args):
33+
raise Exception("Action '{}' pre-conditions not satisfied".format(action))
34+
list_action(self.kb, args)
35+
36+
class Action:
37+
"""
38+
Defines an action schema using preconditions and effects
39+
Use this to describe actions in PDDL
40+
action is an Expr where variables are given as arguments(args)
41+
Precondition and effect are both lists with positive and negated literals
42+
Example:
43+
precond_pos = [expr("Human(person)"), expr("Hungry(Person)")]
44+
precond_neg = [expr("Eaten(food)")]
45+
effect_add = [expr("Eaten(food)")]
46+
effect_rem = [expr("Hungry(person)")]
47+
eat = Action(expr("Eat(person, food)"), [precond_pos, precond_neg], [effect_add, effect_rem])
48+
"""
49+
50+
def __init__(self,action , precond, effect):
51+
self.name = action.op
52+
self.args = action.args
53+
self.precond_pos = precond[0]
54+
self.precond_neg = precond[1]
55+
self.effect_add = effect[0]
56+
self.effect_rem = effect[1]
57+
58+
def __call__(self, kb, args):
59+
return self.act(kb, args)
60+
61+
def substitute(self, e, args):
62+
"""Replaces variables in expression with their respective Propostional symbol"""
63+
new_args = [args[i] for x in e.args for i in range(len(self.args)) if self.args[i]==x]
64+
return Expr(e.op, *new_args)
65+
66+
def check_precond(self, kb, args):
67+
"""Checks if the precondition is satisfied in the current state"""
68+
#check for positive clauses
69+
for clause in self.precond_pos:
70+
if self.substitute(clause, args) not in kb.clauses:
71+
return False
72+
#check for negative clauses
73+
for clause in self.precond_neg:
74+
if self.substitute(clause, args) in kb.clauses:
75+
return False
76+
return True
77+
78+
def act(self, kb, args):
79+
"""Executes the action on the state's kb"""
80+
#check if the preconditions are satisfied
81+
if not self.check_precond(kb, args):
82+
raise Exception("Action pre-conditions not satisfied")
83+
#remove negative literals
84+
for clause in self.effect_rem:
85+
kb.retract(self.substitute(clause, args))
86+
#add positive literals
87+
for clause in self.effect_add:
88+
kb.tell(self.substitute(clause, args))
89+
90+
91+
def air_cargo():
92+
init = [expr('At(C1, SFO)'),
93+
expr('At(C2, JFK)'),
94+
expr('At(P1, SFO)'),
95+
expr('At(P2, JFK)'),
96+
expr('Cargo(C1)'),
97+
expr('Cargo(C2)'),
98+
expr('Plane(P1)'),
99+
expr('Plane(P2)'),
100+
expr('Airport(JFK)'),
101+
expr('Airport(SFO)')]
102+
103+
def goal_test(kb):
104+
required = [expr('At(C1 , JFK)'), expr('At(C2 ,SFO)')]
105+
for q in required:
106+
if kb.ask(q) is False:
107+
return False
108+
return True
109+
110+
## Actions
111+
# Load
112+
precond_pos = [expr("At(c, a)"), expr("At(p, a)"), expr("Cargo(c)"), expr("Plane(p)"), expr("Airport(a)")]
113+
precond_neg = []
114+
effect_add = [expr("In(c, p)")]
115+
effect_rem = [expr("At(c, a)")]
116+
load = Action(expr("Load(c, p, a)"), [precond_pos, precond_neg], [effect_add, effect_rem])
117+
118+
# Unload
119+
precond_pos = [expr("In(c, p)"), expr("At(p, a)"), expr("Cargo(c)"), expr("Plane(p)"), expr("Airport(a)")]
120+
precond_neg = []
121+
effect_add = [expr("At(c, a)")]
122+
effect_rem = [expr("In(c, p)")]
123+
unload = Action(expr("Unload(c, p, a)"), [precond_pos, precond_neg], [effect_add, effect_rem])
124+
125+
# Load
126+
# Used used 'f' instead of 'from' because 'from' is a python keyword and expr uses eval() function
127+
precond_pos = [expr("At(p, f)"), expr("Plane(p)"), expr("Airport(f)"), expr("Airport(to)")]
128+
precond_neg = []
129+
effect_add = [expr("At(p, to)")]
130+
effect_rem = [expr("At(p, f)")]
131+
fly = Action(expr("Fly(p, f, to)"), [precond_pos, precond_neg], [effect_add, effect_rem])
132+
133+
return PDLL(init, [load, unload, fly], goal_test)
134+

tests/test_planning.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from planning import *
2+
from utils import expr
3+
from logic import FolKB
4+
5+
def test_action():
6+
precond = [[expr("P(x)"), expr("Q(y, z)")]
7+
,[expr("Q(x)")]]
8+
effect = [[expr("Q(x)")]
9+
, [expr("P(x)")]]
10+
a=Action(expr("A(x,y,z)"),precond, effect)
11+
args = [expr("A"), expr("B"), expr("C")]
12+
assert a.substitute(expr("P(x, z, y)"), args) == expr("P(A, C, B)")
13+
test_kb = FolKB([expr("P(A)"), expr("Q(B, C)"), expr("R(D)")])
14+
assert a.check_precond(test_kb, args)
15+
a.act(test_kb, args)
16+
assert test_kb.ask(expr("P(A)")) is False
17+
assert test_kb.ask(expr("Q(A)")) is not False
18+
assert test_kb.ask(expr("Q(B, C)")) is not False
19+
assert not a.check_precond(test_kb, args)
20+
21+
def test_air_cargo():
22+
p = air_cargo()
23+
assert p.goal_test() is False
24+
solution =[expr("Load(C1 , P1, SFO)"),
25+
expr("Fly(P1, SFO, JFK)"),
26+
expr("Unload(C1, P1, JFK)"),
27+
expr("Load(C2, P2, JFK)"),
28+
expr("Fly(P2, JFK, SFO)"),
29+
expr("Unload (C2, P2, SFO)")]
30+
31+
for action in solution:
32+
p.act(action)
33+
34+
assert p.goal_test()

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy