| 1 | |
|---|
| 2 | :- object(translator). |
|---|
| 3 | |
|---|
| 4 | :- info([ |
|---|
| 5 | version is 1.1, |
|---|
| 6 | date is 2007/10/13, |
|---|
| 7 | author is 'Paulo Moura', |
|---|
| 8 | comment is 'Translator of logic propositions to clauses in conjunctive normal form.', |
|---|
| 9 | source is 'Code partially based on an example found on the Clocksin and Mellish Prolog book.']). |
|---|
| 10 | |
|---|
| 11 | :- public(translate/2). |
|---|
| 12 | :- mode(translate(+nonvar, -list), zero_or_one). |
|---|
| 13 | :- info(translate/2, [ |
|---|
| 14 | comment is 'Translates a proposition to a list of clauses.', |
|---|
| 15 | argnames is ['Propostion', 'Clauses']]). |
|---|
| 16 | |
|---|
| 17 | :- public(step_by_step/2). |
|---|
| 18 | :- mode(step_by_step(+nonvar, -list), zero_or_one). |
|---|
| 19 | :- info(step_by_step/2, [ |
|---|
| 20 | comment is 'Translates a proposition to a list of clauses, printing the result of each translation step.', |
|---|
| 21 | argnames is ['Propostion', 'Clauses']]). |
|---|
| 22 | |
|---|
| 23 | :- private(gensym_counter_/1). |
|---|
| 24 | :- dynamic(gensym_counter_/1). |
|---|
| 25 | |
|---|
| 26 | |
|---|
| 27 | :- op(10, fy, ~ ). % negation |
|---|
| 28 | :- op(20, yfx, & ). % conjunction |
|---|
| 29 | :- op(30, yfx, v ). % disjunction |
|---|
| 30 | :- op(40, xfx, =>). % implication |
|---|
| 31 | :- op(40, xfx, <=>). % equivalence |
|---|
| 32 | |
|---|
| 33 | |
|---|
| 34 | translate(P, Cs) :- |
|---|
| 35 | remove_implications(P, P2), |
|---|
| 36 | distribute_negation(P2, P3), |
|---|
| 37 | remove_existential_quantifiers(P3, P4), |
|---|
| 38 | convert_to_prenex_normal_form(P4, P5), |
|---|
| 39 | remove_universal_quantifiers(P5, P6), |
|---|
| 40 | convert_to_conjunctive_normal_form(P6, P7), |
|---|
| 41 | convert_to_clauses(P7, Cs), |
|---|
| 42 | print_clauses(Cs). |
|---|
| 43 | |
|---|
| 44 | |
|---|
| 45 | step_by_step(P, Cs) :- |
|---|
| 46 | nl, write('Processing proposition: '), write(P), nl, nl, |
|---|
| 47 | write(' 1. Remove implications: '), |
|---|
| 48 | remove_implications(P, P2), |
|---|
| 49 | write(P2), nl, |
|---|
| 50 | write(' 2. Distribute negation: '), |
|---|
| 51 | distribute_negation(P2, P3), |
|---|
| 52 | write(P3), nl, |
|---|
| 53 | write(' 3. Remove existential quantifiers: '), |
|---|
| 54 | remove_existential_quantifiers(P3, P4), |
|---|
| 55 | write(P4), nl, |
|---|
| 56 | write(' 4. Convert to prenex normal form: '), |
|---|
| 57 | convert_to_prenex_normal_form(P4, P5), |
|---|
| 58 | write(P5), nl, |
|---|
| 59 | write(' 5. Remove universal quantifiers: '), |
|---|
| 60 | remove_universal_quantifiers(P5, P6), |
|---|
| 61 | write(P6), nl, |
|---|
| 62 | write(' 6. Convert to conjunctive normal form: '), |
|---|
| 63 | convert_to_conjunctive_normal_form(P6, P7), |
|---|
| 64 | write(P7), nl, |
|---|
| 65 | write(' 7. Convert to clauses: '), |
|---|
| 66 | convert_to_clauses(P7, Cs), |
|---|
| 67 | write(Cs), nl, nl, |
|---|
| 68 | write('Clauses in Prolog-like notation:'), nl, |
|---|
| 69 | print_clauses(Cs). |
|---|
| 70 | |
|---|
| 71 | |
|---|
| 72 | remove_implications(all(X, P), all(X, P2)) :- |
|---|
| 73 | !, |
|---|
| 74 | remove_implications(P, P2). |
|---|
| 75 | |
|---|
| 76 | remove_implications(exists(X, P), exists(X, P2)) :- |
|---|
| 77 | !, |
|---|
| 78 | remove_implications(P, P2). |
|---|
| 79 | |
|---|
| 80 | remove_implications(P <=> Q, P2 & Q2 v ~P2 & ~Q2) :- |
|---|
| 81 | !, |
|---|
| 82 | remove_implications(P, P2), |
|---|
| 83 | remove_implications(Q, Q2). |
|---|
| 84 | |
|---|
| 85 | remove_implications(P => Q, ~P2 v Q2) :- |
|---|
| 86 | !, |
|---|
| 87 | remove_implications(P, P2), |
|---|
| 88 | remove_implications(Q, Q2). |
|---|
| 89 | |
|---|
| 90 | remove_implications(P & Q, P2 & Q2) :- |
|---|
| 91 | !, |
|---|
| 92 | remove_implications(P, P2), |
|---|
| 93 | remove_implications(Q, Q2). |
|---|
| 94 | |
|---|
| 95 | remove_implications(P v Q, P2 v Q2) :- |
|---|
| 96 | !, |
|---|
| 97 | remove_implications(P, P2), |
|---|
| 98 | remove_implications(Q, Q2). |
|---|
| 99 | |
|---|
| 100 | remove_implications(~P, ~P2) :- |
|---|
| 101 | !, |
|---|
| 102 | remove_implications(P, P2). |
|---|
| 103 | |
|---|
| 104 | remove_implications(P, P). |
|---|
| 105 | |
|---|
| 106 | |
|---|
| 107 | distribute_negation(all(X, P), all(X, P2)) :- |
|---|
| 108 | !, |
|---|
| 109 | distribute_negation(P, P2). |
|---|
| 110 | |
|---|
| 111 | distribute_negation(exists(X, P), exists(X, P2)) :- |
|---|
| 112 | !, |
|---|
| 113 | distribute_negation(P, P2). |
|---|
| 114 | |
|---|
| 115 | distribute_negation(P & Q, P2 & Q2) :- |
|---|
| 116 | !, |
|---|
| 117 | distribute_negation(P, P2), |
|---|
| 118 | distribute_negation(Q, Q2). |
|---|
| 119 | |
|---|
| 120 | distribute_negation(P v Q, P2 v Q2) :- |
|---|
| 121 | !, |
|---|
| 122 | distribute_negation(P, P2), |
|---|
| 123 | distribute_negation(Q, Q2). |
|---|
| 124 | |
|---|
| 125 | distribute_negation(~P, P2) :- |
|---|
| 126 | !, |
|---|
| 127 | apply_negation(P, P2). |
|---|
| 128 | |
|---|
| 129 | distribute_negation(P, P). |
|---|
| 130 | |
|---|
| 131 | |
|---|
| 132 | apply_negation(all(X, P), exists(X, P2)) :- |
|---|
| 133 | !, |
|---|
| 134 | apply_negation(P, P2). |
|---|
| 135 | |
|---|
| 136 | apply_negation(exists(X, P), all(X, P2)) :- |
|---|
| 137 | !, |
|---|
| 138 | apply_negation(P, P2). |
|---|
| 139 | |
|---|
| 140 | apply_negation(P & Q, P2 v Q2) :- |
|---|
| 141 | !, |
|---|
| 142 | apply_negation(P, P2), |
|---|
| 143 | apply_negation(Q, Q2). |
|---|
| 144 | |
|---|
| 145 | apply_negation(P v Q, P2 & Q2) :- |
|---|
| 146 | !, |
|---|
| 147 | apply_negation(P, P2), |
|---|
| 148 | apply_negation(Q, Q2). |
|---|
| 149 | |
|---|
| 150 | apply_negation(~P, P2) :- |
|---|
| 151 | !, |
|---|
| 152 | distribute_negation(P, P2). |
|---|
| 153 | |
|---|
| 154 | apply_negation(P, ~P). |
|---|
| 155 | |
|---|
| 156 | |
|---|
| 157 | remove_existential_quantifiers(P, P2) :- |
|---|
| 158 | remove_existential_quantifiers(P, P2, []). |
|---|
| 159 | |
|---|
| 160 | remove_existential_quantifiers(all(X, P), all(X, P2), Vars) :- |
|---|
| 161 | !, |
|---|
| 162 | remove_existential_quantifiers(P, P2, [X| Vars]). |
|---|
| 163 | |
|---|
| 164 | remove_existential_quantifiers(exists(X, P), P2, Vars) :- |
|---|
| 165 | !, |
|---|
| 166 | gensym(f, F), |
|---|
| 167 | X =.. [F| Vars], |
|---|
| 168 | remove_existential_quantifiers(P, P2, Vars). |
|---|
| 169 | |
|---|
| 170 | remove_existential_quantifiers(P & Q, P2 & Q2, Vars) :- |
|---|
| 171 | !, |
|---|
| 172 | remove_existential_quantifiers(P, P2, Vars), |
|---|
| 173 | remove_existential_quantifiers(Q, Q2, Vars). |
|---|
| 174 | |
|---|
| 175 | remove_existential_quantifiers(P v Q, P2 v Q2, Vars) :- |
|---|
| 176 | !, |
|---|
| 177 | remove_existential_quantifiers(P, P2, Vars), |
|---|
| 178 | remove_existential_quantifiers(Q, Q2, Vars). |
|---|
| 179 | |
|---|
| 180 | remove_existential_quantifiers(P, P, _). |
|---|
| 181 | |
|---|
| 182 | |
|---|
| 183 | convert_to_prenex_normal_form(P, P2) :- |
|---|
| 184 | collect_vars(P, P1, [], Vars), |
|---|
| 185 | add_vars_at_front(Vars, P1, P2). |
|---|
| 186 | |
|---|
| 187 | collect_vars(all(X, P), P2, Acc, Vars) :- |
|---|
| 188 | !, |
|---|
| 189 | collect_vars(P, P2, [X| Acc], Vars). |
|---|
| 190 | |
|---|
| 191 | collect_vars(P & Q, P2 & Q2, Acc, Vars) :- |
|---|
| 192 | !, |
|---|
| 193 | collect_vars(P, P2, Acc, Acc2), |
|---|
| 194 | collect_vars(Q, Q2, Acc2, Vars). |
|---|
| 195 | |
|---|
| 196 | collect_vars(P v Q, P2 v Q2, Acc, Vars) :- |
|---|
| 197 | !, |
|---|
| 198 | collect_vars(P, P2, Acc, Acc2), |
|---|
| 199 | collect_vars(Q, Q2, Acc2, Vars). |
|---|
| 200 | |
|---|
| 201 | collect_vars(P, P, Vars, Vars). |
|---|
| 202 | |
|---|
| 203 | |
|---|
| 204 | add_vars_at_front([], P, P). |
|---|
| 205 | |
|---|
| 206 | add_vars_at_front([X| Vars], P, P2) :- |
|---|
| 207 | add_vars_at_front(Vars, all(X, P), P2). |
|---|
| 208 | |
|---|
| 209 | |
|---|
| 210 | remove_universal_quantifiers(all(_, P), P2) :- |
|---|
| 211 | !, |
|---|
| 212 | remove_universal_quantifiers(P, P2). |
|---|
| 213 | |
|---|
| 214 | remove_universal_quantifiers(P & Q, P2 & Q2) :- |
|---|
| 215 | !, |
|---|
| 216 | remove_universal_quantifiers(P, P2), |
|---|
| 217 | remove_universal_quantifiers(Q, Q2). |
|---|
| 218 | |
|---|
| 219 | remove_universal_quantifiers(P v Q, P2 v Q2) :- |
|---|
| 220 | !, |
|---|
| 221 | remove_universal_quantifiers(P, P2), |
|---|
| 222 | remove_universal_quantifiers(Q, Q2). |
|---|
| 223 | |
|---|
| 224 | remove_universal_quantifiers(P, P). |
|---|
| 225 | |
|---|
| 226 | |
|---|
| 227 | convert_to_conjunctive_normal_form(P v Q, R) :- |
|---|
| 228 | !, |
|---|
| 229 | convert_to_conjunctive_normal_form(P, P2), |
|---|
| 230 | convert_to_conjunctive_normal_form(Q, Q2), |
|---|
| 231 | distribute_disjunction(P2 v Q2, R). |
|---|
| 232 | |
|---|
| 233 | convert_to_conjunctive_normal_form(P & Q, P2 & Q2) :- |
|---|
| 234 | !, |
|---|
| 235 | convert_to_conjunctive_normal_form(P, P2), |
|---|
| 236 | convert_to_conjunctive_normal_form(Q, Q2). |
|---|
| 237 | |
|---|
| 238 | convert_to_conjunctive_normal_form(P, P). |
|---|
| 239 | |
|---|
| 240 | |
|---|
| 241 | distribute_disjunction(P & Q v R, P2 & Q2) :- |
|---|
| 242 | !, |
|---|
| 243 | convert_to_conjunctive_normal_form(P v R, P2), |
|---|
| 244 | convert_to_conjunctive_normal_form(Q v R, Q2). |
|---|
| 245 | |
|---|
| 246 | distribute_disjunction(P v Q & R, P2 & Q2) :- |
|---|
| 247 | !, |
|---|
| 248 | convert_to_conjunctive_normal_form(P v Q, P2), |
|---|
| 249 | convert_to_conjunctive_normal_form(P v R, Q2). |
|---|
| 250 | |
|---|
| 251 | distribute_disjunction(P, P). |
|---|
| 252 | |
|---|
| 253 | |
|---|
| 254 | convert_to_clauses(P, Cs) :- |
|---|
| 255 | convert_to_clauses(P, [], Cs). |
|---|
| 256 | |
|---|
| 257 | |
|---|
| 258 | convert_to_clauses(P & Q, Acc, Cs) :- |
|---|
| 259 | !, |
|---|
| 260 | convert_to_clauses(Q, Acc, Acc2), |
|---|
| 261 | convert_to_clauses(P, Acc2, Cs). |
|---|
| 262 | |
|---|
| 263 | convert_to_clauses(P, Acc, [cl(Pos, Negs)| Acc]) :- |
|---|
| 264 | convert_to_clauses(P, [], Pos, [], Negs), |
|---|
| 265 | !. |
|---|
| 266 | |
|---|
| 267 | convert_to_clauses(_, Cs, Cs). |
|---|
| 268 | |
|---|
| 269 | |
|---|
| 270 | convert_to_clauses(P v Q, AccPos, Pos, AccNegs, Negs) :- |
|---|
| 271 | !, |
|---|
| 272 | convert_to_clauses(Q, AccPos, AccPos2, AccNegs, AccNegs2), |
|---|
| 273 | convert_to_clauses(P, AccPos2, Pos, AccNegs2, Negs). |
|---|
| 274 | |
|---|
| 275 | convert_to_clauses(~P, Pos, Pos, AccNegs, [P| AccNegs]) :- |
|---|
| 276 | !, |
|---|
| 277 | not_member_of(P, Pos). |
|---|
| 278 | |
|---|
| 279 | convert_to_clauses(P, AccPos, [P| AccPos], Negs, Negs) :- |
|---|
| 280 | !, |
|---|
| 281 | not_member_of(P, Negs). |
|---|
| 282 | |
|---|
| 283 | /* |
|---|
| 284 | convert_to_clauses(P & Q, {P2, Q2}) :- |
|---|
| 285 | !, |
|---|
| 286 | convert_to_clauses(P, P2), |
|---|
| 287 | convert_to_clauses(Q, Q2). |
|---|
| 288 | |
|---|
| 289 | convert_to_clauses(P v Q, R) :- |
|---|
| 290 | !, |
|---|
| 291 | convert_to_clause(P v Q, R). |
|---|
| 292 | |
|---|
| 293 | convert_to_clauses(P, {P}). |
|---|
| 294 | |
|---|
| 295 | |
|---|
| 296 | convert_to_clause(P & Q, R) :- |
|---|
| 297 | !, |
|---|
| 298 | convert_to_clauses(P & Q, {R}). |
|---|
| 299 | |
|---|
| 300 | convert_to_clause(P v Q, {P2, Q}) :- |
|---|
| 301 | !, |
|---|
| 302 | convert_to_clause(P, P2). |
|---|
| 303 | |
|---|
| 304 | convert_to_clause(P, P). |
|---|
| 305 | */ |
|---|
| 306 | |
|---|
| 307 | not_member_of(P, [P| _]) :- |
|---|
| 308 | !, |
|---|
| 309 | fail. |
|---|
| 310 | |
|---|
| 311 | not_member_of(P, [_| Ps]) :- |
|---|
| 312 | !, |
|---|
| 313 | not_member_of(P, Ps). |
|---|
| 314 | |
|---|
| 315 | not_member_of(_, []). |
|---|
| 316 | |
|---|
| 317 | |
|---|
| 318 | print_clauses([]) :- |
|---|
| 319 | nl. |
|---|
| 320 | |
|---|
| 321 | print_clauses([cl(Pos, Negs)| Cs]) :- |
|---|
| 322 | print_clause(Pos, Negs), nl, |
|---|
| 323 | print_clauses(Cs). |
|---|
| 324 | |
|---|
| 325 | print_clause(Pos, []) :- |
|---|
| 326 | !, |
|---|
| 327 | print_disjunctions(Pos), write(' :- .'). |
|---|
| 328 | |
|---|
| 329 | print_clause([], Negs) :- |
|---|
| 330 | !, |
|---|
| 331 | write(':- '), print_conjunctions(Negs), write('.'). |
|---|
| 332 | |
|---|
| 333 | print_clause(Pos, Negs) :- |
|---|
| 334 | !, |
|---|
| 335 | print_disjunctions(Pos), write(' :- '), |
|---|
| 336 | print_conjunctions(Negs), write('.'). |
|---|
| 337 | |
|---|
| 338 | |
|---|
| 339 | print_disjunctions([P]) :- |
|---|
| 340 | !, |
|---|
| 341 | write(P). |
|---|
| 342 | |
|---|
| 343 | print_disjunctions([P| Ps]) :- |
|---|
| 344 | !, |
|---|
| 345 | write(P), write('; '), |
|---|
| 346 | print_disjunctions(Ps). |
|---|
| 347 | |
|---|
| 348 | |
|---|
| 349 | print_conjunctions([P]) :- |
|---|
| 350 | !, |
|---|
| 351 | write(P). |
|---|
| 352 | |
|---|
| 353 | print_conjunctions([P| Ps]) :- |
|---|
| 354 | !, |
|---|
| 355 | write(P), write(', '), |
|---|
| 356 | print_conjunctions(Ps). |
|---|
| 357 | |
|---|
| 358 | |
|---|
| 359 | gensym_counter_(0). |
|---|
| 360 | |
|---|
| 361 | |
|---|
| 362 | gensym(Base, Atom) :- |
|---|
| 363 | retract(gensym_counter_(Counter)), |
|---|
| 364 | Counter2 is Counter + 1, |
|---|
| 365 | number_codes(Counter2, Codes2), |
|---|
| 366 | atom_codes(Number, Codes2), |
|---|
| 367 | atom_concat(Base, Number, Atom), |
|---|
| 368 | assertz(gensym_counter_(Counter2)). |
|---|
| 369 | |
|---|
| 370 | |
|---|
| 371 | :- end_object. |
|---|