-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGraphplan.lean
More file actions
187 lines (159 loc) · 6.49 KB
/
Graphplan.lean
File metadata and controls
187 lines (159 loc) · 6.49 KB
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
184
185
186
187
import Graphplan.Basic
import Graphplan.FileParse
import Graphplan.Search.Basic
import Graphplan.Search.Linear
import Graphplan.Search.Graphplan
-- We use the definition in the Basic module to construct the example
-- for a STRIPS planning problem from the Wikipedia article on STRIPS.
-- The enum of positional variables
inductive Position
| A
| B
| C
deriving DecidableEq, Repr, Fintype
def Position.all : List Position := [Position.A, Position.B, Position.C]
-- Whether the monkey is currently high or low
inductive Height
| High
| Low
deriving DecidableEq, Repr, Fintype
def Height.all : List Height := [Height.High, Height.Low]
-- The Enum of propositional variables
inductive MonkeyBoxProp
| At (p : Position) -- The monkey is at position p
| BoxAt (p : Position) -- The box is at position p
| BananaAt (p : Position) -- The banana is at position p
| Level (h : Height) -- The monkey is at height h
| HasBanana -- The monkey has the banana
deriving DecidableEq, Repr, Fintype
open MonkeyBoxProp Position Height STRIPS
-- The Move Operator. Requires the monkey to be low and at some position p1.
def Move (p1 : Position) (p2 : Position) : STRIPS_Operator MonkeyBoxProp where
preconditions := {At p1, Level Low}
neg_preconditions := {}
add_effects := {At p2}
del_effects := {At p1}
-- The ClimbUp Operator. Requires the monkey to be at the same position as the box and be low.
def ClimbUp (p : Position) : STRIPS_Operator MonkeyBoxProp where
preconditions := {At p, BoxAt p, Level Low}
neg_preconditions := {}
add_effects := {Level High}
del_effects := {Level Low}
-- The ClimbDown Operator. Requires the monkey to be high (and at the same position as the box).
def ClimbDown (p : Position) : STRIPS_Operator MonkeyBoxProp where
preconditions := {At p, BoxAt p, Level High}
neg_preconditions := {}
add_effects := {Level Low}
del_effects := {Level High}
-- The MoveBox Operator. Requires the monkey to be low and at the same position as the box.
def MoveBox (p1 : Position) (p2 : Position) : STRIPS_Operator MonkeyBoxProp where
preconditions := {At p1, BoxAt p1, Level Low}
neg_preconditions := {}
add_effects := {BoxAt p2, At p2}
del_effects := {BoxAt p1, At p1}
-- The TakeBananas Operator. Requires the monkey to be high and at the same position as the bananas.
def TakeBananas (p : Position) : STRIPS_Operator MonkeyBoxProp where
preconditions := {At p, BananaAt p, Level High}
neg_preconditions := {}
add_effects := {HasBanana}
del_effects := {}
-- -- Because the actions have free variables (the positions),
-- -- we need to instantiate them for all possible values.
-- def All_MonkeyBox_Actions : (STRIPS_Operator MonkeyBoxProp) :=
-- { m : STRIPS_Operator MonkeyBoxProp | ∃ p1 p2 : Position, m = Move p1 p2 } ∪
-- { m : STRIPS_Operator MonkeyBoxProp | ∃ p : Position, m = ClimbUp p } ∪
-- { m : STRIPS_Operator MonkeyBoxProp | ∃ p : Position, m = ClimbDown p } ∪
-- { m : STRIPS_Operator MonkeyBoxProp | ∃ p1 p2 : Position, m = MoveBox p1 p2 } ∪
-- { m : STRIPS_Operator MonkeyBoxProp | ∃ p : Position, m = TakeBananas p }
-- The definition changed, we need it as an Array now (Set membership is not decidable)
-- So to make it easier, we just construct the array directly.
def All_MonkeyBox_Actions : Array (STRIPS_Operator MonkeyBoxProp × String) :=
let out_array := Id.run do
let mut arr := #[]
-- Add all Move actions
for p1 in Position.all do
for p2 in Position.all do
if p1 ≠ p2 then
arr := arr.push (Move p1 p2, s!"Move {repr p1} {repr p2}")
-- Add all ClimbUp actions
for p in Position.all do
arr := arr.push (ClimbUp p, s!"ClimbUp {repr p}")
-- Add all ClimbDown actions
for p in Position.all do
arr := arr.push (ClimbDown p, s!"ClimbDown {repr p}")
-- Add all MoveBox actions
for p1 in Position.all do
for p2 in Position.all do
if p1 ≠ p2 then
arr := arr.push (MoveBox p1 p2, s!"MoveBox {repr p1} {repr p2}")
-- Add all TakeBananas actions
for p in Position.all do
arr := arr.push (TakeBananas p, s!"TakeBananas {repr p}")
arr
out_array
-- Returns the canonical name of an action
def action_name (op : STRIPS_Operator MonkeyBoxProp) : Option String :=
let found := All_MonkeyBox_Actions.find? (fun x => x.fst = op)
found.map (fun x => x.snd)
-- The complete STRIPS planning problem for the monkey and bananas example.
def MonkeyBox_STRIPS_Plan : STRIPS_Plan MonkeyBoxProp where
prop_decidable := instDecidableEqMonkeyBoxProp
prop_repr := instReprMonkeyBoxProp
Actions := All_MonkeyBox_Actions.map (fun x => x.fst)
current_state := {At A, BoxAt B, BananaAt C, Level Low}
goal_states := {{HasBanana}}
prop_hashable := by {
refine { hash := ?_ }
intro p
match p with
| At A => exact 1
| At B => exact 2
| At C => exact 3
| BoxAt A => exact 4
| BoxAt B => exact 5
| BoxAt C => exact 6
| BananaAt A => exact 7
| BananaAt B => exact 8
| BananaAt C => exact 9
| Level Low => exact 10
| Level High => exact 11
| HasBanana => exact 12
}
-- The same example, but using the DSL operator `>-`
def Example_Simulation_End_state_DSL : STRIPS_Plan MonkeyBoxProp :=
MonkeyBox_STRIPS_Plan
>- Move A B
>- MoveBox B C
>- ClimbUp C
>- TakeBananas C
#eval Search.is_valid_plan Example_Simulation_End_state_DSL []
def main : IO Unit := do
IO.println file_parse_result
-- The list of actions defined above
def solution_actions : List (STRIPS_Operator MonkeyBoxProp) :=
[ Move A B,
MoveBox B C,
ClimbUp C,
TakeBananas C
]
#eval Search.is_valid_plan MonkeyBox_STRIPS_Plan solution_actions
-- Apply the linear search to the MonkeyBox_STRIPS_Plan
def initial_search_state := Search.mk_search_state MonkeyBox_STRIPS_Plan
-- def solution := linear_search initial_search_state
def solution := linear_search_proved initial_search_state
-- def solution := graphplan_search initial_search_state
def solution_repr :=
let _ := initial_search_state.plan.prop_repr
let op_rep : Repr (STRIPS_Operator MonkeyBoxProp) := by infer_instance
let _ : Repr (List (STRIPS_Operator MonkeyBoxProp)) := instReprList
solution.map (fun sol => sol.actions.map (fun op => repr op))
def new_solution_actions :=
solution.map (fun sol => sol.actions)
#eval Search.is_valid_plan MonkeyBox_STRIPS_Plan new_solution_actions.get!
def solution_names :=
solution.map (fun sol =>
sol.actions.map (fun op =>
match action_name op with
| some name => name
| none => "Unknown Action"))
#eval solution_names