-
Notifications
You must be signed in to change notification settings - Fork 108
Expand file tree
/
Copy pathfol.lisp
More file actions
117 lines (99 loc) · 4.5 KB
/
fol.lisp
File metadata and controls
117 lines (99 loc) · 4.5 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
;;;; First Order Logic (FOL) Tell, Retract, and Ask-Each
(defstruct fol-kb
;;; A FOL (First-Order Logic) KB stores clauses.
;;; Access to the KB is via POSSIBLE-RESOLVERS, which takes a
;;; literal (e.g. (not D), or B), and returns all the clauses that
;;; contain the literal. We also keep a list of temporary clauses,
;;; added to the KB during a proof and removed at the end. Internally,
;;; clauses are in minimal-cnf format, which is CNF without the and/or.
;;; So (and (or P Q) (or R (not S))) becomes ((P Q) (R (not S)))
(positive-clauses (make-hash-table :test #'eq))
(negative-clauses (make-hash-table :test #'eq))
(temp-added nil))
(defmethod tell ((kb fol-kb) sentence)
"Add a sentence to a FOL knowledge base."
(for each clause in (->minimal-cnf sentence) do
(tell-minimal-cnf-clause kb clause)))
(defmethod retract ((kb fol-kb) sentence)
"Delete each conjunct of sentence from KB."
(retract-minimal-cnf-clauses kb (->minimal-cnf sentence)))
(defmethod ask-each ((kb fol-kb) query fn)
"Use resolution to decide if sentence is true."
(prove-by-refutation kb (->minimal-cnf `(not ,query)) fn))
;;;; FOL Knowledge Base Utility Functions
(defun possible-resolvers (kb literal)
"Find clauses that might resolve with a clause containing literal."
(if (eq (op literal) 'not)
(gethash (op (arg1 literal)) (fol-kb-negative-clauses kb))
(gethash (op literal) (fol-kb-positive-clauses kb))))
(defun tell-minimal-cnf-clause (kb clause)
;; We don't add tautologies like "P | ~P".
;; It would be good to eliminate subsumed clauses like
;; Eq(1,1) when Eq(x,x) is already in the kb.
;; Currently we don't check for that.
(unless (tautology? clause)
(for each literal in clause do
(if (eq (op literal) 'not)
(push clause (gethash (op (arg1 literal))
(fol-kb-negative-clauses kb)))
(push clause (gethash (op literal)
(fol-kb-positive-clauses kb)))))))
(defun retract-minimal-cnf-clauses (kb clauses)
"Remove the minimal-cnf clauses from the KB."
(for each clause in clauses do
(for each literal in clause do
(if (eq (op literal) 'not)
(deletef clause
(gethash (op (arg1 literal))
(fol-kb-negative-clauses kb)))
(deletef clause (gethash (op literal)
(fol-kb-positive-clauses kb)))))))
(defun ->minimal-cnf (sentence)
"Convert a logical sentence to minimal CNF (no and/or connectives)."
;; E.g., (and (or P (not Q) R) S) becomes ((P (not Q) R) (S))
;; Everything internal in the FOL module uses minimal-cnf
;; Only tell, retract, and ask-* use the regular logical form.
(mapcar #'disjuncts (conjuncts (->cnf sentence))))
(defun undo-temp-changes (kb)
"Undo the changes that were temporarilly made to KB."
(retract-minimal-cnf-clauses kb (fol-kb-temp-added kb))
(setf (fol-kb-temp-added kb) nil))
(defun tautology? (clause)
"Is clause a tautology (something that is always true)?"
(some #'(lambda (literal)
(and (eq (op literal) 'not)
(member (arg1 literal) clause :test #'equal)))
clause))
;;;; Functions for Resolution Refutation Theorem Proving
(defun prove-by-refutation (kb sos fn)
"Try to prove that ~SOS is true (given KB) by resolution refutation."
;; Call FN on every substitution that leads to a proof.
;; Similar to OTTER [p. 311], the KB plays the role of the usable
;; (background) axioms, and SOS (set of support) is formed by the
;; negation of the query. Uses set of support heuristic and uses
;; shorter clauses first (which is a generalization of the unit
;; preference strategy). Filters out tautologies.
(setf sos (sort sos #'< :key #'length))
(undo-temp-changes kb)
(let (clause)
(loop
(when (null sos) (RETURN nil))
;; Move clause from SOS to the usable KB
(setf clause (pop sos))
(tell-minimal-cnf-clause kb clause)
(push clause (fol-kb-temp-added kb))
;; Process everything that resolves with CLAUSE
(for each literal in clause do
(for each r in (possible-resolvers kb literal) do
(let ((b (unify ??? literal)))
(when b
(setf sos (insert clause sos #'< :key #'length))
(case (length clause)
(0 (funcall fn b)) ;; refutation found!!
; should look for unit refutation if length is 1
))))))))
(defun resolve (literal clause)
"Resolve a single literal against a clause"
)
(defun insert (item list pred &key (key #'identity))
(merge 'list (list item) list pred :key key))