-
Notifications
You must be signed in to change notification settings - Fork 0
/
example_have_cake.py
executable file
·183 lines (158 loc) · 6.36 KB
/
example_have_cake.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
from aimacode.logic import PropKB
from aimacode.planning import Action
from aimacode.search import (
Node, breadth_first_search, astar_search,
depth_first_graph_search, uniform_cost_search, greedy_best_first_graph_search,
Problem,
)
from aimacode.utils import expr
from lp_utils import (
FluentState, encode_state, decode_state
)
from my_planning_graph import PlanningGraph
from run_search import run_search
class HaveCakeProblem(Problem):
def __init__(self, initial: FluentState, goal: list):
self.state_map = initial.pos + initial.neg
Problem.__init__(self, encode_state(
initial, self.state_map), goal=goal)
self.actions_list = self.get_actions()
def get_actions(self):
# Action 1: Eating a Cake
# Preconditions
precond_pos = [expr("Have(Cake)")]
precond_neg = []
# Positive and Negative Effects
# Adds this to the positive state
effect_add = [expr("Eaten(Cake)")]
effect_rem = [expr("Have(Cake)")]
# Eat action is defined when you have a cake via precond_pos
# No precond_neg, so effect_rem returns cake
eat_action = Action(expr("Eat(Cake)"),
[precond_pos, precond_neg],
[effect_add, effect_rem])
# Action 2: Baking a Cake
# Preconditions
precond_pos = []
precond_neg = [expr("Have(Cake)")]
# Positive and Negative Effects
# Then uses these truth statements to flip the switches of whats in which state
effect_add = [expr("Have(Cake)")]
effect_rem = []
# Bake action is defined only when you have no cake via precond_pos
# If negative, after Bake(Cake) you Have(Cake)
bake_action = Action(expr("Bake(Cake)"),
[precond_pos, precond_neg],
[effect_add, effect_rem])
return [eat_action, bake_action]
# Test Action: Decorating a Cake
# Preconditions
# FIXME: Not really working out. Probably leaving too many positives or negatives for a goal.
precond_pos = [expr("Decorate(Cake)")]
precond_neg = [expr("Eaten(Cake)")]
# Positive and Negative Effects
effect_add = [expr("Have(Cake)")]
effect_rem = []
decorate_action = Action(expr("Decorate(Cake)"),
[precond_pos, precond_neg],
[effect_add, effect_rem])
return [decorate_action, bake_action]
def actions(self, state: str) -> list: # of Action
possible_actions = []
kb = PropKB()
kb.tell(decode_state(state, self.state_map).pos_sentence())
for action in self.actions_list:
is_possible = True
for clause in action.precond_pos:
if clause not in kb.clauses:
is_possible = False
for clause in action.precond_neg:
if clause in kb.clauses:
is_possible = False
if is_possible:
possible_actions.append(action)
return possible_actions
def result(self, state: str, action: Action):
new_state = FluentState([], [])
old_state = decode_state(state, self.state_map)
for fluent in old_state.pos:
if fluent not in action.effect_rem:
new_state.pos.append(fluent)
for fluent in action.effect_add:
if fluent not in new_state.pos:
new_state.pos.append(fluent)
for fluent in old_state.neg:
if fluent not in action.effect_add:
new_state.neg.append(fluent)
for fluent in action.effect_rem:
if fluent not in new_state.neg:
new_state.neg.append(fluent)
return encode_state(new_state, self.state_map)
def goal_test(self, state: str) -> bool:
kb = PropKB()
kb.tell(decode_state(state, self.state_map).pos_sentence())
for clause in self.goal:
if clause not in kb.clauses:
return False
return True
def h_1(self, node: Node):
# note that this is not a true heuristic
h_const = 1
return h_const
def h_pg_levelsum(self, node: Node):
# uses the planning graph level-sum heuristic calculated
# from this node to the goal
# requires implementation in PlanningGraph
pg = PlanningGraph(self, node.state)
pg_levelsum = pg.h_levelsum()
return pg_levelsum
def h_ignore_preconditions(self, node: Node):
# not implemented
count = 0
return count
## Let's try some different worlds
# World 1 - Preconditions: Have(Cake), !Eaten(Cake)
# World 2 - Preconditions: !Have(Cake), !Eaten(Cake) > uses Bake(Cake)
# World 3 - Preconditions: !Have(Cake), !Eaten(Cake) > uses Bake(Cake)
def have_cake():
def get_init():
pos = [
]
neg = [
expr('Have(Cake)'),
expr('Eaten(Cake)'),
]
return FluentState(pos, neg)
def get_goal():
return [expr('Have(Cake)'),
expr('Eaten(Cake)'),
]
return HaveCakeProblem(get_init(), get_goal())
if __name__ == '__main__':
p = have_cake()
print("**** Have Cake example problem setup ****")
print("Initial state for this problem is {}".format(p.initial))
print("Actions for this domain are:")
for a in p.actions_list:
print(' {}{}'.format(a.name, a.args))
print("Fluents in this problem are:")
for f in p.state_map:
print(' {}'.format(f))
print("Goal requirement for this problem are:")
for g in p.goal:
print(' {}'.format(g))
print()
print("*** Breadth First Search")
run_search(p, breadth_first_search)
print("*** Depth First Search")
run_search(p, depth_first_graph_search)
print("*** Uniform Cost Search")
run_search(p, uniform_cost_search)
print("*** Greedy Best First Graph Search - null heuristic")
run_search(p, greedy_best_first_graph_search, parameter=p.h_1)
print("*** A-star null heuristic")
run_search(p, astar_search, p.h_1)
# print("A-star ignore preconditions heuristic")
# rs(p, "astar_search - ignore preconditions heuristic", astar_search, p.h_ignore_preconditions)
# print(""A-star levelsum heuristic)
# rs(p, "astar_search - levelsum heuristic", astar_search, p.h_pg_levelsum)