/*
* Copyright (C) 2012-2013 University of Freiburg
*
* This file is part of SMTInterpol.
*
* SMTInterpol is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SMTInterpol is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SMTInterpol. If not, see <http://www.gnu.org/licenses/>.
*/
package de.uni_freiburg.informatik.ultimate.smtinterpol.proofcheck;
import java.util.HashMap;
import de.uni_freiburg.informatik.ultimate.logic.ApplicationTerm;
import de.uni_freiburg.informatik.ultimate.logic.Term;
import de.uni_freiburg.informatik.ultimate.logic.Theory;
/**
* This class is used to convert a split proof node (@split).
* A split brings canonical term forms (DAG) to CNF. There are two kinds of
* rules: The real splitting (of a conjunct from a conjunction) and
* transformations for Boolean equalities and if-then-else.
*
* @author Christian Schilling
*/
public class SplitConverter extends AConverter {
// map for the rules
private final HashMap<String, IRule> mAnnot2Rule;
/**
* @param appendable appendable to write the proof to
* @param theory the theory
* @param converter term converter
* @param simplifier computation simplifier
*/
public SplitConverter(final Appendable appendable, final Theory theory,
final TermConverter converter,
final ComputationSimplifier simplifier) {
super(appendable, theory, converter, simplifier);
// fill rule map
mAnnot2Rule = new HashMap<String, IRule>((int)(9 / 0.75) + 1);
fillMap();
}
// [start] rules //
/**
* This method fills the rule map with the rules.
* For each rule a conversion object is added to a hash map, which handles
* the conversion individually.
*
* Here the rules could be changed or new ones added if necessary.
*/
private void fillMap() {
// splitting a negated disjunct from a negated disjunction
mAnnot2Rule.put(":notOr",
new NotOrRule());
/*
* Boolean equality to disjunction with positive first and negative
* second term
*/
mAnnot2Rule.put(":=+1",
new SimpleRule("(rule split_eqP1)\n"));
/*
* Boolean equality to disjunction with negative first and positive
* second term
*/
mAnnot2Rule.put(":=+2",
new SimpleRule("(rule split_eqP2)\n"));
/*
* negated Boolean equality to disjunction with positive first and
* second term
*/
mAnnot2Rule.put(":=-1",
new SimpleRule("(rule split_eqM1)\n"));
/*
* negated Boolean equality to disjunction with negative first and
* second term
*/
mAnnot2Rule.put(":=-2",
new SimpleRule("(rule split_eqM2)\n"));
/*
* if-then-else to disjunction with negative condition and positive
* first case
*/
mAnnot2Rule.put(":ite+1",
new SimpleRule("(rule split_iteP1)\n"));
// if-then-else to disjunction with positive condition and second case
mAnnot2Rule.put(":ite+2",
new SimpleRule("(rule split_iteP2)\n"));
/*
* negative if-then-else to disjunction with negative condition and
* first case
*/
mAnnot2Rule.put(":ite-1",
new SimpleRule("(rule split_iteM1)\n"));
/*
* negative if-then-else to disjunction with positive condition and
* negative second case
*/
mAnnot2Rule.put(":ite-2",
new SimpleRule("(rule split_iteM2)\n"));
}
/**
* This interface is used for the rule translation.
*/
private interface IRule {
/**
* @param negDisjunction the (negated) disjunction
* @param result the (negated) disjunct that is split away
*/
void convert(final ApplicationTerm negDisjunction,
final ApplicationTerm result);
}
/**
* This class translates trivial rules that need no further investigation.
*/
private class SimpleRule implements IRule {
// Isabelle rule
private final String mRule;
/**
* @param rule the rule
*/
public SimpleRule(final String rule) {
mRule = rule;
}
/**
* The rule is simply written without any additional steps.
*
* {@inheritDoc}
*/
@Override
public void convert(final ApplicationTerm negDisjunction,
final ApplicationTerm result) {
writeString(mRule);
}
}
/**
* This class translates the :notOr rule.
*
* This is a split of a negated disjunct from a negated disjunction.
* Note that this is equivalent to splitting a conjunct from a
* conjunction. Disjunction is right-associative in Isabelle, so we
* only consider binary disjunctions.
*
* The proof goes by elimination tactics, that is, the rules are repeatedly
* applied until either none is available or the goal is closed. If the
* first (negated) disjunct is the target term, the proof is finished with
* a binary split rule. If not, the left-hand side of the disjunction is
* dropped and the search goes on recursively in the right-hand side.
*
* NOTE: If the target term is the rightmost (negated) disjunct,
* the proof rule finishes with the obligation '~P ==> ~P'.
* This is automatically solved by the 'by' command in Isabelle.
* But it can be the case that the rightmost disjunct is itself a
* disjunction. To prevent elimination there, another rule is
* necessary for this special case.
*
* More attention is payed towards the translation. Note that this is not
* necessary, but only for better performance.
* Alternatively, both the binary finishing rules could be added to the
* 'elim' arguments list.
*/
private class NotOrRule implements IRule {
@Override
public void convert(final ApplicationTerm negDisjunction,
final ApplicationTerm result) {
assert ((negDisjunction.getFunction() == mTheory.mNot)
&& (negDisjunction.getParameters().length == 1)
&& (negDisjunction.getParameters()[0]
instanceof ApplicationTerm));
final ApplicationTerm disjunction = (ApplicationTerm)
negDisjunction.getParameters()[0];
assert ((disjunction.getFunction() == mTheory.mOr)
&& (disjunction.getParameters().length > 1)
&& (result.getFunction() == mTheory.mNot)
&& (result.getParameters().length == 1));
final Term last = disjunction.getParameters()[disjunction.
getParameters().length - 1];
// the result is the rightmost disjunct
if (last == result.getParameters()[0]) {
writeString("(elim split_notOr_finR split_notOr_elim)\n");
} else {
// the result should be somewhere else
writeString("(elim split_notOr_finL split_notOr_elim)\n");
}
}
}
// [end] rules //
/**
* This method converts the split rule.
* The transformation rules only need one application of a lemma.
* Only the :notOr rule (real splitting, mostly occurs) needs more effort.
*
* @param negDisjunction the (negated) disjunction
* @param result the (negated) disjunct that is split away
* @param annotation the specific rule that is used
*/
public void convert(final ApplicationTerm negDisjunction,
final ApplicationTerm result, final String annotation) {
mConverter.convert(result);
writeString("\" by ");
assert (mAnnot2Rule.get(annotation) != null);
mAnnot2Rule.get(annotation).convert(negDisjunction, result);
}
}