-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcreate-corpus-code.lisp
More file actions
341 lines (292 loc) · 13.1 KB
/
Copy pathcreate-corpus-code.lisp
File metadata and controls
341 lines (292 loc) · 13.1 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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
(in-package :monroe)
;; runs planner and outputs a plan corpus
;;;;;;;;;;;;;;;;;;;;;;;;;; loads ;;;;;;;;;;;;;;;;;;;
;; (load "nlib") ;; my library
;; (load "shop2random") ;; planner
;; (load "planlib") ;; code for generating plan lib
;; (load "monroe_plib") ;; plan library
;; (load "monroe_state") ;; state
;;;;;;;;;;;;;;;;;;;;;;;;;;;; shortcuts ;;;;;;;;;;;;;;;
;; (defun lcc () ;; loads this file
;; (load "create-corpus-code"))
(declaim (special *monroe*)) ;defined in monroe-config
(defun gg (size &key flat (object *monroe*) problem-file) ;; this one is for interactive calling
(cc-main "plib.txt" "corpus.txt" size object flat problem-file))
;;;;;;;;;;;;;;;;;;;;;;;;; global variables ;;;;;;;;;;;;;;;;;;;;
(defvar *flat-output* '()) ;; whether or not we're outputing for flat or hierarchical
(defparameter *corpus-max-depth* -1) ;; this keeps track of the maximum plan
;; tree depth for any of the sessions in the corpus, so we can
;; output it in the planlib and then use it in hierarchical recognition
;; to get around any recursive methods. It's a hack, but not
;; too ugly a one - we could always constrain our planner to not
;; output plans > max-depth (if we were doing it in a more principled
;; way
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; code ;;;;;;;;;;;;;;;;;;
(defun extract-acts (plan)
(every-other plan 1 0))
(defun munge (plan)
(extract-acts (car plan)))
(defun get-goal (prob)
(cdr (get-tasks prob)))
(defun get-schema (act)
;; returns the schema part of the action as an atom
(car act))
(defun get-params (act)
;; returns the params part as a lst
(cdr act))
(defun params-to-string (params)
;; turns a param list into a string (with commas)
(if (endp params)
""
(if (eq 1 (length params))
(format nil "~A" (car params))
;; else longer than 1
(format nil "~A,~A"
(car params)
(params-to-string (cdr params))))))
(defun act-to-string (act)
;; turns the action into a string
(format nil "~A(~A)"
(get-schema act)
(params-to-string (get-params act))))
(defun output-session-flat (goal plan outfile)
;; prints out this particular plan session
(format outfile "~%Goal: ~A~%" (act-to-string goal))
(mapc #'(lambda (act)
(format outfile " ~A~%" (act-to-string act)))
plan))
(defmethod choose-goal-schema ((obj monroe-config))
;; chooses the goal stochastically
(problist-choose-stochastic *top-goals*))
(defun create-atloc (objname loc)
;; creates the form (atloc objname loc)
`(atloc ,objname ,loc))
(defun gen-loc-pred (pred loc)
;; for a single predicate, returns a list of itself and its corresponding
;; atloc
(list pred (gen-loc-obj (second pred) loc)))
(defun gen-loc-obj (obj loc)
;; for a single object, generate location
(create-atloc obj loc))
(defun gen-fixed-loc (loclist possible-locs)
;; generates a location for a single list of predicates
;; and returns a list of those predicates and corresponding
;; atlocs
(labels
((gather-list (loclist loc)
;; goes through each element of list and adds the atloc to it
(if (endp loclist)
'()
(append (gather-list (cdr loclist) loc)
(gen-loc-pred (car loclist) loc)))))
(let ((loc (list-choose-uniform possible-locs)))
(gather-list loclist loc))))
(defun gen-fixed-locs (list possible-locs)
;; generates the fixed-state-need-loc part of the state
;; list is a list of lists of predicates, each list representing
;; an equivalence set of items that need to be colocated
;; this returns a list of those predicates as well as their
;; corresponding atloc predicates
(if (endp list)
'()
(append (gen-fixed-loc (car list) possible-locs)
(gen-fixed-locs (cdr list) possible-locs))))
(defun gen-fixed-start-state (fixed-state fixed-state-need-loc possible-locs)
;; generates the fixed part of the start state (everything but the
;; goal specific stuff
(append fixed-state
(gen-fixed-locs fixed-state-need-loc possible-locs)))
(defmethod common-state :before ((conf monroe-corpus-config))
(unless (slot-boundp conf 'common-state)
(setf (common-state conf)
(gen-fixed-start-state *fixed-state*
*fixed-state-need-loc*
*possible-locs*))))
(defun get-goal-func-name (schema-name)
;; this turns a schema name into a function name for that specific
;; function of the form gen-state-<schema-name>
;; returns this as a string
(format nil "GEN-STATE-~A" schema-name))
(defun gen-object (&optional (type 'obj))
(gensym (format nil "~A-" type)))
(defun gen-goal-and-state (schema)
;; generates the goal and the non-fixed part of the start state
;; i.e. the part that is specific to this goal schema
;; returns in form (goal state)
;; this function basically calls specific functions to the schema
(let* ((schema-name (get-schema schema))
(func-name (get-goal-func-name schema-name)))
;; this creates a function name based on the schema and calls it
(apply (intern func-name :monroe) (list schema-name))))
(defmethod generate-goal-and-start-state ((config-obj monroe-config) schema)
;; generates the goal and start state given the schema
;; it is easiest to just generate both together, since specific
;; code needs to be called for each goal schema
;; returns a 2-tuple of form (goal start-state)
(let* ((fixed-start-state (common-state config-obj))
(goal-and-state (gen-goal-and-state schema))
(goal (first goal-and-state))
(state (second goal-and-state))
(start-state (append state fixed-start-state)))
`(,goal ,start-state)))
(defun generate-problem (config-obj)
;; generates the problem (goal and state) to be used to plan with
;; doesn't return anything, the problem is stored internally
;; in the planner as 'generated-problem
(let* ((schema (choose-goal-schema config-obj))
(goal-and-start-state (generate-goal-and-start-state config-obj schema))
(goal (first goal-and-start-state))
(start-state (second goal-and-start-state)))
(make-problem 'generated-problem (domain-name config-obj) start-state goal)
(format t "~%Choosing goal: ~S~%" (get-tasks 'generated-problem)))
)
(defun atomic-level (action)
;; if the action is an atomic-level action
;; the output is (1.0 (!act param) num)
(numberp (car action)))
(defun output-goalchain (outfile goalstack action)
;; outputs a single line (i.e., goalchain and action)
;; also updates *corpus-max-depth*
(let ((depth (1+ (length goalstack))))
(if (> depth *corpus-max-depth*)
(setq *corpus-max-depth* depth)))
(format outfile "~A::~A~%"
(act-to-string action)
(perljoin ";"
(mapcar #'act-to-string goalstack))))
(defun output-plan (config-obj outfile plans)
(let ((*print-readably* t)
(*package* (plan-package config-obj)))
(destructuring-bind (plan-forests plan-sequences) plans
(let ((plan-forest (first plan-forests))
(plan-sequence (first plan-sequences)))
(if *flat-output*
(output-session-flat
(get-goal 'generated-problem)
(shop2:shorter-plan plan-sequence)
outfile)
;; else hierarchical output
(progn
;; ugh -- it's really horrible that the tree ISN'T A BLOODY TREE!
;; SHOP2's "trees" are really forests.
(mapcar #'(lambda (tree) (output-tree tree outfile)) plan-forest)
(terpri outfile)
(let ((*print-pretty* t)
(*print-readably* t))
(mapc #'(lambda (act) (print act outfile))
(shop2:shorter-plan plan-sequence)))
(terpri outfile)
(terpri outfile)))))))
;;; Print a plan tree, and as a side-effect, track the depth of the corpus.
(defun output-tree (tree stream)
(labels ((traverse (node depth)
(if (primitive-node-p node)
(progn
(when (> depth *corpus-max-depth*)
(setf *corpus-max-depth* depth))
(tree-node-task node))
(list (tree-node-task node) (mapcar #'(lambda (n) (traverse n (1+ depth))) (complex-node-children node))))))
(let ((tree
(traverse tree 0)))
(let ((*print-readably* t)
(*print-pretty* t))
(print tree stream)))))
(defun osp (plan)
;; test function to output a single plan
(with-open-file (outfile "test.pc" :direction :output
:if-exists :supersede
:if-does-not-exist :create)
(output-plan *monroe* outfile plan)))
(defun get-random-plan (config-obj &optional (which :random))
;; returns a random plan
(format T "~%generating problem")
(generate-problem config-obj) ;; generates the prob with goal
(format T "~%beginning to plan..")
(multiple-value-bind (plans runtime trees)
(generate-random-plan which)
(declare (ignore runtime))
(format T "finished planning~%")
;; monroe was based on lists, rather than multiple values...
(list trees plans)))
(defun generate-random-plan (&optional (which :random))
(find-plans 'generated-problem
:which which
:verbose 0
:plan-tree t))
(defun num-steps (plan)
;; returns the number of immediate children in the plan
;; i.e., the next level down (not atomic)
(length plan))
(defmethod plan-ok ((obj monroe-config) plan)
(declare (ignorable obj))
;; checks a generated plan to make sure we want to keep it
;; right now, makes sure plans are at least 2 steps (immediate subgoals) long
;; (1-step or 0-step plans aren't interesting to us)
;; NOTE: PLAN is a misnomer for this value, which is actually:
;; ( (PLAN-TREE) (PLAN-SEQUENCE) )
;; also, Nate checks the number of subgoals to the top-goal, rather than the number of which could underestimate the number of steps in the plan. I modified the check to agree with the comment, rather than maintaining it's
(let ((top-subgoals (complex-node-children (caaar plan))))
(if (> (num-steps top-subgoals) 2)
plan
(progn
(format t "~%bad plan: ~A~%" plan)
nil))))
(defun get-acceptable-plan (config-obj)
;; returns a random plan that is also acceptable (by plan-ok)
(LOOP :FOR plan = (get-random-plan config-obj)
:UNTIL (plan-ok config-obj plan)
:FINALLY (progn
(when *problem-filename*
(with-open-file (str *problem-filename*
:direction :output
:if-does-not-exist :create
:if-exists :append)
(let ((*print-readably* t)
(*package* (plan-package config-obj)))
(let ((problem (find-problem 'generated-problem)))
(setf (slot-value problem 'shop2::name) (gensym "PROB"))
(print problem str)))))
(return-from get-acceptable-plan plan))))
(defun get-sessions-single-problem (config-obj outstream)
;; creates a single problem and goal and extracts a plan for it
;; which it writes to outstream
(output-plan
config-obj
outstream
(get-acceptable-plan config-obj)))
(defun get-sessions-open-file (config-obj outstream problem-filename corpus-size)
;; auxiliary for get-sessions, takes an open file and writes
;; the corpus to it, called recursively to loop
;; to get each individual case
(let ((*problem-filename* problem-filename))
(dotimes (x corpus-size)
(format t "~%creating session~D~%" (1+ x))
(get-sessions-single-problem config-obj outstream)
)))
(defun get-sessions (config-obj filename problem-filename corpus-size)
(with-open-file (outstream filename :direction :output
:if-exists :supersede
:if-does-not-exist :create)
(get-sessions-open-file config-obj outstream problem-filename corpus-size)
;; will do this upon reading in into perl plan corpus
;;(if (not *flat-output*)
;;(format outfile "::Maximum Tree Depth: ~A~%" *corpus-max-depth*)))
))
(defun get-corpus (config-obj plib-filename corpus-filename corpus-size problem-filename)
;; do corpus stuff
(get-sessions config-obj corpus-filename problem-filename corpus-size)
;; write out plan library
(output-planlib config-obj plib-filename *corpus-max-depth*)
(values))
(defun cc-main (plib-filename
corpus-filename corpus-size
config-obj
&optional flat-output problem-file)
;; main routine
;; args = (string: plibfilename, outputfilename, num: corpus-size,[bool: flat-output])
(let ((*flat-output* flat-output) ;; set if we are outputting for flat or hierarchical
(*top-goals* (top-goals config-obj)))
(when problem-file (uiop:delete-file-if-exists problem-file))
(get-corpus config-obj plib-filename
corpus-filename corpus-size
problem-file)))