Skip to content

Commit 2207127

Browse files
ad71norvig
authored andcommitted
Minor update to planning.py (aimacode#923)
* PDDLs and Actions can now be defined using Exprs as well as Strings * Minor refactors
1 parent c65ac4e commit 2207127

File tree

1 file changed

+71
-26
lines changed

1 file changed

+71
-26
lines changed

planning.py

Lines changed: 71 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,25 @@ class PDDL:
1717

1818
def __init__(self, init, goals, actions):
1919
self.init = self.convert(init)
20-
self.goals = expr(goals)
20+
self.goals = self.convert(goals)
2121
self.actions = actions
2222

23-
def convert(self, init):
23+
def convert(self, clauses):
2424
"""Converts strings into exprs"""
25+
if not isinstance(clauses, Expr):
26+
if len(clauses) > 0:
27+
clauses = expr(clauses)
28+
else:
29+
clauses = []
2530
try:
26-
init = conjuncts(expr(init))
31+
clauses = conjuncts(clauses)
2732
except AttributeError:
28-
init = expr(init)
29-
return init
33+
clauses = clauses
34+
return clauses
3035

3136
def goal_test(self):
3237
"""Checks if the goals have been reached"""
33-
return all(goal in self.init for goal in conjuncts(self.goals))
38+
return all(goal in self.init for goal in self.goals)
3439

3540
def act(self, action):
3641
"""
@@ -61,34 +66,35 @@ class Action:
6166
"""
6267

6368
def __init__(self, action, precond, effect):
64-
action = expr(action)
69+
if isinstance(action, str):
70+
action = expr(action)
6571
self.name = action.op
6672
self.args = action.args
67-
self.precond, self.effect = self.convert(precond, effect)
73+
self.precond = self.convert(precond)
74+
self.effect = self.convert(effect)
6875

6976
def __call__(self, kb, args):
7077
return self.act(kb, args)
7178

72-
def convert(self, precond, effect):
79+
def convert(self, clauses):
7380
"""Converts strings into Exprs"""
81+
if isinstance(clauses, Expr):
82+
clauses = conjuncts(clauses)
83+
for i in range(len(clauses)):
84+
if clauses[i].op == '~':
85+
clauses[i] = expr('Not' + str(clauses[i].args[0]))
7486

75-
precond = precond.replace('~', 'Not')
76-
if len(precond) > 0:
77-
precond = expr(precond)
78-
effect = effect.replace('~', 'Not')
79-
if len(effect) > 0:
80-
effect = expr(effect)
87+
elif isinstance(clauses, str):
88+
clauses = clauses.replace('~', 'Not')
89+
if len(clauses) > 0:
90+
clauses = expr(clauses)
8191

82-
try:
83-
precond = conjuncts(precond)
84-
except AttributeError:
85-
pass
86-
try:
87-
effect = conjuncts(effect)
88-
except AttributeError:
89-
pass
92+
try:
93+
clauses = conjuncts(clauses)
94+
except AttributeError:
95+
pass
9096

91-
return precond, effect
97+
return clauses
9298

9399
def substitute(self, e, args):
94100
"""Replaces variables in expression with their respective Propositional symbol"""
@@ -138,10 +144,10 @@ def act(self, kb, args):
138144
def air_cargo():
139145
"""Air cargo problem"""
140146

141-
return PDDL(init='At(C1, SFO) & At(C2, JFK) & At(P1, SFO) & At(P2, JFK) & Cargo(C1) & Cargo(C2) & Plane(P1) & Plane(P2) & Airport(SFO) & Airport(JFK)',
147+
return PDDL(init='At(C1, SFO) & At(C2, JFK) & At(P1, SFO) & At(P2, JFK) & Cargo(C1) & Cargo(C2) & Plane(P1) & Plane(P2) & Airport(SFO) & Airport(JFK)',
142148
goals='At(C1, JFK) & At(C2, SFO)',
143149
actions=[Action('Load(c, p, a)',
144-
precond='At(c, a) & At(p, a) & Cargo(c) & Plane(p) & Airport(a)',
150+
precond='At(c, a) & At(p, a) & Cargo(c) & Plane(p) & Airport(a)',
145151
effect='In(c, p) & ~At(c, a)'),
146152
Action('Unload(c, p, a)',
147153
precond='In(c, p) & At(p, a) & Cargo(c) & Plane(p) & Airport(a)',
@@ -207,6 +213,25 @@ def shopping_problem():
207213
effect='At(y) & ~At(x)')])
208214

209215

216+
def socks_and_shoes():
217+
"""Socks and shoes problem"""
218+
219+
return PDDL(init='',
220+
goals='RightShoeOn & LeftShoeOn',
221+
actions=[Action('RightShoe',
222+
precond='RightSockOn',
223+
effect='RightShoeOn'),
224+
Action('RightSock',
225+
precond='',
226+
effect='RightSockOn'),
227+
Action('LeftShoe',
228+
precond='LeftSockOn',
229+
effect='LeftShoeOn'),
230+
Action('LeftSock',
231+
precond='',
232+
effect='LeftSockOn')])
233+
234+
210235
class Level:
211236
"""
212237
Contains the state of the planning problem
@@ -559,6 +584,26 @@ def goal_test(kb, goals):
559584
return None
560585

561586

587+
def socks_and_shoes_graphplan():
588+
pddl = socks_and_shoes()
589+
graphplan = GraphPlan(pddl)
590+
591+
def goal_test(kb, goals):
592+
return all(kb.ask(q) is not False for q in goals)
593+
594+
goals = expr('RightShoeOn, LeftShoeOn')
595+
596+
while True:
597+
if (goal_test(graphplan.graph.levels[-1].kb, goals) and graphplan.graph.non_mutex_goals(goals, -1)):
598+
solution = graphplan.extract_solution(goals, -1)
599+
if solution:
600+
return solution
601+
602+
graphplan.graph.expand_graph()
603+
if len(graphplan.graph.levels) >= 2 and graphplan.check_leveloff():
604+
return None
605+
606+
562607
def linearize(solution):
563608
"""Converts a level-ordered solution into a linear solution"""
564609

0 commit comments

Comments
 (0)