-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprop2cnf.rkt
190 lines (174 loc) · 6.93 KB
/
prop2cnf.rkt
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
#lang racket
(provide prop->cnf bconn? hash-foldr single-ify)
; A Boolean connective (bconn) is
(define (bconn? x) (memq x '(or and not implies)))
;A Prop is one of
; - `(,bconn ,Prop ...)
; - #f
; - #t
; - other ;;; interpreted
;A Literal is one of
; - Symbol
; - `(not Symbol)
;A Depth1Prop is one of
; - `(,bconn ,Literal ...)
; - #f
; - #t
; - other
(define (uninterpreted-prop? x)
(not (or (boolean? x)
(and (pair? x)
(bconn? (car x))))))
(define (single-ify bconn base lst)
(cond [(empty? lst) base]
[(empty? (cdr lst)) (car lst)]
[else (cons bconn lst)]))
(define (remove-prop-booleans prop)
(match prop
[`(not ,prop*)
(let ([rprop* (remove-prop-booleans prop*)])
(if (boolean? rprop*)
(not rprop*)
`(not ,rprop*)))]
[`(implies ,prop1 ,prop2)
(let ([rprop1 (remove-prop-booleans prop1)])
(cond [(eqv? rprop1 #t) ;; TT => P == P
(remove-prop-booleans prop2)]
[(false? rprop1) ;; FF => P == TT
#t]
[else
(let ([rprop2 (remove-prop-booleans prop2)])
(cond [(eqv? rprop2 #t);; P => TT == P
rprop1]
[(false? rprop2) ;; P => FF == (not P)
`(not ,rprop1)]
[else ;; general case
`(implies ,rprop1 ,rprop2)]))]))]
[`(and ,props ...)
(let ([rprops (map remove-prop-booleans props)])
(cond [(memq #f rprops)
#f]
[else (let ([rprops-no-t (remove* (list #t) rprops)])
(or (empty? rprops-no-t)
(single-ify 'and #t rprops-no-t)))]))]
[`(or ,props ...)
(let ([rprops (map remove-prop-booleans props)])
(cond [(memq #t rprops)
#t]
[else (let ([rprops-no-f (remove* (list #f) rprops)])
(and (pair? rprops-no-f)
(single-ify 'or #f rprops-no-f)))]))]
[other other]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Utility functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (hash-foldr fn base hash)
(let recur ((i (hash-iterate-first hash)))
(if i
(fn (hash-iterate-key hash i)
(hash-iterate-value hash i)
(recur (hash-iterate-next hash i)))
base)))
(define (hash-reduce fn acc base hash)
(let recur ([itr (hash-iterate-first hash)])
(if itr
(acc (fn (hash-iterate-key hash itr)
(hash-iterate-value hash itr))
(recur (hash-iterate-next hash itr)))
base)))
(define (incbox! b) (set-box! b (add1 (unbox b))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Tseitin transform functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; shred : Prop * Box Natural * Hash<Prop,Natural> -> Literal
; where Env is a Hash<Depth1Prop to DimacsLit>
; We do an initial structural hashing in order to spot
; sharing.
; XXX: For finding more sharing, we should normalize associations
; and order literal by some total order.
(define (shred prop varnum env)
;; shredrec : Prop -> Sym
(let shredrec ([p prop])
(match p
[`(not ,p)
(- (shredrec p))]
[`(,(? bconn? op) ,ps ...)
(let ([d1props (map shredrec ps)])
(begin0 (hash-ref! env (cons op d1props) (unbox varnum))
(incbox! varnum)))]
[(? boolean? x)
(error "[Internal error] Literal false or true found!")]
[other ;; intepreted
(begin0 (hash-ref! env p (unbox varnum))
(incbox! varnum))])))
;; Tseitin transform depth1props to Dimacs format.
;; This means counting the number of clauses created.
(define (wff-hash->cnf env num-clauses)
;; some shorthand for easy reading
(define (implies p . q) (list* (- p) q))
(define (implies* p q) (list* (- p) q))
(define (or . ps) ps)
(define (not p) (- p))
(hash-reduce
(lambda (prop dimacsvar)
(match prop
[`(not ,sym)
(error "[Internal error] Naked NOT should not survive shredding.")]
[`(implies ,p ,q)
(set-box! num-clauses (+ 3 (unbox num-clauses)))
(list (implies dimacsvar (not p) q)
(implies q dimacsvar)
;; implication not true => p had to be true.
(or dimacsvar p))]
[`(and ,ps ...)
;; and gate is true iff all of ps are true
(let ([andlits (map - ps)]
[impclauses (map (lambda (p)
(incbox! num-clauses)
(implies dimacsvar p))
ps)])
(incbox! num-clauses)
(cons (cons dimacsvar andlits) ; ~andgate => (not (and ,@ps))
impclauses))] ; for all p in ps, andgate => p
[`(or ,ps ...)
;; or gate is true iff one of ps is true.
(let ([impclauses (map (lambda (p)
(incbox! num-clauses)
(implies p dimacsvar))
ps)])
(incbox! num-clauses)
(list* (implies* dimacsvar ps) ; orgate => p1 or p2 or ...
impclauses))] ; for all p in ps, p => orgate
[other ;; ground proposition. Not in clause.
'()]))
append '() env))
; prop->cnf : Prop -> CNF * T-State
(define (prop->cnf initialize-t-state prop)
(let ((simp-prop (remove-prop-booleans prop)))
(printf "Simplified: ~a~%" simp-prop)
(match simp-prop
[#t (values #t (initialize-t-state (make-hash)))]
[#f (values #f (initialize-t-state (make-hash)))]
[non-trivial
(let* ([env (make-hash)]
[total-vars (box 1)] ;; start variables at 1 since 0 can't be negated
[total-clauses (box 0)] ;; start with 0 clauses and count upwards
[top-sym (shred non-trivial total-vars env)]
[cnf (wff-hash->cnf env total-clauses)]
[atomic-propositions
;; collect all theory literals in a dictionary keyed
;; by their propositional variable.
(make-immutable-hash
(hash-foldr
(λ (prop dimacs-lit atomic-assoc)
;; dimacs-lit should always be positive for an uninterpreted prop
(if (uninterpreted-prop? prop)
(dict-set atomic-assoc prop dimacs-lit)
atomic-assoc))
'()
env))])
(values (list (sub1 (unbox total-vars)) ; one too many due to needing fresh names
(add1 (unbox total-clauses)) ; add 1 for top level assertion
(cons (list top-sym) ; assert the top level
cnf))
(initialize-t-state atomic-propositions)))])))