Connect++ 0.7.0
A fast, readable connection prover for first-order logic.
Loading...
Searching...
No Matches
FOF.cpp
1/*
2
3Copyright © 2023-26 Sean Holden. All rights reserved.
4
5*/
6/*
7
8This file is part of Connect++.
9
10Connect++ is free software: you can redistribute it and/or modify it
11under the terms of the GNU General Public License as published by the
12Free Software Foundation, either version 3 of the License, or (at your
13option) any later version.
14
15Connect++ is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18more details.
19
20You should have received a copy of the GNU General Public License along
21with Connect++. If not, see <https://www.gnu.org/licenses/>.
22
23*/
24
25#include "FOF.hpp"
26
29TermIndex* FOF::term_index = nullptr;
31TPTPRecords* FOF::recs_p = nullptr;
32
33//---------------------------------------------------------------------------
34// Simple methods for Variables.
35//---------------------------------------------------------------------------
37 switch (type) {
38 case FOFType::Empty:
39 cerr << "Don't do this with an Empty FOF!" << endl;
40 return false;
41 break;
42 case FOFType::Atom:
43 return pred.contains_variable(v);
44 case FOFType::Neg:
45 return (sub_formulas[0].has_free_variable(v));
46 break;
47 case FOFType::And:
48 case FOFType::Or:
49 for (size_t i = 0; i < sub_formulas.size(); i++) {
51 return true;
52 }
53 }
54 return false;
55 break;
56 case FOFType::Imp:
57 case FOFType::Iff:
58 return (sub_formulas[0].has_free_variable(v) ||
60 break;
61 case FOFType::A:
62 case FOFType::E:
63 if (var == v)
64 return false;
65 return sub_formulas[0].has_free_variable(v);
66 break;
67 default:
68 break;
69 }
70 return false;
71}
72//---------------------------------------------------------------------------
73void FOF::replace_variable(Variable* new_var, Variable* old_var) {
74 if (type == FOFType::Empty) {
75 cerr << "Don't do this with an Empty FOF!" << endl;
76 return;
77 }
78 if (type == FOFType::Atom) {
79 pred.replace_variable(new_var, old_var, term_index);
80 }
81 else {
82 for (FOF& f : sub_formulas)
83 f.replace_variable(new_var, old_var);
84 }
85}
86//---------------------------------------------------------------------------
88 set<Term*> a = this->find_free_variables();
89 vector<Term*> args;
90 for (Term* p : a)
91 args.push_back(p);
93 Literal lit(name, args, args.size(), true);
94 return FOF(lit);
95}
96//---------------------------------------------------------------------------
98 // For literals there is nothing to do.
99 if (is_literal()) {
100 return false;
101 }
102 // If we're at an AND, or an OR with no AND immediately under it,
103 // then we're just going to deal with the subformulas.
104 size_t and_location = find_and();
105 size_t s = sub_formulas.size();
106 if (type == FOFType::And ||
107 ((type == FOFType::Or) && (and_location == s))) {
108 bool result = false;
109 // OK, so it's not, strictly speaking, just "once" but
110 // we don't really mind do we?
111 for (size_t i = 0; i < s; i++) {
113 result = true;
114 }
115 return result;
116 }
117 // It must be an OR with an AND immediately under it. That means
118 // we can distribute. First get the AND's subformulas and
119 // remove it.
120 vector<FOF> and_fof_subs = sub_formulas[and_location].sub_formulas;
121 if (and_location != (s-1)) {
122 sub_formulas[and_location] = sub_formulas[s-1];
123 }
124 sub_formulas.pop_back();
125 // Now you've saved the sub-formulas for the AND, and
126 // removed it. The last remaining child of the OR is
127 // now going to be combined using OR with all
128 // the saved subformulas.
129 FOF f = sub_formulas[s-2];
130 size_t s2 = and_fof_subs.size();
131 vector<FOF> new_sub_formulas_2;
132 for (int i = 0; i < s2; i++) {
133 vector<FOF> new_sub_formulas;
134 new_sub_formulas.push_back(f);
135 new_sub_formulas.push_back(and_fof_subs[i]);
136 new_sub_formulas_2.push_back(FOF::make_or(new_sub_formulas));
137 }
138 // You may have started with an OR with only two children. If so
139 // then you can now move the AND upwards.
140 if (s == 2) {
141 type = FOFType::And;
142 sub_formulas = new_sub_formulas_2;
143 }
144 else {
145 sub_formulas[s-2] = FOF::make_and(new_sub_formulas_2);
146 }
147 return true;
148}
149//---------------------------------------------------------------------------
151 // For literals there is nothing to do.
152 if (is_literal()) {
153 return false;
154 }
155 // If we're at an OR, or an AND with no OR immediately under it,
156 // then we're just going to deal with the subformulas.
157 size_t or_location = find_or();
158 size_t s = sub_formulas.size();
159 if (type == FOFType::Or ||
160 ((type == FOFType::And) && (or_location == s))) {
161 bool result = false;
162 // OK, so it's not, strictly speaking, just "once" but
163 // we don't really mind do we?
164 for (size_t i = 0; i < s; i++) {
166 result = true;
167 }
168 return result;
169 }
170 // It must be an AND with an OR immediately under it. That means
171 // we can distribute. First get the OR's subformulas and
172 // remove it.
173 vector<FOF> or_fof_subs = sub_formulas[or_location].sub_formulas;
174 if (or_location != (s-1)) {
175 sub_formulas[or_location] = sub_formulas[s-1];
176 }
177 sub_formulas.pop_back();
178 // Now you've saved the sub-formulas for the OR, and
179 // removed it. The last remaining child of the AND is
180 // now going to be combined using AND with all
181 // the saved subformulas.
182 FOF f = sub_formulas[s-2];
183 size_t s2 = or_fof_subs.size();
184 vector<FOF> new_sub_formulas_2;
185 for (int i = 0; i < s2; i++) {
186 vector<FOF> new_sub_formulas;
187 new_sub_formulas.push_back(f);
188 new_sub_formulas.push_back(or_fof_subs[i]);
189 new_sub_formulas_2.push_back(FOF::make_and(new_sub_formulas));
190 }
191 // You may have started with an AND with only two children. If so
192 // then you can now move the OR upwards.
193 if (s == 2) {
194 type = FOFType::Or;
195 sub_formulas = new_sub_formulas_2;
196 }
197 else {
198 sub_formulas[s-2] = FOF::make_or(new_sub_formulas_2);
199 }
200 return true;
201}
202//---------------------------------------------------------------------------
203// Skolemization
204//---------------------------------------------------------------------------
205Term* FOF::make_skolem_function(const vector<Term*>& args) {
206 Function* sk = fun_index->make_skolem_function(args.size());
207 Term* sk_t = term_index->add_function_term(sk, args);
208 return sk_t;
209}
210//---------------------------------------------------------------------------
212 if (type == FOFType::Empty) {
213 cerr << "Don't do this with an Empty FOF!" << endl;
214 return;
215 }
216 if (type == FOFType::Atom) {
217 pred.replace_variable_with_term(new_term, old_var, term_index);
218 }
219 else {
220 for (FOF& f : sub_formulas)
221 f.replace_variable_with_term(new_term, old_var);
222 }
223}
224//---------------------------------------------------------------------------
225void FOF::skolemize_main(vector<Term*> skolem_arguments,
226 FOF* whole_f,
227 bool tptp) {
228 Term* sk_t;
229 FOF f(FOFType::Atom);
230 string sk_s;
231 string sk_t_s;
232 string var_s;
233 string f_s;
234 switch (type) {
235 case FOFType::Atom:
236 break;
237 case FOFType::Neg:
238 sub_formulas[0].skolemize_main(skolem_arguments, whole_f, tptp);
239 break;
240 case FOFType::And:
241 case FOFType::Or:
242 case FOFType::Imp:
243 case FOFType::Iff:
244 for (FOF& g : sub_formulas)
245 g.skolemize_main(skolem_arguments, whole_f, tptp);
246 break;
247 case FOFType::A:
248 skolem_arguments.push_back(term_index->add_variable_term(var));
249 sub_formulas[0].skolemize_main(skolem_arguments, whole_f, tptp);
250 break;
251 case FOFType::E:
252 sk_t = make_skolem_function(skolem_arguments);
253 if (tptp) {
254 sk_s = sk_t->get_f()->get_name();
255 sk_t_s = sk_t->to_prolog_string();
256 var_s = var->to_prolog_string();
257 }
258 sub_formulas[0].replace_variable_with_term(sk_t, var);
259 f = sub_formulas[0];
260 *this = f;
261 if (tptp) {
262 FOF f2 = *whole_f;
263 f_s = f2.to_tptp_string();
264 recs_p->add_skolemization_record(f_s, var_s, sk_t_s, sk_s);
265 }
266 skolemize_main(skolem_arguments, whole_f, tptp);
267 break;
268 default:
269 break;
270 }
271}
272//---------------------------------------------------------------------------
273void FOF::skolemize_universals_main(vector<Term*> skolem_arguments,
274 FOF* whole_f,
275 bool tptp) {
276 Term* sk_t;
277 FOF f(FOFType::Atom);
278 string sk_s;
279 string sk_t_s;
280 string var_s;
281 string f_s;
282 switch (type) {
283 case FOFType::Atom:
284 break;
285 case FOFType::Neg:
286 sub_formulas[0].skolemize_universals_main(skolem_arguments, whole_f, tptp);
287 break;
288 case FOFType::And:
289 case FOFType::Or:
290 case FOFType::Imp:
291 case FOFType::Iff:
292 for (FOF& g : sub_formulas)
293 g.skolemize_universals_main(skolem_arguments, whole_f, tptp);
294 break;
295 case FOFType::E:
296 skolem_arguments.push_back(term_index->add_variable_term(var));
297 sub_formulas[0].skolemize_universals_main(skolem_arguments, whole_f, tptp);
298 break;
299 case FOFType::A:
300 sk_t = make_skolem_function(skolem_arguments);
301 if (tptp) {
302 sk_s = sk_t->get_f()->get_name();
303 sk_t_s = sk_t->to_prolog_string();
304 var_s = var->to_prolog_string();
305 }
306 sub_formulas[0].replace_variable_with_term(sk_t, var);
307 f = sub_formulas[0];
308 *this = f;
309 if (tptp) {
310 FOF f2 = *whole_f;
311 f_s = f2.to_tptp_string();
312 recs_p->add_herbrandization_record(f_s, var_s, sk_t_s, sk_s);
313 }
314 skolemize_universals_main(skolem_arguments, whole_f, tptp);
315 break;
316 default:
317 break;
318 }
319}
320//---------------------------------------------------------------------------
321// Miniscoping
322//---------------------------------------------------------------------------
324 vector<FOF>& free,
325 vector<FOF>& absent) {
326 // Remember that at this point you have a NNF with
327 // unique variables. So whatever is in the subformula
328 // is AND, OR, Atom or Neg (Literal).
329 vector<FOF>& subs = sub_formulas[0].sub_formulas;
330 for (size_t i = 0; i < subs.size(); i++) {
331 FOF f(subs[i]);
332 if (f.has_free_variable(v))
333 free.push_back(f);
334 else
335 absent.push_back(f);
336 }
337}
338//---------------------------------------------------------------------------
340 for (size_t i = 0; i < sub_formulas.size(); i++ ) {
341 sub_formulas[i].miniscope();
342 }
343}
344//---------------------------------------------------------------------------
345// Constructors.
346//---------------------------------------------------------------------------
347FOF::FOF(const Literal& lit)
348: sub_formulas()
349, var(nullptr)
350{
351 if (lit.is_positive()) {
352 type = FOFType::Atom;
353 pred = lit;
354 }
355 else {
356 pred.clear();
357 type = FOFType::Neg;
358 Literal lit_copy = lit;
359 lit_copy.make_positive();
360 FOF f(lit_copy);
361 sub_formulas.push_back(f);
362 }
363}
364//---------------------------------------------------------------------------
365FOF::FOF(FOFType t, const vector<FOF>& sf, Variable* v)
366: type(t)
367, pred()
368, sub_formulas(sf)
369, var(v)
370{
371 switch (t) {
372 case FOFType::Atom:
373 cerr << "Stop it! You can't make an atom with this constructor!" << endl;
374 break;
375 case FOFType::Neg:
376 case FOFType::And:
377 case FOFType::Or:
378 case FOFType::Imp:
379 case FOFType::Iff:
380 // Easy as the work gets done above.
381 if (var != nullptr) {
382 cerr << "Are you sure you want to associate a variable with something that's not a quantifier?" << endl;
383 var = nullptr;
384 }
385 break;
386 case FOFType::A:
387 case FOFType::E:
388 if (sf.size() != 1) {
389 cerr << "Careful! A quantifier should only have one subformula." << endl;
390 }
391 if (v == nullptr) {
392 cerr << "Careful! A quantifier needs a variable." << endl;
393 }
394 break;
395 default:
396 break;
397 }
398}
399//---------------------------------------------------------------------------
400// Basic tests.
401//---------------------------------------------------------------------------
402bool FOF::is_literal() const {
403 return (type == FOFType::Atom) ||
404 (type == FOFType::Neg && sub_formulas[0].type == FOFType::Atom);
405}
406//---------------------------------------------------------------------------
407bool FOF::is_clause() const {
408 if (is_literal()) {
409 return true;
410 }
411 if (!(type == FOFType::Or)) {
412 return false;
413 }
414 for (size_t i = 0; i < sub_formulas.size(); i++) {
415 if (!sub_formulas[i].is_literal()) {
416 return false;
417 }
418 }
419 return true;
420}
421//---------------------------------------------------------------------------
422// Standard simplifications.
423//---------------------------------------------------------------------------
425 if (type == FOFType::Neg) {
426 FOF f = sub_formulas[0];
427 *this = f;
428 }
429}
430//---------------------------------------------------------------------------
432 if (type == FOFType::Empty) {
433 cerr << "Don't do this with an Empty FOF!" << endl;
434 return;
435 }
436 if (type == FOFType::Imp) {
437 type = FOFType::And;
438 sub_formulas[1].negate();
439 }
440 else if (type == FOFType::Neg) {
442 }
443 else {
444 FOF f = *this;
445 type = FOFType::Neg;
446 pred.clear();
447 var = nullptr;
448 sub_formulas.clear();
449 sub_formulas.push_back(f);
450 }
451}
452//---------------------------------------------------------------------------
454 FOF f = *this;
455 type = FOFType::Neg;
456 pred.clear();
457 var = nullptr;
458 sub_formulas.clear();
459 sub_formulas.push_back(f);
460}
461//---------------------------------------------------------------------------
463 if (type == FOFType::Atom) {
465 return;
466 }
467 if (type == FOFType::Neg && sub_formulas[0].type == FOFType::Atom) {
469 return;
470 }
471 cerr << "Don't use this with a non-literal." << endl;
472}
473//---------------------------------------------------------------------------
475 if (type == FOFType::Empty) {
476 cerr << "Don't do this with an Empty FOF!" << endl;
477 return;
478 }
479 // End of recursion.
480 if (type == FOFType::Atom)
481 return;
482 // Do the relevant transformation.
483 if (type == FOFType::Iff) {
484 FOF lhs = *this;
485 FOF rhs = *this;
486 lhs.type = FOFType::Imp;
487 rhs.type = FOFType::Imp;
488 FOF store = rhs.sub_formulas[1];
489 rhs.sub_formulas[1] = rhs.sub_formulas[0];
490 rhs.sub_formulas[0] = store;
491 type = FOFType::And;
492 sub_formulas.clear();
493 sub_formulas.push_back(lhs);
494 sub_formulas.push_back(rhs);
495 }
496 // Finish the job. Also applies the transformation to other FOF types.
497 for (FOF& f : sub_formulas)
498 f.remove_iff();
499}
500//---------------------------------------------------------------------------
502 if (type == FOFType::Empty) {
503 cerr << "Don't do this with an Empty FOF!" << endl;
504 return;
505 }
506 // End of recursion.
507 if (type == FOFType::Atom)
508 return;
509 // Do the relevant transformation.
510 if (type == FOFType::Imp) {
511 type = FOFType::Or;
512 sub_formulas[0].negate();
513 }
514 // Finish the job. Also applies the transformation to other FOF types.
515 for (FOF& f : sub_formulas)
516 f.remove_imp();
517}
518//---------------------------------------------------------------------------
520 Variable* new_var;
521 switch (type) {
522 case FOFType::Atom:
523 break;
524 case FOFType::Neg:
525 case FOFType::And:
526 case FOFType::Or:
527 case FOFType::Imp:
528 case FOFType::Iff:
529 for (FOF& sf : sub_formulas)
530 sf.make_unique_bound_variables();
531 break;
532 case FOFType::A:
533 case FOFType::E:
534 sub_formulas[0].make_unique_bound_variables();
535 new_var = var_index->add_unique_var();
536 sub_formulas[0].replace_variable(new_var, var);
537 var = new_var;
538 break;
539 default:
540 break;
541 }
542}
543//---------------------------------------------------------------------------
545 Variable* new_var;
546 switch (type) {
547 case FOFType::Atom:
548 break;
549 case FOFType::Neg:
550 case FOFType::And:
551 case FOFType::Or:
552 case FOFType::Imp:
553 case FOFType::Iff:
554 for (FOF& sf : sub_formulas)
555 sf.remove_redundant_quantifiers();
556 break;
557 case FOFType::A:
558 case FOFType::E:
559 sub_formulas[0].remove_redundant_quantifiers();
561 vector<FOF> sf(sub_formulas);
562 type = sub_formulas[0].type;
563 pred = sub_formulas[0].pred;
564 var = sub_formulas[0].var;
565 sub_formulas = sf[0].sub_formulas;
566 }
567 break;
568 default:
569 break;
570 }
571}
572//---------------------------------------------------------------------------
574 switch (type) {
575 case FOFType::Neg:
576 switch (sub_formulas[0].type) {
577 case FOFType::Neg:
580 push_negs();
581 break;
582 case FOFType::Atom:
583 break;
584 case FOFType::And:
586 type = FOFType::Or;
587 for (FOF& f : sub_formulas) {
588 f.negate();
589 f.push_negs();
590 }
591 break;
592 case FOFType::Or:
594 type = FOFType::And;
595 for (FOF& f : sub_formulas) {
596 f.negate();
597 f.push_negs();
598 }
599 break;
600 case FOFType::A:
602 type = FOFType::E;
603 sub_formulas[0].negate();
604 sub_formulas[0].push_negs();
605 break;
606 case FOFType::E:
608 type = FOFType::A;
609 sub_formulas[0].negate();
610 sub_formulas[0].push_negs();
611 break;
612 case FOFType::Imp:
613 case FOFType::Iff:
614 cerr << "Stop it!!! You don't push negations through -> or <->." << endl;
615 break;
616 default:
617 break;
618 }
619 break;
620 case FOFType::Atom:
621 break;
622 case FOFType::And:
623 case FOFType::Or:
624 case FOFType::A:
625 case FOFType::E:
626 for (FOF& f : sub_formulas)
627 f.push_negs();
628 break;
629 case FOFType::Imp:
630 case FOFType::Iff:
631 cerr << "Stop it!!! You don't push negations through -> or <->." << endl;
632 break;
633 default:
634 break;
635 }
636}
637//---------------------------------------------------------------------------
639 if (type == FOFType::Empty) {
640 cerr << "Don't do this with an Empty FOF!" << endl;
641 return;
642 }
643 remove_iff();
644 remove_imp();
645 push_negs();
646}
647//---------------------------------------------------------------------------
649 vector<FOF> free;
650 vector<FOF> absent;
651 FOF new_sub(FOFType::Empty);
652 vector<FOF> new_subs;
653 Variable* new_var;
654 switch (type) {
655 case FOFType::Empty:
656 cerr << "Don't do this with an empty formula" << endl;
657 break;
658 case FOFType::Atom:
659 case FOFType::Neg:
660 break;
661 case FOFType::And:
662 case FOFType::Or:
664 break;
665 case FOFType::Imp:
666 case FOFType::Iff:
667 cerr << "Don't do this unless you've removed -> and <->" << endl;
668 break;
669 // Remember you're only dealing with stuff in NNF. You
670 // do however have to handle nested quantifiers.
671 case FOFType::A:
672 sub_formulas[0].miniscope();
673 if (!(sub_formulas[0].type == FOFType::And ||
674 sub_formulas[0].type == FOFType::Or)) {
675 return;
676 }
677 // You have \forall followed by (miniscoped) AND or OR.
678 miniscope_split(var, free, absent);
679 // If the quantifier is followed by AND you can just
680 // make a \forall for every subformula involving the
681 // variable.
682 if (sub_formulas[0].type == FOFType::And) {
683 type = FOFType::And;
684 // If everything is bound then make a new forall everywhere
685 // with a new variable.
686 if (free.size() == sub_formulas[0].sub_formulas.size()) {
687 for (size_t i = 0; i < free.size(); i++) {
688 new_var = var_index->add_unique_var();
689 new_sub = free[i];
690 new_sub.replace_variable(new_var, var);
691 new_sub = FOF::make_forall(new_sub, new_var);
692 new_subs.push_back(new_sub);
693 }
694 sub_formulas = new_subs;
695 }
696 // If any subformula doesn't have the variable then just
697 // move the forall in. Remember you need to consider the
698 // possibility that the quantifier can just be removed.
699 else if (free.size() > 0) {
700 sub_formulas = absent;
701 if (free.size() == 1)
702 new_sub = free[0];
703 else
704 new_sub = FOF::make_and(free);
705 new_sub = FOF::make_forall(new_sub, var);
706 sub_formulas.push_back(new_sub);
707 }
708 // You're just going to remove the quantifier.
709 else {
710 sub_formulas = sub_formulas[0].sub_formulas;
711 }
712 var = nullptr;
714 return;
715 }
716 if (sub_formulas[0].type == FOFType::Or) {
717 // You have a \forall followed by an OR.
718 // If eveything is bound there's nothing to do.
719 if (absent.size() == 0)
720 return;
721 else if (free.size() > 0) {
722 type = FOFType::Or;
723 sub_formulas = absent;
724 if (free.size() == 1)
725 new_sub = free[0];
726 else
727 new_sub = FOF::make_or(free);
728 new_sub = FOF::make_forall(new_sub, var);
729 sub_formulas.push_back(new_sub);
730 var = nullptr;
732 }
733 // You can just drop the quantifier.
734 else {
735 type = FOFType::Or;
736 vector<FOF> sf(sub_formulas);
737 sub_formulas = sf[0].sub_formulas;
738 var = nullptr;
739 }
740 return;
741 }
742 break;
743 // You have an \exists.
744 case FOFType::E:
745 sub_formulas[0].miniscope();
746 if (!(sub_formulas[0].type == FOFType::And ||
747 sub_formulas[0].type == FOFType::Or)) {
748 return;
749 }
750 // You have an \exists followed by AND or OR.
751 miniscope_split(var, free, absent);
752 if (sub_formulas[0].type == FOFType::Or) {
753 type = FOFType::Or;
754 // If everything is bound then make a new exists everywhere
755 // with a new variable.
756 if (free.size() == sub_formulas[0].sub_formulas.size()) {
757 for (size_t i = 0; i < free.size(); i++) {
758 new_var = var_index->add_unique_var();
759 new_sub = free[i];
760 new_sub.replace_variable(new_var, var);
761 new_sub = FOF::make_exists(new_sub, new_var);
762 new_subs.push_back(new_sub);
763 }
764 sub_formulas = new_subs;
765 }
766 // If any subformula doesn't have the variable then just
767 // move the \exists in.
768 else if (free.size() > 0) {
769 sub_formulas = absent;
770 if (free.size() == 1)
771 new_sub = free[0];
772 else
773 new_sub = FOF::make_or(free);
774 new_sub = FOF::make_exists(new_sub, var);
775 sub_formulas.push_back(new_sub);
776 }
777 // We're just going to drop the quantifier.
778 else {
779 sub_formulas = sub_formulas[0].sub_formulas;
780 }
781 var = nullptr;
783 return;
784 }
785 // You have an \exists followed by and AND.
786 if (sub_formulas[0].type == FOFType::And) {
787 // If eveything is bound there's nothing to do.
788 if (absent.size() == 0)
789 return;
790 else if (free.size() != sub_formulas[0].sub_formulas.size()) {
791 type = FOFType::And;
792 sub_formulas = absent;
793 if (free.size() == 1)
794 new_sub = free[0];
795 else
796 new_sub = FOF::make_and(free);
797 new_sub = FOF::make_exists(new_sub, var);
798 sub_formulas.push_back(new_sub);
799 var = nullptr;
801 }
802 // We can just drop the quantifier.
803 else {
804 type = FOFType::And;
805 vector<FOF> sf(sub_formulas);
806 sub_formulas = sf[0].sub_formulas;
807 var = nullptr;
808 }
809 return;
810 }
811 break;
812 default:
813 break;
814 }
815}
816//---------------------------------------------------------------------------
817void FOF::convert_to_cnf_clauses(vector<Clause>& cs, vector<string>& _names, const string& _role) {
818 if (type == FOFType::Empty) {
819 cerr << "Don't do this with an Empty FOF!" << endl;
820 return;
821 }
822#ifdef DEBUGOUTPUT
823 cout << "Remove iff:" << endl;
824#endif
825 remove_iff();
826#ifdef DEBUGOUTPUT
827 cout << *this << endl;
828 cout << "Remove imp" << endl;
829#endif
830 remove_imp();
831#ifdef DEBUGOUTPUT
832 cout << *this << endl;
833 cout << "Push negs:" << endl;
834#endif
835 push_negs();
836 recs_p->add_fof_inference_record("fof_nnf,[status(thm)]",
837 this->to_tptp_string());
838
839#ifdef DEBUGOUTPUT
840 cout << *this << endl;
841 cout << "Make unique vars:" << endl;
842#endif
844 recs_p->add_fof_inference_record("variable_rename,[status(thm)]",
845 this->to_tptp_string());
846#ifdef DEBUGOUTPUT
847 cout << *this << endl;
848 cout << "Remove redundant quantifiers:" << endl;
849#endif
851#ifdef DEBUGOUTPUT
852 cout << *this << endl;
853 cout << "Miniscope:" << endl;
854#endif
855 if (params::miniscope) {
856 miniscope();
857 }
858 recs_p->add_fof_inference_record("miniscope,[status(thm)]",
859 this->to_tptp_string());
860#ifdef DEBUGOUTPUT
861 cout << *this << endl;
862 cout << "Skolemize:" << endl;
863#endif
864 skolemize();
865#ifdef DEBUGOUTPUT
866 cout << *this << endl;
867 cout << "Remove universal quantifiers:" << endl;
868#endif
870#ifdef DEBUGOUTPUT
871 cout << *this << endl;
872 cout << "Distribute or:" << endl;
873#endif
875#ifdef DEBUGOUTPUT
876 cout << *this << endl;
877 cout << "Convert to clauses:" << endl;
878#endif
880 for (const Clause& c : cs) {
881 string role = _role;
882 if (_role != string("negated_conjecture"))
883 role = "plain";
884 string name = recs_p->add_clause_record(c, role);
885 _names.push_back(name);
886 }
887#ifdef DEBUGOUTPUT
888 cout << *this << endl;
889#endif
890}
891//---------------------------------------------------------------------------
892void FOF::split_sub_formulas(vector<FOF>& left_sub, vector<FOF>& right_sub) {
893 left_sub.clear();
894 right_sub.clear();
895 size_t s = sub_formulas.size();
896 if (s == 2) {
897 left_sub.push_back(sub_formulas[0]);
898 right_sub.push_back(sub_formulas[1]);
899 return;
900 }
901 if (s == 3) {
902 right_sub.push_back(sub_formulas[2]);
903 left_sub = sub_formulas;
904 left_sub.pop_back();
905 return;
906 }
907 size_t left_size = s / 2;
908 for (size_t i = 0; i < left_size; i++) {
909 left_sub.push_back(sub_formulas[i]);
910 }
911 for (size_t i = left_size; i < s; i++) {
912 right_sub.push_back(sub_formulas[i]);
913 }
914}
915//---------------------------------------------------------------------------
916void FOF::find_definitional_tuple(FOF& f, vector<FOF>& d, vector<FOF>& d_preds, bool in_conjunction) {
917 f.clear();
918 d.clear();
919 // Literals are straightforward.
920 if (is_literal()) {
921 f = *this;
922 vector<FOF> new_d;
923 d = new_d;
924 return;
925 }
926 // You must have an And or an Or because we're in NNF.
927 // Let's split half and half, just for the sake of symmetry.
928 vector<FOF> left;
929 vector<FOF> right;
930 split_sub_formulas(left, right);
931 FOF l = left[0];
932 FOF r = right[0];
933 if (left.size() > 1) {
934 l = FOF(type, left, nullptr);
935 }
936 if (right.size() > 1) {
937 r = FOF(type, right, nullptr);
938 }
939 // Somewhere to store results.
940 FOF new_f_1(FOFType::Empty);
941 FOF new_f_2(FOFType::Empty);
942 vector<FOF> new_d_1;
943 vector<FOF> new_d_2;
944 // The tricky case is an Or inside an And.
945 if (in_conjunction && type == FOFType::Or) {
946 l.find_definitional_tuple(new_f_1, new_d_1, d_preds, false);
947 r.find_definitional_tuple(new_f_2, new_d_2, d_preds, false);
949 f = def;
950 d_preds.push_back(def);
951
952 def.simple_negate();
953 vector<FOF> args1;
954 args1.push_back(def);
955 args1.push_back(new_f_1);
956 d.push_back(FOF::make_and(args1));
957 vector<FOF> args2;
958 args2.push_back(def);
959 args2.push_back(new_f_2);
960 d.push_back(FOF::make_and(args2));
961 for (const FOF& g : new_d_1) {
962 d.push_back(g);
963 }
964 for (const FOF& g : new_d_2) {
965 d.push_back(g);
966 }
967 return;
968 }
969 // The final case is straightforward.
970 bool is_and(type == FOFType::And);
971 l.find_definitional_tuple(new_f_1, new_d_1, d_preds, is_and);
972 r.find_definitional_tuple(new_f_2, new_d_2, d_preds, is_and);
973 vector<FOF> new_args;
974 new_args.push_back(new_f_1);
975 new_args.push_back(new_f_2);
976 FOF new_f(type, new_args, nullptr);
977 f = new_f;
978 d = new_d_1;
979 for (const FOF& g : new_d_2){
980 d.push_back(g);
981 }
982}
983//---------------------------------------------------------------------------
984void FOF::definitional_convert_to_cnf_clauses(vector<Clause>& cs, vector<string>& _names, const string& _role) {
985 if (type == FOFType::Empty) {
986 cerr << "Don't do this with an Empty FOF!" << endl;
987 return;
988 }
989 /*
990 * Note that the description in the restricted backtracking paper produces a
991 * DNF and starts with a Skolemized NNF of the original formula, *not* its
992 * negation. As the difference between this and the current representation, for
993 * connection calculus is just that all the literals get negated, this could
994 * be done more efficiently, but for now I'm going to just do a direct
995 * implementation of the procedure described in the paper. So: negate
996 * first, produce a DNF, then negate again.
997 */
999
1000 recs_p->add_fof_inference_record("def_negate,[status(cth)]",
1001 this->to_tptp_string());
1002
1003 remove_iff();
1004 remove_imp();
1005 push_negs();
1006
1007 recs_p->add_fof_inference_record("fof_nnf,[status(thm)]",
1008 this->to_tptp_string());
1009
1011
1012 recs_p->add_fof_inference_record("variable_rename,[status(thm)]",
1013 this->to_tptp_string());
1014
1016 /*
1017 * As we're producing a DNF, we skolemize universals and then remove existentials.
1018 */
1021 /*
1022 * Now we do the definitional magic.
1023 */
1024 FOF f(FOFType::Empty);
1025 vector<FOF> d;
1026 vector<FOF> d_preds;
1027 find_definitional_tuple(f, d, d_preds, false);
1028 /*
1029 * f is a DNF so we can invert it and flatten it to
1030 * the required CNF.
1031 */
1033 /*
1034 * Each element of d now needs to be converted using
1035 * a standard conversion, then inverted and transformed
1036 * to CNF.
1037 */
1038 for (FOF& formula : d) {
1039 vector<Clause> new_cs;
1040 formula.distribute_and();
1041 formula.dnf_invert_and_convert_to_clauses(new_cs);
1042 for (const Clause& new_c : new_cs) {
1043 cs.push_back(new_c);
1044 }
1045 }
1046 /*
1047 * TPTP has no dnf() way of doing things. D'Oh! So I need a way of
1048 * making TPTP format output. Do the negation and make the clauses
1049 * for cnf. Then use their conjunction to output the new symbols
1050 * introduced but as CTP, which it is with respect to the herbrand step.
1051 * Then the individual clauses are THM.
1052 */
1053 /*
1054 * First make a cnf formula but in an fof format with quantifiers.
1055 */
1056 string tptp_fof_string("( ");
1057 int remaining = cs.size();
1058 for (const Clause& c : cs) {
1059 tptp_fof_string += c.to_tptp_fof_string();
1060 if (--remaining > 0) {
1061 tptp_fof_string += " & ";
1062 }
1063 }
1064 tptp_fof_string += " )";
1065 /*
1066 * Now you can construct the necessary TPTP format proof output. This
1067 * is where you also report any new symbols.
1068 */
1069 string role = _role;
1070 if (_role != string("negated_conjecture"))
1071 role = "plain";
1072
1073 string def_symbols;
1074 if (d_preds.size() > 0) {
1075 def_symbols += "[";
1076 commas::comma com(d_preds.size());
1077 for (const FOF& f : d_preds) {
1078 def_symbols += f.predicate_to_tptp_string();
1079 def_symbols += com();
1080 }
1081 def_symbols += "]";
1082 }
1083 recs_p->add_definitional_record(tptp_fof_string, def_symbols);
1084 /*
1085 * Now make what you actually need in cnf format.
1086 */
1087 for (const Clause& c : cs) {
1088 string name = recs_p->add_clause_record(c, role);
1089 _names.push_back(name);
1090 }
1091}
1092//---------------------------------------------------------------------------
1094 vector<Term*> skolem_arguments;
1095 skolemize_main(skolem_arguments, this, true);
1096}
1097//---------------------------------------------------------------------------
1099 vector<Term*> skolem_arguments;
1100 skolemize_universals_main(skolem_arguments, this, true);
1101}
1102//---------------------------------------------------------------------------
1104 FOF f(FOFType::Atom);
1105 switch (type) {
1106 case FOFType::Atom:
1107 break;
1108 case FOFType::Neg:
1109 sub_formulas[0].remove_universal_quantifiers();
1110 break;
1111 case FOFType::And:
1112 case FOFType::Or:
1113 case FOFType::Imp:
1114 case FOFType::Iff:
1115 for (FOF& g : sub_formulas)
1116 g.remove_universal_quantifiers();
1117 break;
1118 case FOFType::A:
1119 sub_formulas[0].remove_universal_quantifiers();
1120 f = sub_formulas[0];
1121 *this = f;
1122 break;
1123 case FOFType::E:
1124 sub_formulas[0].remove_universal_quantifiers();
1125 break;
1126 default:
1127 break;
1128 }
1129}
1130//---------------------------------------------------------------------------
1132 FOF f(FOFType::Atom);
1133 switch (type) {
1134 case FOFType::Atom:
1135 break;
1136 case FOFType::Neg:
1137 sub_formulas[0].remove_existential_quantifiers();
1138 break;
1139 case FOFType::And:
1140 case FOFType::Or:
1141 case FOFType::Imp:
1142 case FOFType::Iff:
1143 for (FOF& g : sub_formulas)
1144 g.remove_existential_quantifiers();
1145 break;
1146 case FOFType::E:
1147 sub_formulas[0].remove_existential_quantifiers();
1148 f = sub_formulas[0];
1149 *this = f;
1150 break;
1151 case FOFType::A:
1152 sub_formulas[0].remove_existential_quantifiers();
1153 break;
1154 default:
1155 break;
1156 }
1157}
1158//---------------------------------------------------------------------------
1159void FOF::to_Literal(Literal& new_lit) const {
1160 if (type == FOFType::Atom) {
1161 new_lit = pred;
1162 }
1163 else {
1164 new_lit = sub_formulas[0].pred;
1165 new_lit.make_negative();
1166 }
1167}
1168//---------------------------------------------------------------------------
1169void FOF::convert_to_clauses(vector<Clause>& cs) const {
1170 cs.clear();
1171 if (is_literal()) {
1172 Literal new_lit;
1173 to_Literal(new_lit);
1174 Clause new_c;
1175 new_c.add_lit(new_lit);
1176 cs.push_back(new_c);
1177 return;
1178 }
1179 if (type == FOFType::Or) {
1180 vector<Clause> c;
1181 Clause new_c;
1182 cs.push_back(new_c);
1183 for (size_t i = 0; i < sub_formulas.size(); i++) {
1184 sub_formulas[i].convert_to_clauses(c);
1185 for (size_t j = 0; j < c[0].size(); j++) {
1186 cs[0].add_lit((c[0])[j]);
1187 }
1188 }
1189 return;
1190 }
1191 if (type == FOFType::And) {
1192 vector<Clause> c;
1193 for (size_t i = 0; i < sub_formulas.size(); i++) {
1194 sub_formulas[i].convert_to_clauses(c);
1195 for (size_t j = 0; j < c.size();j++) {
1196 cs.push_back(c[j]);
1197 }
1198 }
1199 }
1200}
1201//---------------------------------------------------------------------------
1202void FOF::dnf_invert_and_convert_to_clauses(vector<Clause>& cs) const {
1203 cs.clear();
1204 if (is_literal()) {
1205 Literal new_lit;
1206 to_Literal(new_lit);
1207 // This is where the inversion happens.
1208 new_lit.invert();
1209 Clause new_c;
1210 new_c.add_lit(new_lit);
1211 cs.push_back(new_c);
1212 return;
1213 }
1214 // Anything under here is essentially ANDed literals.
1215 if (type == FOFType::And) {
1216 vector<Clause> c;
1217 Clause new_c;
1218 cs.push_back(new_c);
1219 for (size_t i = 0; i < sub_formulas.size(); i++) {
1220 sub_formulas[i].dnf_invert_and_convert_to_clauses(c);
1221 for (size_t j = 0; j < c[0].size(); j++) {
1222 cs[0].add_lit((c[0])[j]);
1223 }
1224 }
1225 return;
1226 }
1227 // Anything below here essentially converts to another DNF.
1228 if (type == FOFType::Or) {
1229 vector<Clause> c;
1230 for (size_t i = 0; i < sub_formulas.size(); i++) {
1231 sub_formulas[i].dnf_invert_and_convert_to_clauses(c);
1232 for (size_t j = 0; j < c.size();j++) {
1233 cs.push_back(c[j]);
1234 }
1235 }
1236 }
1237}
1238//---------------------------------------------------------------------------
1239size_t FOF::find_and() const {
1240 size_t s = sub_formulas.size();
1241 for (size_t i = 0; i < s; i++) {
1242 if (sub_formulas[i].type == FOFType::And) {
1243 return i;
1244 }
1245 }
1246 return s;
1247}
1248//---------------------------------------------------------------------------
1249size_t FOF::find_or() const {
1250 size_t s = sub_formulas.size();
1251 for (size_t i = 0; i < s; i++) {
1252 if (sub_formulas[i].type == FOFType::Or) {
1253 return i;
1254 }
1255 }
1256 return s;
1257}
1258//---------------------------------------------------------------------------
1260 while (distribute_or_once()) {};
1261}
1262//---------------------------------------------------------------------------
1264 while (distribute_and_once()) {};
1265}
1266//---------------------------------------------------------------------------
1267string FOF::to_string() const {
1268 string result;
1269 size_t s = sub_formulas.size();;
1270 size_t i = 1;
1271 switch (type) {
1272 case FOFType::Atom:
1273 result = pred.to_string();
1274 break;
1275 case FOFType::Neg:
1276 result = unicode_symbols::LogSym::neg;
1277 result += "( ";
1278 result += sub_formulas[0].to_string();
1279 result += " )";
1280 break;
1281 case FOFType::And:
1282 result = "( ";
1283 for (const FOF& g : sub_formulas) {
1284 result += g.to_string();
1285 if (i < s) {
1286 result += " ";
1287 result += unicode_symbols::LogSym::and_sym;
1288 result += " ";
1289 }
1290 i++;
1291 }
1292 result += " )";
1293 break;
1294 case FOFType::Or:
1295 result = "( ";
1296 for (const FOF& g : sub_formulas) {
1297 result += g.to_string();
1298 if (i < s) {
1299 result += " ";
1300 result += unicode_symbols::LogSym::or_sym;
1301 result += " ";
1302 }
1303 i++;
1304 }
1305 result += " )";
1306 break;
1307 case FOFType::Imp:
1308 result = "( ";
1309 result += sub_formulas[0].to_string();
1310 result += " ";
1311 result += unicode_symbols::LogSym::ifthen;
1312 result += " ";
1313 result += sub_formulas[1].to_string();
1314 result += " )";
1315 break;
1316 case FOFType::Iff:
1317 result = "( ";
1318 result += sub_formulas[0].to_string();
1319 result += " ";
1320 result += unicode_symbols::LogSym::iff;
1321 result += " ";
1322 result += sub_formulas[1].to_string();
1323 result += " )";
1324 break;
1325 case FOFType::A:
1326 result = unicode_symbols::LogSym::forall;
1327 result += var->to_string();
1328 result += " . [ ";
1329 result += sub_formulas[0].to_string();
1330 result += " ]";
1331 break;
1332 case FOFType::E:
1333 result = unicode_symbols::LogSym::exists;
1334 result += var->to_string();
1335 result += " . [ ";
1336 result += sub_formulas[0].to_string();
1337 result += " ]";
1338 break;
1339 default:
1340 break;
1341 }
1342 return result;
1343}
1344//---------------------------------------------------------------------------
1345string FOF::to_tptp_string(bool nesting) const {
1346 string result;
1347 size_t s = sub_formulas.size();;
1348 size_t i = 1;
1349 bool nested = false;
1350 switch (type) {
1351 case FOFType::Atom:
1352 result = pred.to_tptp_string();
1353 break;
1354 case FOFType::Neg:
1355 result = "~";
1356 result += "( ";
1357 result += sub_formulas[0].to_tptp_string();
1358 result += " )";
1359 break;
1360 case FOFType::And:
1361 result = "( ";
1362 for (const FOF& g : sub_formulas) {
1363 result += g.to_tptp_string();
1364 if (i < s) {
1365 result += " ";
1366 result += "&";
1367 result += " ";
1368 }
1369 i++;
1370 }
1371 result += " )";
1372 break;
1373 case FOFType::Or:
1374 result = "( ";
1375 for (const FOF& g : sub_formulas) {
1376 result += g.to_tptp_string();
1377 if (i < s) {
1378 result += " ";
1379 result += "|";
1380 result += " ";
1381 }
1382 i++;
1383 }
1384 result += " )";
1385 break;
1386 case FOFType::Imp:
1387 result = "( ";
1388 result += sub_formulas[0].to_tptp_string();
1389 result += " ";
1390 result += "=>";
1391 result += " ";
1392 result += sub_formulas[1].to_tptp_string();
1393 result += " )";
1394 break;
1395 case FOFType::Iff:
1396 result = "( ";
1397 result += sub_formulas[0].to_tptp_string();
1398 result += " ";
1399 result += "<=>";
1400 result += " ";
1401 result += sub_formulas[1].to_tptp_string();
1402 result += " )";
1403 break;
1404 case FOFType::A:
1405 if (nesting) {
1406 result += ",";
1407 }
1408 else {
1409 result = "! [ ";
1410 }
1411 result += var->to_prolog_string();
1412 nested = sub_formulas[0].type == FOFType::A;
1413 if (!nested) {
1414 result += " ] : ";
1415 }
1416 result += sub_formulas[0].to_tptp_string(nested);
1417 break;
1418 case FOFType::E:
1419 if (nesting) {
1420 result += ",";
1421 }
1422 else {
1423 result = "? [ ";
1424 }
1425 result += var->to_prolog_string();
1426 nested = sub_formulas[0].type == FOFType::E;
1427 if (!nested) {
1428 result += " ] : ";
1429 }
1430 result += sub_formulas[0].to_tptp_string(nested);
1431 break;
1432 default:
1433 break;
1434 }
1435 return result;
1436}
1437//---------------------------------------------------------------------------
1439 if (type != FOFType::Atom) {
1440 cerr << "You should only be doing this with an atom!" << endl;
1441 return string();
1442 }
1443 return pred.get_pred()->to_tptp_string();
1444
1445}
1446//---------------------------------------------------------------------------
1447SimplificationResult FOF::simplify_cnf(vector<Clause>& cnf,
1448 vector<string>& roles,
1449 vector<string>& names) {
1450 vector<Clause> new_cnf;
1451 vector<string> new_roles;
1452 vector<string> new_names;
1453 bool cnf_is_contradiction = false;
1454 size_t i = 0;
1455 for (Clause& c : cnf) {
1456 Clause c2 = c;
1457 SimplificationResult result = c.simplify();
1458 if (result == SimplificationResult::Tautology) {
1459 recs_p->add_tf_clause_record(names[i], roles[i], "$true");
1460 i++;
1461 continue;
1462 }
1463 if (result == SimplificationResult::Contradiction) {
1464 cnf_is_contradiction = true;
1465 recs_p->add_tf_clause_record(names[i], roles[i], "$false");
1466 i++;
1467 continue;
1468 }
1469 new_cnf.push_back(c);
1470 new_roles.push_back(roles[i]);
1471 if (c == c2) {
1472 new_names.push_back(names[i]);
1473 }
1474 else {
1475 string new_name = recs_p->add_clause_record(c, roles[i], names[i]);
1476 new_names.push_back(new_name);
1477 }
1478 i++;
1479 }
1480 cnf = new_cnf;
1481 roles = new_roles;
1482 names = new_names;
1483 if (cnf_is_contradiction)
1484 return SimplificationResult::Contradiction;
1485 if (cnf.size() == 0)
1486 return SimplificationResult::Tautology;
1487 return SimplificationResult::OK;
1488}
1489//---------------------------------------------------------------------------
1490SimplificationResult FOF::simplify_cnf(vector<Clause>& cnf) {
1491 vector<Clause> new_cnf;
1492 bool cnf_is_contradiction = false;
1493 for (Clause& c : cnf) {
1494 SimplificationResult result = c.simplify();
1495 if (result == SimplificationResult::Tautology)
1496 continue;
1497 if (result == SimplificationResult::Contradiction) {
1498 cnf_is_contradiction = true;
1499 continue;
1500 }
1501 new_cnf.push_back(c);
1502 }
1503 cnf = new_cnf;
1504 if (cnf_is_contradiction)
1505 return SimplificationResult::Contradiction;
1506 if (cnf.size() == 0)
1507 return SimplificationResult::Tautology;
1508 return SimplificationResult::OK;
1509}
1510//---------------------------------------------------------------------------
1511set<Term*> FOF::find_free_variables() const {
1512 set<Term*> result;
1513 set<Term*> free;
1514 Term* to_remove;
1515 switch (type) {
1516 case FOFType::Empty:
1517 cerr << "You shouldn't be doing this with an FOFType::Empty!" << endl;
1518 break;
1519 case FOFType::Atom:
1520 for (const Term* p : pred.get_args()) {
1521 free = p->all_variables();
1522 result.insert(free.begin(), free.end());
1523 }
1524 break;
1525 case FOFType::Neg:
1526 case FOFType::And:
1527 case FOFType::Or:
1528 case FOFType::Imp:
1529 case FOFType::Iff:
1530 for (const FOF& f : sub_formulas) {
1531 free = f.find_free_variables();
1532 result.insert(free.begin(), free.end());
1533 }
1534 break;
1535 case FOFType::A:
1536 case FOFType::E:
1537 result = sub_formulas[0].find_free_variables();
1538 to_remove = term_index->add_variable_term(var);
1539 result.erase(to_remove);
1540 break;
1541 default:
1542 break;
1543 }
1544 return result;
1545}
1546//---------------------------------------------------------------------------
1547ostream& operator<<(ostream& out, const FOF& f) {
1548 out << f.to_string();
1549 return out;
1550}
Representation of clauses.
Definition Clause.hpp:52
SimplificationResult simplify()
Simplify a clause by dealing with $true, $false, complementary literals, and duplicates.
Definition Clause.cpp:143
void add_lit(const Literal &)
Add a literal, making sure you don't duplicate.
Definition Clause.cpp:96
Representation of first order formulas.
Definition FOF.hpp:58
void skolemize()
Skolemize the given formula.
Definition FOF.cpp:1093
void remove_iff()
Replace <-> throughout using ->.
Definition FOF.cpp:474
static FOF make_or(const vector< FOF > &fs)
Directly make a disjunction.
Definition FOF.hpp:313
void miniscope_all()
Apply miniscoping to all subformulas.
Definition FOF.cpp:339
size_t find_or() const
Does the collection of subformulas contain an OR? If so, find it.
Definition FOF.cpp:1249
static VariableIndex * var_index
Access to the index: static because all FOFs should share it.
Definition FOF.hpp:85
void convert_to_nnf()
Convert to Negation Normal Form.
Definition FOF.cpp:638
void clear()
Make an FOFType::Empty.
Definition FOF.hpp:276
string to_tptp_string(bool=false) const
Convert a FOF into a nice-looking string in the TPTP format.
Definition FOF.cpp:1345
void dnf_invert_and_convert_to_clauses(vector< Clause > &) const
Assuming you have a DNF, invert it and convert it to a collection of CNF clauses.
Definition FOF.cpp:1202
set< Term * > find_free_variables() const
Find the free variables in the formula.
Definition FOF.cpp:1511
void remove_redundant_quantifiers()
Remove quantifiers if they don't bind anything in their scope.
Definition FOF.cpp:544
void miniscope_split(Variable *, vector< FOF > &, vector< FOF > &)
Helper for miniscope.
Definition FOF.cpp:323
void split_sub_formulas(vector< FOF > &, vector< FOF > &)
Split subformulas in half.
Definition FOF.cpp:892
void make_unique_bound_variables()
Replace all bound variables with unique new ones.
Definition FOF.cpp:519
static SimplificationResult simplify_cnf(vector< Clause > &)
Simplify the clauses in a CNF using the method in Clause.
Definition FOF.cpp:1490
void remove_universal_quantifiers()
Self-explanatory.
Definition FOF.cpp:1103
void skolemize_main(vector< Term * >, FOF *, bool=false)
Main helper function called by FOF::skolemize().
Definition FOF.cpp:225
Variable * var
Associate a Variable with a quantifier.
Definition FOF.hpp:80
bool distribute_or_once()
Find an OR that can be distributed and deal with it. Indicate if there isn't one.
Definition FOF.cpp:97
FOFType type
Used for all FOFs to denote what kind it it.
Definition FOF.hpp:67
static FOF make_and(const vector< FOF > &fs)
Directly make a conjunction.
Definition FOF.hpp:306
void miniscope()
Apply the rules for miniscoping.
Definition FOF.cpp:648
void push_negs()
Push all negations in.
Definition FOF.cpp:573
bool distribute_and_once()
Find an AND that can be distributed and deal with it. Indicate if there isn't one.
Definition FOF.cpp:150
bool has_free_variable(Variable *)
Does this formula contain the specified variable unbound?
Definition FOF.cpp:36
void skolemize_universals()
Skolemize the universal quantifiers in the given formula.
Definition FOF.cpp:1098
void replace_variable(Variable *, Variable *)
Self-explanatory.
Definition FOF.cpp:73
vector< FOF > sub_formulas
Most FOFs will have subformulas.
Definition FOF.hpp:76
void to_Literal(Literal &) const
Assuming the FOF is a literal, convert it to something of type Literal.
Definition FOF.cpp:1159
FOF make_definitional_predicate() const
When doing definitional clause conversion you need to be able to make unique new predicates....
Definition FOF.cpp:87
static FOF make_exists(const FOF &f, Variable *v)
Directly make an existentially quantified FOF.
Definition FOF.hpp:349
void definitional_convert_to_cnf_clauses(vector< Clause > &, vector< string > &, const string &)
Convert to Conjunctive Normal Form using a form of definitional conversion.
Definition FOF.cpp:984
static TermIndex * term_index
Access to the index: static because all FOFs should share it.
Definition FOF.hpp:95
void remove_negation()
Remove the leading negation from an arbitrary FOF, if it has one.
Definition FOF.cpp:424
static PredicateIndex * pred_index
Access to the index: static because all FOFs should share it.
Definition FOF.hpp:100
static FOF make_forall(const FOF &f, Variable *v)
Directly make a universally quantified FOF.
Definition FOF.hpp:340
void convert_to_clauses(vector< Clause > &) const
Assuming you have a CNF, convert it to a collection of Clauses.
Definition FOF.cpp:1169
void remove_imp()
Replace A->B throughout with neg A v B.
Definition FOF.cpp:501
size_t find_and() const
Does the collection of subformulas contain an AND? If so, find it.
Definition FOF.cpp:1239
static FunctionIndex * fun_index
Access to the index: static because all FOFs should share it.
Definition FOF.hpp:90
FOF()=delete
You don't want this constructor.
void distribute_and()
Distribute ANDs to the maximum extent possible.
Definition FOF.cpp:1263
Term * make_skolem_function(const vector< Term * > &)
Make a new Skolem function.
Definition FOF.cpp:205
void distribute_or()
Distribute ORs to the maximum extent possible.
Definition FOF.cpp:1259
static TPTPRecords * recs_p
Allow FOF to add TPTP outputs.
Definition FOF.hpp:63
void convert_to_cnf_clauses(vector< Clause > &, vector< string > &, const string &)
Convert to Conjunctive Normal Form.
Definition FOF.cpp:817
void find_definitional_tuple(FOF &, vector< FOF > &, vector< FOF > &, bool)
Heavy-lifting for conversion to definitional clause form.
Definition FOF.cpp:916
void simple_negate()
Negate an FOF without applying any simplifications.
Definition FOF.cpp:453
bool is_literal() const
Check if an FOF is a literal.
Definition FOF.cpp:402
void skolemize_universals_main(vector< Term * >, FOF *, bool=false)
The dual of skolemize_main.
Definition FOF.cpp:273
string to_string() const
Convert a FOF into a nice-looking string.
Definition FOF.cpp:1267
void negate()
Negate an FOF, applying obvious simplifications if it's already negated or an implication.
Definition FOF.cpp:431
string predicate_to_tptp_string() const
Assuming this is an Atom, return the predicate name as a string.
Definition FOF.cpp:1438
void remove_existential_quantifiers()
Self-explanatory.
Definition FOF.cpp:1131
void invert_literal()
Self-explanatory!
Definition FOF.cpp:462
bool is_clause() const
Check if something is a clause.
Definition FOF.cpp:407
Literal pred
FOFType::Atom can store one of these to represent a Literal.
Definition FOF.hpp:72
void replace_variable_with_term(Term *, Variable *)
Replace a Variable with a Term.
Definition FOF.cpp:211
Basic representation of functions.
Definition Function.hpp:54
string get_name() const
Most basic access function.
Definition Function.hpp:84
Mechanism for looking after functions.
Function * make_skolem_function(Arity)
Add a new Skolem function. Naming is automatic.
Basic representation of literals, bundling together (pointers to) a Predicate, a collection of argume...
Definition Literal.hpp:50
void replace_variable_with_term(Term *, Variable *, TermIndex *)
Replace one variable with a term throughout.
Definition Literal.cpp:298
const vector< Term * > & get_args() const
Basic get method.
Definition Literal.hpp:83
string to_string(bool=false) const
Full conversion of Literal to string.
Definition Literal.cpp:185
bool contains_variable(Variable *) const
Does this Literal contain the specified variable?
Definition Literal.cpp:131
void replace_variable(Variable *, Variable *, TermIndex *)
Replace one variable with another throughout.
Definition Literal.cpp:287
bool is_positive() const
Basic manipulation - entirely self-explanatory.
Definition Literal.hpp:91
string to_tptp_string(bool=false) const
Convert to a string in a format compatible with the TPTP.
Definition Literal.cpp:225
void invert()
Basic manipulation - entirely self-explanatory.
Definition Literal.hpp:107
void clear()
Basic manipulation - entirely self-explanatory.
Definition Literal.hpp:119
void make_negative()
Basic manipulation - entirely self-explanatory.
Definition Literal.hpp:103
Predicate * get_pred() const
Basic get method.
Definition Literal.hpp:71
Basic representation of predicates: here just names, ids and arities.
Definition Predicate.hpp:51
string to_tptp_string() const
At present returns only the name.
Definition Predicate.cpp:32
Management of Predicate objects.
Predicate * make_definitional_predicate(Arity arity)
Make a new, unique definitional predicate.
Class collecting a bunch of TPTPRecord items for later formatting.
General representation of terms.
Definition Term.hpp:62
Function * get_f() const
Self-explanatory access function.
Definition Term.hpp:90
string to_prolog_string(bool=false) const
Convert to a string that can be read by Prolog.
Definition Term.cpp:202
Look after terms, using hash consing to avoid storing copies of terms.
Definition TermIndex.hpp:54
Term * add_function_term(Function *, const vector< Term * > &)
Self-explanatory: add a Term containing a function to the index.
Definition TermIndex.cpp:56
Term * add_variable_term(Variable *)
Self-explanatory: add a Term containing a variable to the index.
Definition TermIndex.cpp:41
Basic representation of variables.
Definition Variable.hpp:58
string to_prolog_string(bool=false) const
Convert to a Prolog string.
Definition Term.cpp:346
string to_string(bool=false) const
Convert to a (coloured) string.
Definition Term.cpp:336
Storage of named variables, and management of new, anonymous and unique variables.
Variable * add_unique_var()
Add a unique variable when converting to CNF.
Simple function object for putting commas in lists.