-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdialogue-search.lisp
365 lines (336 loc) · 16.7 KB
/
dialogue-search.lisp
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
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
;;; dialogue-search.lisp Dialogue games as search trees
(in-package :dialogues)
(defclass dialogue-search-problem (problem)
((formula
:type formula
:accessor formula
:initform (error "A dialogue search problem requires an initial formula.")
:initarg :formula)
(ruleset
:type ruleset
:accessor ruleset
:initform (error "A dialogue search problem requires a ruleset.")
:initarg :ruleset)))
(defmethod goal-test :before ((problem dialogue-search-problem) node)
(expand node problem))
(defmethod goal-test ((problem dialogue-search-problem) node)
(and (null (successors node))
(proponent-move-p (last-move (state node)))))
(defmethod successors-in-problem ((dsp dialogue-search-problem) node)
(continuations (state node)))
(defun dialogue-search-bfs (rules initial-statement &optional more-nodes)
(let* ((initial-state (make-instance 'dialogue
:initial-formula initial-statement
:rulset rules))
(problem (make-instance 'dialogue-search-problem
:initial-state initial-state
:rules rules)))
(breadth-first-search-for-bottom-with-nodes problem more-nodes)))
(defun dialogue-search-dfs (rules initial-statement)
(let* ((initial-state (make-instance 'dialogue
:initial-formula initial-statement
:ruleset rules))
(problem (make-instance 'dialogue-search-problem
:initial-state initial-state
:rules rules)))
(depth-first-search-for-bottom problem)))
(defun bounded-dialogue-search-dfs (rules initial-statement depth &optional (initial-state (make-instance 'dialogue :initial-formula initial-statement :ruleset rules)))
(let ((problem (make-instance 'dialogue-search-problem
:initial-state initial-state
:rules rules)))
(depth-limited-dfs-search problem depth)))
(defun bounded-dialogue-search-bfs (rules initial-statement depth
&optional (initial-state (make-instance 'dialogue :initial-formula initial-statement :ruleset rules))
initial-queue)
(let ((problem (make-instance 'dialogue-search-problem
:initial-state initial-state
:rules rules)))
(bounded-bfs-with-nodes problem depth initial-queue)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Searching for strategies
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defclass dialogue-strategy-search-problem (problem)
((rules
:initform nil
:type list
:accessor rule)))
(defun strategy-successors (strategy rules)
(declare (ignore strategy rules))
nil)
(defun some-non-cutoff-result (pred list)
(if (null list)
nil
(loop
:with all-are-cutoffs = t
:for search-result :in list
:do
(let ((result (funcall pred search-result)))
(setf all-are-cutoffs (and all-are-cutoffs
(eq result :cutoff)))
(unless (eq result :cutoff)
(unless (null result)
(return t))))
:finally
(if all-are-cutoffs
(return :cutoff)
(return nil)))))
(defun every-disallowing-cutoffs (pred list)
(loop
:for elt :in list
:for result = (funcall pred elt)
:when (eq result :cutoff) :do (return :cutoff)
:when (null result) :do (return nil)
:finally (return t)))
(defun proponent-has-winning-strategy? (dialogue cutoff)
(cond ((minusp cutoff)
:cutoff)
((zerop cutoff)
(or (null (next-opponent-moves dialogue))
:cutoff))
(t (let ((every-result
(every-disallowing-cutoffs
#'(lambda (opponent-move)
(let ((dialogue-opponent
(add-move-to-dialogue dialogue
opponent-move)))
(some-non-cutoff-result
#'(lambda (proponent-move)
(let ((dialogue-proponent
(add-move-to-dialogue dialogue-opponent
proponent-move)))
(proponent-has-winning-strategy? dialogue-proponent
(- cutoff 2))))
(next-proponent-moves dialogue-opponent))))
(next-opponent-moves dialogue))))
(if (eq every-result :cutoff)
:cutoff
every-result)))))
(defgeneric intuitionistically-valid? (formula strategy-depth)
(:documentation "Does there exist a winning strategy for FORMULA having depth at most STRATEGY-DEPTH?"))
(defmethod intuitionistically-valid? ((formula atomic-formula) strategy-depth)
nil)
(defun tptp->dialogue (db ruleset)
(let ((c (conjecture-formula db))
(premises (non-conjecture-formulas db)))
(setf c (formula c))
(setf premises (mapcar #'formula premises))
(setf c (equivalence->conjunction c))
(cond ((atomic-formula-p c)
(if (null premises)
(error "Cannot make a dialogue for a TPTP database having only an atomic conjecture formula.")
(make-instance 'dialogue
:initial-formula (make-implication (binarize (apply #'make-multiple-arity-conjunction premises)) c)
:ruleset ruleset)))
((null premises)
(make-instance 'dialogue
:initial-formula c
:ruleset ruleset))
((length= 1 premises)
(let* ((premise (first premises))
(initial-formula (make-implication premise c))
(dialogue (make-instance 'dialogue
:initial-formula initial-formula
:ruleset ruleset))
(i 0))
(setf dialogue
(add-move-to-dialogue dialogue
(make-instance 'opponent-move
:attack t
:reference 0
:statement premise)))
(incf i)
(add-move-to-dialogue dialogue
(make-instance 'proponent-move
:attack nil
:reference 1
:statement c))))
(t
(let* ((conjunction (binarize (apply #'make-multiple-arity-conjunction premises)))
(initial-formula (make-implication conjunction c))
(dialogue (make-instance 'dialogue
:initial-formula initial-formula
:ruleset ruleset))
(i 0)
(lhs (lhs conjunction))
(rhs (rhs conjunction)))
(setf dialogue
(add-move-to-dialogue dialogue
(make-instance 'opponent-move
:attack t
:reference 0
:statement conjunction)))
(incf i)
(while (and premises (rest premises))
(let ((rest (rest premises)))
(setf dialogue
(add-move-to-dialogue dialogue
(make-instance 'proponent-move
:attack t
:reference i
:statement *attack-left-conjunct*)))
(incf i)
(setf dialogue
(add-move-to-dialogue dialogue
(make-instance 'opponent-move
:attack nil
:reference i
:statement lhs)))
(incf i)
(setf dialogue
(add-move-to-dialogue dialogue
(make-instance 'proponent-move
:attack t
:reference (- i 2)
:statement *attack-right-conjunct*)))
(incf i)
(setf dialogue
(add-move-to-dialogue dialogue
(make-instance 'opponent-move
:attack nil
:reference i
:statement rhs)))
(incf i)
(setf lhs (second premises))
(setf rhs (third premises))
(setf premises rest)))
(setf dialogue (add-move-to-dialogue dialogue
(make-instance 'proponent-move
:attack nil
:reference 1
:statement c))))))))
(defmethod intuitionistically-valid? ((tptp pathname) strategy-depth)
(intuitionistically-valid? (parse-tptp tptp) strategy-depth))
(defmethod intuitionistically-valid? ((db tptp-db) strategy-depth)
(if (contains-quantifier-p db)
(loop
:for term-depth = 0
:for ruleset = (make-instance 'ruleset
:description (format nil "E, maximum term depth = ~d" term-depth)
:expander #'(lambda (dialogue)
(e-fol-expander--no-repetitions+prefer-defenses dialogue term-depth))
:validator #'e-fol-validator)
:for dialogue = (tptp->dialogue db ruleset)
:for search-result = (proponent-has-winning-strategy? dialogue strategy-depth)
:do
(when search-result
(unless (eql search-result :cutoff)
(return t))))
(let ((dialogue-1 (tptp->dialogue db *e-ruleset--no-repetitions*))
(dialogue-2 (tptp->dialogue db *e-ruleset--prefer-defenses*))
(dialogue-3 (tptp->dialogue db *e-ruleset*)))
(let ((search-result-1 (proponent-has-winning-strategy? dialogue-1 strategy-depth)))
(cond ((eql search-result-1 :cutoff)
(let ((search-result-2 (proponent-has-winning-strategy? dialogue-2 strategy-depth)))
(cond ((eql search-result-2 :cutoff)
(proponent-has-winning-strategy? dialogue-3 strategy-depth))
(search-result-2
t)
(t
(proponent-has-winning-strategy? dialogue-3 strategy-depth)))))
(search-result-1
t)
(t
(let ((search-result-2 (proponent-has-winning-strategy? dialogue-2 strategy-depth)))
(cond ((eql search-result-2 :cutoff)
(proponent-has-winning-strategy? dialogue-3 strategy-depth))
(search-result-2
t)
(t
(proponent-has-winning-strategy? dialogue-3 strategy-depth))))))))))
(defmethod intuitionistically-valid? ((formula formula) strategy-depth)
(if (contains-quantifier-p formula)
(loop
:for term-depth = 0
:for ruleset = (make-instance 'ruleset
:description (format nil "E, maximum term depth = ~d" term-depth)
:expander #'(lambda (dialogue)
(e-fol-expander--no-repetitions+prefer-defenses dialogue term-depth)))
:for dialogue = (make-instance 'dialogue
:initial-formula formula
:ruleset ruleset)
:for search-result = (proponent-has-winning-strategy? dialogue strategy-depth)
:do
(when search-result
(unless (eql search-result :cutoff)
(return t))))
(let ((dialogue (make-instance 'dialogue
:initial-formula formula
:ruleset *e-ruleset--no-repetitions*)))
(proponent-has-winning-strategy? dialogue strategy-depth))))
(defun develop-dialogue-tree-to-depth (tree-root depth problem)
(let ((expandable-leaves (expandable-leaf-nodes tree-root)))
(dolist (leaf expandable-leaves tree-root)
(exhaustive-depth-limited-search problem depth leaf))))
(defun copy-search-tree-node (node)
(make-instance 'dialogues::node
:state (state node)
:parent (parent node)
:action (action node)
:successors (mapcar #'copy-search-tree-node (successors node))
:depth (depth node)
:expanded-p (expanded-p node)))
(defun dialogue->search-tree (dialogue)
"Construct a search tree (a sequence, in fact) from DIALOGUE."
(let (nodes)
(dotimes (i (dialogue-length dialogue)) ; first construct the nodes
(push (make-instance 'dialogues::node
:state (truncate-dialogue dialogue i)
:parent nil
:action nil
:successors nil
:depth i)
nodes))
(setf nodes (nreverse nodes))
(loop
for parent in nodes
for node-successor in (cdr nodes)
do
(setf (parent node-successor) parent
(successors parent) (list node-successor)
(expanded-p parent) t))
(car (last nodes))))
(defmethod proponent-node? ((node node))
(proponent-move-p (last-move (state node))))
(defmethod opponent-node? ((node node))
(opponent-move-p (last-move (state node))))
(defun proponent-ws-from-opponent-node (opponent-node &optional ruleset)
"Find a winning strategy from OPPONENT-NODE, which is supposed to represent a move just played by opponent. Return :DIALOGUE-TREE-TOO-SHALLOW if there are any unexpanded nodes that, if expanded, could make a difference in the determination of the existence of a winning strategy. Return NIL if there are no winning strategies for Proponent starting from OPPONENT-NODE. If there are, return a copy of OPPONENT-NODE that contains the winning strategy. It is assumed that OPPONENT-NODE is expanded."
(let ((opponent-succs (successors opponent-node)))
(if (expanded-p opponent-node)
(if (null opponent-succs)
nil
(let ((strategies (mapcar #'(lambda (node)
(proponent-ws-from-proponent-node node ruleset))
opponent-succs)))
(if (every #'null strategies)
nil
(let ((maybe-winner (find-if #'node-p strategies)))
(if (node-p maybe-winner)
(make-instance 'dialogues::node
:state (state opponent-node)
:parent (parent opponent-node)
:action (action opponent-node)
:successors (list maybe-winner)
:depth (depth opponent-node)
:expanded-p t)
:dialogue-tree-too-shallow)))))
:dialogue-tree-too-shallow)))
(defun proponent-ws-from-proponent-node (proponent-node &optional ruleset)
(if (expanded-p proponent-node)
(let ((succs (successors proponent-node)))
(let ((strategies (mapcar #'(lambda (node)
(proponent-ws-from-opponent-node node ruleset))
succs)))
(if (member nil strategies)
nil
(if (member :dialogue-tree-too-shallow strategies)
:dialogue-tree-too-shallow
(make-instance 'dialogues::node
:state (state proponent-node)
:parent (parent proponent-node)
:action (action proponent-node)
:successors strategies
:depth (depth proponent-node)
:expanded-p t)))))
:dialogue-tree-too-shallow))
;;; dialogue-search.lisp ends here