49 (* prop_formula: formulas of propositional logic, built from Boolean *) |
49 (* prop_formula: formulas of propositional logic, built from Boolean *) |
50 (* variables (referred to by index) and True/False using *) |
50 (* variables (referred to by index) and True/False using *) |
51 (* not/or/and *) |
51 (* not/or/and *) |
52 (* ------------------------------------------------------------------------- *) |
52 (* ------------------------------------------------------------------------- *) |
53 |
53 |
54 datatype prop_formula = |
54 datatype prop_formula = |
55 True |
55 True |
56 | False |
56 | False |
57 | BoolVar of int (* NOTE: only use indices >= 1 *) |
57 | BoolVar of int (* NOTE: only use indices >= 1 *) |
58 | Not of prop_formula |
58 | Not of prop_formula |
59 | Or of prop_formula * prop_formula |
59 | Or of prop_formula * prop_formula |
60 | And of prop_formula * prop_formula; |
60 | And of prop_formula * prop_formula; |
61 |
61 |
62 (* ------------------------------------------------------------------------- *) |
62 (* ------------------------------------------------------------------------- *) |
63 (* The following constructor functions make sure that True and False do not *) |
63 (* The following constructor functions make sure that True and False do not *) |
64 (* occur within any of the other connectives (i.e. Not, Or, And), and *) |
64 (* occur within any of the other connectives (i.e. Not, Or, And), and *) |
65 (* perform double-negation elimination. *) |
65 (* perform double-negation elimination. *) |
66 (* ------------------------------------------------------------------------- *) |
66 (* ------------------------------------------------------------------------- *) |
67 |
67 |
68 (* prop_formula -> prop_formula *) |
68 fun SNot True = False |
69 |
69 | SNot False = True |
70 fun SNot True = False |
70 | SNot (Not fm) = fm |
71 | SNot False = True |
71 | SNot fm = Not fm; |
72 | SNot (Not fm) = fm |
72 |
73 | SNot fm = Not fm; |
73 fun SOr (True, _) = True |
74 |
74 | SOr (_, True) = True |
75 (* prop_formula * prop_formula -> prop_formula *) |
75 | SOr (False, fm) = fm |
76 |
76 | SOr (fm, False) = fm |
77 fun SOr (True, _) = True |
77 | SOr (fm1, fm2) = Or (fm1, fm2); |
78 | SOr (_, True) = True |
78 |
79 | SOr (False, fm) = fm |
79 fun SAnd (True, fm) = fm |
80 | SOr (fm, False) = fm |
80 | SAnd (fm, True) = fm |
81 | SOr (fm1, fm2) = Or (fm1, fm2); |
81 | SAnd (False, _) = False |
82 |
82 | SAnd (_, False) = False |
83 (* prop_formula * prop_formula -> prop_formula *) |
83 | SAnd (fm1, fm2) = And (fm1, fm2); |
84 |
|
85 fun SAnd (True, fm) = fm |
|
86 | SAnd (fm, True) = fm |
|
87 | SAnd (False, _) = False |
|
88 | SAnd (_, False) = False |
|
89 | SAnd (fm1, fm2) = And (fm1, fm2); |
|
90 |
84 |
91 (* ------------------------------------------------------------------------- *) |
85 (* ------------------------------------------------------------------------- *) |
92 (* simplify: eliminates True/False below other connectives, and double- *) |
86 (* simplify: eliminates True/False below other connectives, and double- *) |
93 (* negation *) |
87 (* negation *) |
94 (* ------------------------------------------------------------------------- *) |
88 (* ------------------------------------------------------------------------- *) |
95 |
89 |
96 (* prop_formula -> prop_formula *) |
90 fun simplify (Not fm) = SNot (simplify fm) |
97 |
91 | simplify (Or (fm1, fm2)) = SOr (simplify fm1, simplify fm2) |
98 fun simplify (Not fm) = SNot (simplify fm) |
92 | simplify (And (fm1, fm2)) = SAnd (simplify fm1, simplify fm2) |
99 | simplify (Or (fm1, fm2)) = SOr (simplify fm1, simplify fm2) |
93 | simplify fm = fm; |
100 | simplify (And (fm1, fm2)) = SAnd (simplify fm1, simplify fm2) |
|
101 | simplify fm = fm; |
|
102 |
94 |
103 (* ------------------------------------------------------------------------- *) |
95 (* ------------------------------------------------------------------------- *) |
104 (* indices: collects all indices of Boolean variables that occur in a *) |
96 (* indices: collects all indices of Boolean variables that occur in a *) |
105 (* propositional formula 'fm'; no duplicates *) |
97 (* propositional formula 'fm'; no duplicates *) |
106 (* ------------------------------------------------------------------------- *) |
98 (* ------------------------------------------------------------------------- *) |
107 |
99 |
108 (* prop_formula -> int list *) |
100 fun indices True = [] |
109 |
101 | indices False = [] |
110 fun indices True = [] |
102 | indices (BoolVar i) = [i] |
111 | indices False = [] |
103 | indices (Not fm) = indices fm |
112 | indices (BoolVar i) = [i] |
104 | indices (Or (fm1, fm2)) = union (op =) (indices fm1) (indices fm2) |
113 | indices (Not fm) = indices fm |
105 | indices (And (fm1, fm2)) = union (op =) (indices fm1) (indices fm2); |
114 | indices (Or (fm1, fm2)) = union (op =) (indices fm1) (indices fm2) |
|
115 | indices (And (fm1, fm2)) = union (op =) (indices fm1) (indices fm2); |
|
116 |
106 |
117 (* ------------------------------------------------------------------------- *) |
107 (* ------------------------------------------------------------------------- *) |
118 (* maxidx: computes the maximal variable index occuring in a formula of *) |
108 (* maxidx: computes the maximal variable index occuring in a formula of *) |
119 (* propositional logic 'fm'; 0 if 'fm' contains no variable *) |
109 (* propositional logic 'fm'; 0 if 'fm' contains no variable *) |
120 (* ------------------------------------------------------------------------- *) |
110 (* ------------------------------------------------------------------------- *) |
121 |
111 |
122 (* prop_formula -> int *) |
112 fun maxidx True = 0 |
123 |
113 | maxidx False = 0 |
124 fun maxidx True = 0 |
114 | maxidx (BoolVar i) = i |
125 | maxidx False = 0 |
115 | maxidx (Not fm) = maxidx fm |
126 | maxidx (BoolVar i) = i |
116 | maxidx (Or (fm1, fm2)) = Int.max (maxidx fm1, maxidx fm2) |
127 | maxidx (Not fm) = maxidx fm |
117 | maxidx (And (fm1, fm2)) = Int.max (maxidx fm1, maxidx fm2); |
128 | maxidx (Or (fm1, fm2)) = Int.max (maxidx fm1, maxidx fm2) |
|
129 | maxidx (And (fm1, fm2)) = Int.max (maxidx fm1, maxidx fm2); |
|
130 |
118 |
131 (* ------------------------------------------------------------------------- *) |
119 (* ------------------------------------------------------------------------- *) |
132 (* exists: computes the disjunction over a list 'xs' of propositional *) |
120 (* exists: computes the disjunction over a list 'xs' of propositional *) |
133 (* formulas *) |
121 (* formulas *) |
134 (* ------------------------------------------------------------------------- *) |
122 (* ------------------------------------------------------------------------- *) |
135 |
123 |
136 (* prop_formula list -> prop_formula *) |
124 fun exists xs = Library.foldl SOr (False, xs); |
137 |
|
138 fun exists xs = Library.foldl SOr (False, xs); |
|
139 |
125 |
140 (* ------------------------------------------------------------------------- *) |
126 (* ------------------------------------------------------------------------- *) |
141 (* all: computes the conjunction over a list 'xs' of propositional formulas *) |
127 (* all: computes the conjunction over a list 'xs' of propositional formulas *) |
142 (* ------------------------------------------------------------------------- *) |
128 (* ------------------------------------------------------------------------- *) |
143 |
129 |
144 (* prop_formula list -> prop_formula *) |
130 fun all xs = Library.foldl SAnd (True, xs); |
145 |
|
146 fun all xs = Library.foldl SAnd (True, xs); |
|
147 |
131 |
148 (* ------------------------------------------------------------------------- *) |
132 (* ------------------------------------------------------------------------- *) |
149 (* dot_product: ([x1,...,xn], [y1,...,yn]) -> x1*y1+...+xn*yn *) |
133 (* dot_product: ([x1,...,xn], [y1,...,yn]) -> x1*y1+...+xn*yn *) |
150 (* ------------------------------------------------------------------------- *) |
134 (* ------------------------------------------------------------------------- *) |
151 |
135 |
152 (* prop_formula list * prop_formula list -> prop_formula *) |
136 fun dot_product (xs, ys) = exists (map SAnd (xs ~~ ys)); |
153 |
|
154 fun dot_product (xs,ys) = exists (map SAnd (xs~~ys)); |
|
155 |
137 |
156 (* ------------------------------------------------------------------------- *) |
138 (* ------------------------------------------------------------------------- *) |
157 (* is_nnf: returns 'true' iff the formula is in negation normal form (i.e., *) |
139 (* is_nnf: returns 'true' iff the formula is in negation normal form (i.e., *) |
158 (* only variables may be negated, but not subformulas). *) |
140 (* only variables may be negated, but not subformulas). *) |
159 (* ------------------------------------------------------------------------- *) |
141 (* ------------------------------------------------------------------------- *) |
160 |
142 |
161 local |
143 local |
162 fun is_literal (BoolVar _) = true |
144 fun is_literal (BoolVar _) = true |
163 | is_literal (Not (BoolVar _)) = true |
145 | is_literal (Not (BoolVar _)) = true |
164 | is_literal _ = false |
146 | is_literal _ = false |
165 fun is_conj_disj (Or (fm1, fm2)) = |
147 fun is_conj_disj (Or (fm1, fm2)) = is_conj_disj fm1 andalso is_conj_disj fm2 |
166 is_conj_disj fm1 andalso is_conj_disj fm2 |
148 | is_conj_disj (And (fm1, fm2)) = is_conj_disj fm1 andalso is_conj_disj fm2 |
167 | is_conj_disj (And (fm1, fm2)) = |
149 | is_conj_disj fm = is_literal fm |
168 is_conj_disj fm1 andalso is_conj_disj fm2 |
150 in |
169 | is_conj_disj fm = |
151 fun is_nnf True = true |
170 is_literal fm |
152 | is_nnf False = true |
171 in |
153 | is_nnf fm = is_conj_disj fm |
172 fun is_nnf True = true |
154 end; |
173 | is_nnf False = true |
|
174 | is_nnf fm = is_conj_disj fm |
|
175 end; |
|
176 |
155 |
177 (* ------------------------------------------------------------------------- *) |
156 (* ------------------------------------------------------------------------- *) |
178 (* is_cnf: returns 'true' iff the formula is in conjunctive normal form *) |
157 (* is_cnf: returns 'true' iff the formula is in conjunctive normal form *) |
179 (* (i.e., a conjunction of disjunctions of literals). 'is_cnf' *) |
158 (* (i.e., a conjunction of disjunctions of literals). 'is_cnf' *) |
180 (* implies 'is_nnf'. *) |
159 (* implies 'is_nnf'. *) |
181 (* ------------------------------------------------------------------------- *) |
160 (* ------------------------------------------------------------------------- *) |
182 |
161 |
183 local |
162 local |
184 fun is_literal (BoolVar _) = true |
163 fun is_literal (BoolVar _) = true |
185 | is_literal (Not (BoolVar _)) = true |
164 | is_literal (Not (BoolVar _)) = true |
186 | is_literal _ = false |
165 | is_literal _ = false |
187 fun is_disj (Or (fm1, fm2)) = is_disj fm1 andalso is_disj fm2 |
166 fun is_disj (Or (fm1, fm2)) = is_disj fm1 andalso is_disj fm2 |
188 | is_disj fm = is_literal fm |
167 | is_disj fm = is_literal fm |
189 fun is_conj (And (fm1, fm2)) = is_conj fm1 andalso is_conj fm2 |
168 fun is_conj (And (fm1, fm2)) = is_conj fm1 andalso is_conj fm2 |
190 | is_conj fm = is_disj fm |
169 | is_conj fm = is_disj fm |
191 in |
170 in |
192 fun is_cnf True = true |
171 fun is_cnf True = true |
193 | is_cnf False = true |
172 | is_cnf False = true |
194 | is_cnf fm = is_conj fm |
173 | is_cnf fm = is_conj fm |
195 end; |
174 end; |
196 |
175 |
197 (* ------------------------------------------------------------------------- *) |
176 (* ------------------------------------------------------------------------- *) |
198 (* nnf: computes the negation normal form of a formula 'fm' of propositional *) |
177 (* nnf: computes the negation normal form of a formula 'fm' of propositional *) |
199 (* logic (i.e., only variables may be negated, but not subformulas). *) |
178 (* logic (i.e., only variables may be negated, but not subformulas). *) |
200 (* Simplification (cf. 'simplify') is performed as well. Not *) |
179 (* Simplification (cf. 'simplify') is performed as well. Not *) |
201 (* surprisingly, 'is_nnf o nnf' always returns 'true'. 'nnf fm' returns *) |
180 (* surprisingly, 'is_nnf o nnf' always returns 'true'. 'nnf fm' returns *) |
202 (* 'fm' if (and only if) 'is_nnf fm' returns 'true'. *) |
181 (* 'fm' if (and only if) 'is_nnf fm' returns 'true'. *) |
203 (* ------------------------------------------------------------------------- *) |
182 (* ------------------------------------------------------------------------- *) |
204 |
183 |
205 (* prop_formula -> prop_formula *) |
184 fun nnf fm = |
206 |
185 let |
207 fun nnf fm = |
186 fun |
208 let |
187 (* constants *) |
209 fun |
188 nnf_aux True = True |
210 (* constants *) |
189 | nnf_aux False = False |
211 nnf_aux True = True |
190 (* variables *) |
212 | nnf_aux False = False |
191 | nnf_aux (BoolVar i) = (BoolVar i) |
213 (* variables *) |
192 (* 'or' and 'and' as outermost connectives are left untouched *) |
214 | nnf_aux (BoolVar i) = (BoolVar i) |
193 | nnf_aux (Or (fm1, fm2)) = SOr (nnf_aux fm1, nnf_aux fm2) |
215 (* 'or' and 'and' as outermost connectives are left untouched *) |
194 | nnf_aux (And (fm1, fm2)) = SAnd (nnf_aux fm1, nnf_aux fm2) |
216 | nnf_aux (Or (fm1, fm2)) = SOr (nnf_aux fm1, nnf_aux fm2) |
195 (* 'not' + constant *) |
217 | nnf_aux (And (fm1, fm2)) = SAnd (nnf_aux fm1, nnf_aux fm2) |
196 | nnf_aux (Not True) = False |
218 (* 'not' + constant *) |
197 | nnf_aux (Not False) = True |
219 | nnf_aux (Not True) = False |
198 (* 'not' + variable *) |
220 | nnf_aux (Not False) = True |
199 | nnf_aux (Not (BoolVar i)) = Not (BoolVar i) |
221 (* 'not' + variable *) |
200 (* pushing 'not' inside of 'or'/'and' using de Morgan's laws *) |
222 | nnf_aux (Not (BoolVar i)) = Not (BoolVar i) |
201 | nnf_aux (Not (Or (fm1, fm2))) = SAnd (nnf_aux (SNot fm1), nnf_aux (SNot fm2)) |
223 (* pushing 'not' inside of 'or'/'and' using de Morgan's laws *) |
202 | nnf_aux (Not (And (fm1, fm2))) = SOr (nnf_aux (SNot fm1), nnf_aux (SNot fm2)) |
224 | nnf_aux (Not (Or (fm1, fm2))) = SAnd (nnf_aux (SNot fm1), nnf_aux (SNot fm2)) |
203 (* double-negation elimination *) |
225 | nnf_aux (Not (And (fm1, fm2))) = SOr (nnf_aux (SNot fm1), nnf_aux (SNot fm2)) |
204 | nnf_aux (Not (Not fm)) = nnf_aux fm |
226 (* double-negation elimination *) |
205 in |
227 | nnf_aux (Not (Not fm)) = nnf_aux fm |
206 if is_nnf fm then fm |
228 in |
207 else nnf_aux fm |
229 if is_nnf fm then |
208 end; |
230 fm |
|
231 else |
|
232 nnf_aux fm |
|
233 end; |
|
234 |
209 |
235 (* ------------------------------------------------------------------------- *) |
210 (* ------------------------------------------------------------------------- *) |
236 (* cnf: computes the conjunctive normal form (i.e., a conjunction of *) |
211 (* cnf: computes the conjunctive normal form (i.e., a conjunction of *) |
237 (* disjunctions of literals) of a formula 'fm' of propositional logic. *) |
212 (* disjunctions of literals) of a formula 'fm' of propositional logic. *) |
238 (* Simplification (cf. 'simplify') is performed as well. The result *) |
213 (* Simplification (cf. 'simplify') is performed as well. The result *) |
239 (* is equivalent to 'fm', but may be exponentially longer. Not *) |
214 (* is equivalent to 'fm', but may be exponentially longer. Not *) |
240 (* surprisingly, 'is_cnf o cnf' always returns 'true'. 'cnf fm' returns *) |
215 (* surprisingly, 'is_cnf o cnf' always returns 'true'. 'cnf fm' returns *) |
241 (* 'fm' if (and only if) 'is_cnf fm' returns 'true'. *) |
216 (* 'fm' if (and only if) 'is_cnf fm' returns 'true'. *) |
242 (* ------------------------------------------------------------------------- *) |
217 (* ------------------------------------------------------------------------- *) |
243 |
218 |
244 (* prop_formula -> prop_formula *) |
219 fun cnf fm = |
245 |
220 let |
246 fun cnf fm = |
221 (* function to push an 'Or' below 'And's, using distributive laws *) |
247 let |
222 fun cnf_or (And (fm11, fm12), fm2) = |
248 (* function to push an 'Or' below 'And's, using distributive laws *) |
223 And (cnf_or (fm11, fm2), cnf_or (fm12, fm2)) |
249 fun cnf_or (And (fm11, fm12), fm2) = |
224 | cnf_or (fm1, And (fm21, fm22)) = |
250 And (cnf_or (fm11, fm2), cnf_or (fm12, fm2)) |
225 And (cnf_or (fm1, fm21), cnf_or (fm1, fm22)) |
251 | cnf_or (fm1, And (fm21, fm22)) = |
226 (* neither subformula contains 'And' *) |
252 And (cnf_or (fm1, fm21), cnf_or (fm1, fm22)) |
227 | cnf_or (fm1, fm2) = Or (fm1, fm2) |
253 (* neither subformula contains 'And' *) |
228 fun cnf_from_nnf True = True |
254 | cnf_or (fm1, fm2) = |
229 | cnf_from_nnf False = False |
255 Or (fm1, fm2) |
230 | cnf_from_nnf (BoolVar i) = BoolVar i |
256 fun cnf_from_nnf True = True |
231 (* 'fm' must be a variable since the formula is in NNF *) |
257 | cnf_from_nnf False = False |
232 | cnf_from_nnf (Not fm) = Not fm |
258 | cnf_from_nnf (BoolVar i) = BoolVar i |
233 (* 'Or' may need to be pushed below 'And' *) |
259 (* 'fm' must be a variable since the formula is in NNF *) |
234 | cnf_from_nnf (Or (fm1, fm2)) = |
260 | cnf_from_nnf (Not fm) = Not fm |
235 cnf_or (cnf_from_nnf fm1, cnf_from_nnf fm2) |
261 (* 'Or' may need to be pushed below 'And' *) |
236 (* 'And' as outermost connective is left untouched *) |
262 | cnf_from_nnf (Or (fm1, fm2)) = |
237 | cnf_from_nnf (And (fm1, fm2)) = |
263 cnf_or (cnf_from_nnf fm1, cnf_from_nnf fm2) |
238 And (cnf_from_nnf fm1, cnf_from_nnf fm2) |
264 (* 'And' as outermost connective is left untouched *) |
239 in |
265 | cnf_from_nnf (And (fm1, fm2)) = |
240 if is_cnf fm then fm |
266 And (cnf_from_nnf fm1, cnf_from_nnf fm2) |
241 else (cnf_from_nnf o nnf) fm |
267 in |
242 end; |
268 if is_cnf fm then |
|
269 fm |
|
270 else |
|
271 (cnf_from_nnf o nnf) fm |
|
272 end; |
|
273 |
243 |
274 (* ------------------------------------------------------------------------- *) |
244 (* ------------------------------------------------------------------------- *) |
275 (* defcnf: computes a definitional conjunctive normal form of a formula 'fm' *) |
245 (* defcnf: computes a definitional conjunctive normal form of a formula 'fm' *) |
276 (* of propositional logic. Simplification (cf. 'simplify') is performed *) |
246 (* of propositional logic. Simplification (cf. 'simplify') is performed *) |
277 (* as well. 'defcnf' may introduce auxiliary Boolean variables to avoid *) |
247 (* as well. 'defcnf' may introduce auxiliary Boolean variables to avoid *) |
280 (* necessarily equivalent to 'fm'. Not surprisingly, 'is_cnf o defcnf' *) |
250 (* necessarily equivalent to 'fm'. Not surprisingly, 'is_cnf o defcnf' *) |
281 (* always returns 'true'. 'defcnf fm' returns 'fm' if (and only if) *) |
251 (* always returns 'true'. 'defcnf fm' returns 'fm' if (and only if) *) |
282 (* 'is_cnf fm' returns 'true'. *) |
252 (* 'is_cnf fm' returns 'true'. *) |
283 (* ------------------------------------------------------------------------- *) |
253 (* ------------------------------------------------------------------------- *) |
284 |
254 |
285 (* prop_formula -> prop_formula *) |
255 fun defcnf fm = |
286 |
256 if is_cnf fm then fm |
287 fun defcnf fm = |
257 else |
288 if is_cnf fm then |
258 let |
289 fm |
259 val fm' = nnf fm |
290 else |
260 (* 'new' specifies the next index that is available to introduce an auxiliary variable *) |
291 let |
261 (* int ref *) |
292 val fm' = nnf fm |
262 val new = Unsynchronized.ref (maxidx fm' + 1) |
293 (* 'new' specifies the next index that is available to introduce an auxiliary variable *) |
263 (* unit -> int *) |
294 (* int ref *) |
264 fun new_idx () = let val idx = !new in new := idx+1; idx end |
295 val new = Unsynchronized.ref (maxidx fm' + 1) |
265 (* replaces 'And' by an auxiliary variable (and its definition) *) |
296 (* unit -> int *) |
266 (* prop_formula -> prop_formula * prop_formula list *) |
297 fun new_idx () = let val idx = !new in new := idx+1; idx end |
267 fun defcnf_or (And x) = |
298 (* replaces 'And' by an auxiliary variable (and its definition) *) |
268 let |
299 (* prop_formula -> prop_formula * prop_formula list *) |
269 val i = new_idx () |
300 fun defcnf_or (And x) = |
270 in |
301 let |
271 (* Note that definitions are in NNF, but not CNF. *) |
302 val i = new_idx () |
272 (BoolVar i, [Or (Not (BoolVar i), And x)]) |
303 in |
273 end |
304 (* Note that definitions are in NNF, but not CNF. *) |
274 | defcnf_or (Or (fm1, fm2)) = |
305 (BoolVar i, [Or (Not (BoolVar i), And x)]) |
275 let |
306 end |
276 val (fm1', defs1) = defcnf_or fm1 |
307 | defcnf_or (Or (fm1, fm2)) = |
277 val (fm2', defs2) = defcnf_or fm2 |
308 let |
278 in |
309 val (fm1', defs1) = defcnf_or fm1 |
279 (Or (fm1', fm2'), defs1 @ defs2) |
310 val (fm2', defs2) = defcnf_or fm2 |
280 end |
311 in |
281 | defcnf_or fm = (fm, []) |
312 (Or (fm1', fm2'), defs1 @ defs2) |
282 (* prop_formula -> prop_formula *) |
313 end |
283 fun defcnf_from_nnf True = True |
314 | defcnf_or fm = |
284 | defcnf_from_nnf False = False |
315 (fm, []) |
285 | defcnf_from_nnf (BoolVar i) = BoolVar i |
316 (* prop_formula -> prop_formula *) |
286 (* 'fm' must be a variable since the formula is in NNF *) |
317 fun defcnf_from_nnf True = True |
287 | defcnf_from_nnf (Not fm) = Not fm |
318 | defcnf_from_nnf False = False |
288 (* 'Or' may need to be pushed below 'And' *) |
319 | defcnf_from_nnf (BoolVar i) = BoolVar i |
289 (* 'Or' of literal and 'And': use distributivity *) |
320 (* 'fm' must be a variable since the formula is in NNF *) |
290 | defcnf_from_nnf (Or (BoolVar i, And (fm1, fm2))) = |
321 | defcnf_from_nnf (Not fm) = Not fm |
291 And (defcnf_from_nnf (Or (BoolVar i, fm1)), |
322 (* 'Or' may need to be pushed below 'And' *) |
292 defcnf_from_nnf (Or (BoolVar i, fm2))) |
323 (* 'Or' of literal and 'And': use distributivity *) |
293 | defcnf_from_nnf (Or (Not (BoolVar i), And (fm1, fm2))) = |
324 | defcnf_from_nnf (Or (BoolVar i, And (fm1, fm2))) = |
294 And (defcnf_from_nnf (Or (Not (BoolVar i), fm1)), |
325 And (defcnf_from_nnf (Or (BoolVar i, fm1)), |
295 defcnf_from_nnf (Or (Not (BoolVar i), fm2))) |
326 defcnf_from_nnf (Or (BoolVar i, fm2))) |
296 | defcnf_from_nnf (Or (And (fm1, fm2), BoolVar i)) = |
327 | defcnf_from_nnf (Or (Not (BoolVar i), And (fm1, fm2))) = |
297 And (defcnf_from_nnf (Or (fm1, BoolVar i)), |
328 And (defcnf_from_nnf (Or (Not (BoolVar i), fm1)), |
298 defcnf_from_nnf (Or (fm2, BoolVar i))) |
329 defcnf_from_nnf (Or (Not (BoolVar i), fm2))) |
299 | defcnf_from_nnf (Or (And (fm1, fm2), Not (BoolVar i))) = |
330 | defcnf_from_nnf (Or (And (fm1, fm2), BoolVar i)) = |
300 And (defcnf_from_nnf (Or (fm1, Not (BoolVar i))), |
331 And (defcnf_from_nnf (Or (fm1, BoolVar i)), |
301 defcnf_from_nnf (Or (fm2, Not (BoolVar i)))) |
332 defcnf_from_nnf (Or (fm2, BoolVar i))) |
302 (* all other cases: turn the formula into a disjunction of literals, *) |
333 | defcnf_from_nnf (Or (And (fm1, fm2), Not (BoolVar i))) = |
303 (* adding definitions as necessary *) |
334 And (defcnf_from_nnf (Or (fm1, Not (BoolVar i))), |
304 | defcnf_from_nnf (Or x) = |
335 defcnf_from_nnf (Or (fm2, Not (BoolVar i)))) |
305 let |
336 (* all other cases: turn the formula into a disjunction of literals, *) |
306 val (fm, defs) = defcnf_or (Or x) |
337 (* adding definitions as necessary *) |
307 val cnf_defs = map defcnf_from_nnf defs |
338 | defcnf_from_nnf (Or x) = |
308 in |
339 let |
309 all (fm :: cnf_defs) |
340 val (fm, defs) = defcnf_or (Or x) |
310 end |
341 val cnf_defs = map defcnf_from_nnf defs |
311 (* 'And' as outermost connective is left untouched *) |
342 in |
312 | defcnf_from_nnf (And (fm1, fm2)) = |
343 all (fm :: cnf_defs) |
313 And (defcnf_from_nnf fm1, defcnf_from_nnf fm2) |
344 end |
314 in |
345 (* 'And' as outermost connective is left untouched *) |
315 defcnf_from_nnf fm' |
346 | defcnf_from_nnf (And (fm1, fm2)) = |
316 end; |
347 And (defcnf_from_nnf fm1, defcnf_from_nnf fm2) |
|
348 in |
|
349 defcnf_from_nnf fm' |
|
350 end; |
|
351 |
317 |
352 (* ------------------------------------------------------------------------- *) |
318 (* ------------------------------------------------------------------------- *) |
353 (* eval: given an assignment 'a' of Boolean values to variable indices, the *) |
319 (* eval: given an assignment 'a' of Boolean values to variable indices, the *) |
354 (* truth value of a propositional formula 'fm' is computed *) |
320 (* truth value of a propositional formula 'fm' is computed *) |
355 (* ------------------------------------------------------------------------- *) |
321 (* ------------------------------------------------------------------------- *) |
356 |
322 |
357 (* (int -> bool) -> prop_formula -> bool *) |
323 fun eval a True = true |
358 |
324 | eval a False = false |
359 fun eval a True = true |
325 | eval a (BoolVar i) = (a i) |
360 | eval a False = false |
326 | eval a (Not fm) = not (eval a fm) |
361 | eval a (BoolVar i) = (a i) |
327 | eval a (Or (fm1, fm2)) = (eval a fm1) orelse (eval a fm2) |
362 | eval a (Not fm) = not (eval a fm) |
328 | eval a (And (fm1, fm2)) = (eval a fm1) andalso (eval a fm2); |
363 | eval a (Or (fm1,fm2)) = (eval a fm1) orelse (eval a fm2) |
|
364 | eval a (And (fm1,fm2)) = (eval a fm1) andalso (eval a fm2); |
|
365 |
329 |
366 (* ------------------------------------------------------------------------- *) |
330 (* ------------------------------------------------------------------------- *) |
367 (* prop_formula_of_term: returns the propositional structure of a HOL term, *) |
331 (* prop_formula_of_term: returns the propositional structure of a HOL term, *) |
368 (* with subterms replaced by Boolean variables. Also returns a table *) |
332 (* with subterms replaced by Boolean variables. Also returns a table *) |
369 (* of terms and corresponding variables that extends the table that was *) |
333 (* of terms and corresponding variables that extends the table that was *) |
376 (* 'prop_formula_of_term' is invoked many times, it might be more *) |
340 (* 'prop_formula_of_term' is invoked many times, it might be more *) |
377 (* efficient to pass and return this value as an additional parameter, *) |
341 (* efficient to pass and return this value as an additional parameter, *) |
378 (* so that it does not have to be recomputed (by folding over the *) |
342 (* so that it does not have to be recomputed (by folding over the *) |
379 (* table) for each invocation. *) |
343 (* table) for each invocation. *) |
380 |
344 |
381 (* Term.term -> int Termtab.table -> prop_formula * int Termtab.table *) |
345 fun prop_formula_of_term t table = |
382 fun prop_formula_of_term t table = |
346 let |
383 let |
347 val next_idx_is_valid = Unsynchronized.ref false |
384 val next_idx_is_valid = Unsynchronized.ref false |
348 val next_idx = Unsynchronized.ref 0 |
385 val next_idx = Unsynchronized.ref 0 |
349 fun get_next_idx () = |
386 fun get_next_idx () = |
350 if !next_idx_is_valid then |
387 if !next_idx_is_valid then |
351 Unsynchronized.inc next_idx |
388 Unsynchronized.inc next_idx |
352 else ( |
389 else ( |
353 next_idx := Termtab.fold (Integer.max o snd) table 0; |
390 next_idx := Termtab.fold (Integer.max o snd) table 0; |
354 next_idx_is_valid := true; |
391 next_idx_is_valid := true; |
355 Unsynchronized.inc next_idx |
392 Unsynchronized.inc next_idx |
356 ) |
393 ) |
357 fun aux (Const (@{const_name True}, _)) table = (True, table) |
394 fun aux (Const (@{const_name True}, _)) table = |
358 | aux (Const (@{const_name False}, _)) table = (False, table) |
395 (True, table) |
359 | aux (Const (@{const_name Not}, _) $ x) table = apfst Not (aux x table) |
396 | aux (Const (@{const_name False}, _)) table = |
360 | aux (Const (@{const_name HOL.disj}, _) $ x $ y) table = |
397 (False, table) |
361 let |
398 | aux (Const (@{const_name Not}, _) $ x) table = |
362 val (fm1, table1) = aux x table |
399 apfst Not (aux x table) |
363 val (fm2, table2) = aux y table1 |
400 | aux (Const (@{const_name HOL.disj}, _) $ x $ y) table = |
364 in |
401 let |
365 (Or (fm1, fm2), table2) |
402 val (fm1, table1) = aux x table |
366 end |
403 val (fm2, table2) = aux y table1 |
367 | aux (Const (@{const_name HOL.conj}, _) $ x $ y) table = |
404 in |
368 let |
405 (Or (fm1, fm2), table2) |
369 val (fm1, table1) = aux x table |
406 end |
370 val (fm2, table2) = aux y table1 |
407 | aux (Const (@{const_name HOL.conj}, _) $ x $ y) table = |
371 in |
408 let |
372 (And (fm1, fm2), table2) |
409 val (fm1, table1) = aux x table |
373 end |
410 val (fm2, table2) = aux y table1 |
374 | aux x table = |
411 in |
375 (case Termtab.lookup table x of |
412 (And (fm1, fm2), table2) |
376 SOME i => (BoolVar i, table) |
413 end |
377 | NONE => |
414 | aux x table = |
378 let |
415 (case Termtab.lookup table x of |
379 val i = get_next_idx () |
416 SOME i => |
380 in |
417 (BoolVar i, table) |
381 (BoolVar i, Termtab.update (x, i) table) |
418 | NONE => |
382 end) |
419 let |
383 in |
420 val i = get_next_idx () |
384 aux t table |
421 in |
385 end; |
422 (BoolVar i, Termtab.update (x, i) table) |
|
423 end) |
|
424 in |
|
425 aux t table |
|
426 end; |
|
427 |
386 |
428 (* ------------------------------------------------------------------------- *) |
387 (* ------------------------------------------------------------------------- *) |
429 (* term_of_prop_formula: returns a HOL term that corresponds to a *) |
388 (* term_of_prop_formula: returns a HOL term that corresponds to a *) |
430 (* propositional formula, with Boolean variables replaced by Free's *) |
389 (* propositional formula, with Boolean variables replaced by Free's *) |
431 (* ------------------------------------------------------------------------- *) |
390 (* ------------------------------------------------------------------------- *) |