#include "Lib/Environment.hpp"
#include "Kernel/Inference.hpp"
#include "Kernel/FormulaUnit.hpp"
#include "Kernel/Term.hpp"
#include "Shell/Options.hpp"
#include "NNF.hpp"
using namespace Kernel;
using namespace Shell;
FormulaUnit* NNF::ennf(FormulaUnit* unit)
{
ASS(! unit->isClause());
Formula* f = unit->formula();
Formula* g = ennf(f,true);
if (f == g) { return unit;
}
FormulaUnit* res = new FormulaUnit(g,FormulaClauseTransformation(InferenceRule::ENNF,unit));
if (env.options->showPreprocessing()) {
std::cout << "[PP] ennf in: " << unit->toString() << std::endl;
std::cout << "[PP] ennf out: " << res->toString() << std::endl;
}
return res;
}
FormulaUnit* NNF::nnf(FormulaUnit* unit)
{
ASS(! unit->isClause());
Formula* f = unit->formula();
Formula* g = nnf(f,true);
if (f == g) { return unit;
}
return new FormulaUnit(g,FormulaClauseTransformation(InferenceRule::NNF,unit));
}
Formula* NNF::ennf (Formula* f, bool polarity)
{
Connective c = f->connective();
switch (c) {
case LITERAL:
{
Literal* lit = f->literal();
Literal* newLit = ennf(lit);
newLit = polarity ? newLit : Literal::complementaryLiteral(newLit);
if (newLit == lit) {
return f;
} else {
return new AtomicFormula(newLit);
}
}
case AND:
case OR:
{
FormulaList* fs = f->args();
FormulaList* gs = ennf(fs,polarity);
if (fs == gs) {
return f;
}
if (polarity) {
return new JunctionFormula(c,gs);
}
return new JunctionFormula(c == AND ? OR : AND,gs);
}
case IMP:
{
Formula* l = ennf(f->left(),! polarity);
Formula* r = ennf(f->right(),polarity);
FormulaList* args = new FormulaList(l,new FormulaList(r));
return new JunctionFormula(polarity ? OR : AND,args);
}
case IFF:
case XOR:
{
Formula* l = f->left();
Formula* r = f->right();
Formula* ll = ennf(l,true);
Formula* rr = ennf(r,true);
if (polarity) {
if (l == ll && r == rr) { return f;
}
return new BinaryFormula(c, ll, rr);
}
return new BinaryFormula(c == XOR ? IFF : XOR, ll, rr);
}
case NOT:
return ennf(f->uarg(),!polarity);
case FORALL:
case EXISTS:
{
Formula* g = f->qarg();
Formula* gg = ennf(g,polarity);
if (g == gg) {
return f;
}
if (polarity) {
return new QuantifiedFormula(c,f->vars(),f->sorts(),gg);
}
return new QuantifiedFormula(c == EXISTS ? FORALL : EXISTS,
f->vars(),f->sorts(),gg);
}
case BOOL_TERM: {
TermList ts = f->getBooleanTerm();
TermList ennfTf = ennf(ts, polarity);
if (ts == ennfTf) {
if (polarity) {
return f;
} else {
return new NegatedFormula(f);
}
} else {
return new BoolTermFormula(ennfTf);
}
}
case TRUE:
case FALSE:
if(polarity) {
return f;
}
else {
if(c==TRUE) {
return Formula::falseFormula();
}
else {
return Formula::trueFormula();
}
}
default:
ASSERTION_VIOLATION;
}
}
Literal* NNF::ennf(Literal* l)
{
if (l->shared()) {
return l;
}
bool changed = false;
Stack<TermList> args;
Term::Iterator terms(l);
while (terms.hasNext()) {
TermList argument = terms.next();
TermList ennfArgument = ennf(argument, true);
if (argument != ennfArgument) {
changed = true;
}
args.push(ennfArgument);
}
if (!changed) {
return l;
}
return Literal::create(l, args.begin());
}
TermList NNF::ennf(TermList ts, bool polarity)
{
if (ts.isVar()) {
return ts;
}
Term* term = ts.term();
if (env.signature->isFoolConstantSymbol(true, term->functor())) {
return polarity ? ts : TermList(Term::foolFalse());
}
if (env.signature->isFoolConstantSymbol(false, term->functor())) {
return polarity ? ts : TermList(Term::foolTrue());
}
if (term->shared()) {
return ts;
}
if (term->isSpecial()) {
Term::SpecialTermData* sd = term->getSpecialData();
switch (sd->specialFunctor()) {
case SpecialFunctor::FORMULA: {
Formula* f = sd->getFormula();
Formula* ennfF = ennf(f, polarity);
switch (ennfF->connective()) {
case TRUE:
return TermList(Term::foolTrue());
case FALSE:
return TermList(Term::foolFalse());
default: {
if (f == ennfF) {
return ts;
} else {
return TermList(Term::createFormula(ennfF));
}
}
}
break;
}
case SpecialFunctor::ITE: {
TermList thenBranch = *term->nthArgument(0);
TermList elseBranch = *term->nthArgument(1);
Formula* condition = sd->getITECondition();
TermList ennfThenBranch = ennf(thenBranch, polarity);
TermList ennfElseBranch = ennf(elseBranch, polarity);
Formula* ennfCondition = ennf(condition, true);
if ((thenBranch == ennfThenBranch) &&
(elseBranch == ennfElseBranch) &&
(condition == ennfCondition)) {
return ts;
} else {
return TermList(Term::createITE(ennfCondition, ennfThenBranch, ennfElseBranch, sd->getSort()));
}
break;
}
case SpecialFunctor::LET: {
Formula* binding = sd->getLetBinding();
TermList body = *term->nthArgument(0);
Formula* ennfBinding = ennf(binding, true);
TermList ennfBody = ennf(body, polarity);
if ((binding == ennfBinding) && (body == ennfBody)) {
return ts;
} else {
return TermList(Term::createLet(ennfBinding, ennfBody, sd->getSort()));
}
break;
}
case SpecialFunctor::LAMBDA:
NOT_IMPLEMENTED;
case SpecialFunctor::MATCH: {
DArray<TermList> terms(term->arity());
bool unchanged = true;
for (unsigned i = 0; i < term->arity(); i++) {
terms[i] = ennf(*term->nthArgument(i), polarity);
unchanged = unchanged && (terms[i] == *term->nthArgument(i));
}
if (unchanged) {
return ts;
}
return TermList(Term::createMatch(sd->getSort(), sd->getMatchedSort(), term->arity(), terms.begin()));
}
}
ASSERTION_VIOLATION;
}
bool changed = false;
Stack<TermList> args;
Term::Iterator terms(term);
while (terms.hasNext()) {
TermList argument = terms.next();
TermList ennfArgument = ennf(argument, true);
if (argument != ennfArgument) {
changed = true;
}
args.push(ennfArgument);
}
if (!changed) {
return ts;
}
return TermList(Term::create(term, args.begin()));
}
FormulaList* NNF::ennf (FormulaList* fs, bool polarity)
{
if (FormulaList::isEmpty(fs)) {
return fs;
}
FormulaList::FIFO result;
bool changed = false;
FormulaList::Iterator it(fs);
while (it.hasNext()) {
Formula* f = it.next();
Formula* g = ennf(f,polarity);
result.pushBack(g);
if (f != g) {
changed = true;
}
}
if (changed) {
return result.list();
}
FormulaList::destroy(result.list());
return fs;
}
Formula* NNF::nnf (Formula* f, bool polarity)
{
Connective c = f->connective();
switch (c) {
case LITERAL:
if (! polarity) {
Literal* lit = f->literal();
Literal* newLit = Literal::complementaryLiteral(lit);
return new AtomicFormula(newLit);
}
return f;
case AND:
case OR:
{
FormulaList* fs = f->args();
FormulaList* gs = nnf(fs,polarity);
if (fs == gs) {
return f;
}
if (polarity) {
return new JunctionFormula(c,gs);
}
return new JunctionFormula(c == AND ? OR : AND,gs);
}
case IMP:
{
Formula* l = nnf(f->left(),! polarity);
Formula* r = nnf(f->right(),polarity);
FormulaList* args = new FormulaList(l,new FormulaList(r));
return new JunctionFormula(polarity ? OR : AND,args);
}
case IFF:
case XOR:
{
Formula* l = f->left();
Formula* r = f->right();
Formula* g;
if (polarity ? c == IFF : c == XOR) {
g = new JunctionFormula(AND,
new FormulaList(new BinaryFormula(IMP,l,r),
new FormulaList(new BinaryFormula(IMP,r,l))));
}
else {
g = new JunctionFormula(AND,
new FormulaList(new JunctionFormula(OR,
new FormulaList(l,
new FormulaList(r))),
new FormulaList(new JunctionFormula(OR,
new FormulaList(new NegatedFormula(l),
new FormulaList(new NegatedFormula(r)))))));
}
return nnf(g,true);
}
case NOT:
return nnf(f->uarg(),!polarity);
case FORALL:
case EXISTS:
{
Formula* g = f->qarg();
Formula* gg = nnf(g,polarity);
if (g == gg) {
ASS(polarity);
return f;
}
if (polarity) {
return new QuantifiedFormula(c,f->vars(),f->sorts(),gg);
}
return new QuantifiedFormula(c == EXISTS ? FORALL : EXISTS,
f->vars(),f->sorts(),gg);
}
case BOOL_TERM:
ASSERTION_VIOLATION;
case TRUE:
case FALSE:
return f;
case NAME:
case NOCONN:
ASSERTION_VIOLATION;
}
ASSERTION_VIOLATION;
}
FormulaList* NNF::nnf (FormulaList* fs, bool polarity)
{
if (FormulaList::isEmpty(fs)) {
return fs;
}
FormulaList::FIFO result;
bool changed = false;
FormulaList::Iterator it(fs);
while (it.hasNext()) {
Formula* f = it.next();
Formula* g = nnf(f,polarity);
result.pushBack(g);
if (f != g) {
changed = true;
}
}
if (changed) {
return result.list();
}
FormulaList::destroy(result.list());
return fs;
}