/*
* 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 de.uni_freiburg.informatik.ultimate.logic.AnnotatedTerm;
import de.uni_freiburg.informatik.ultimate.logic.ApplicationTerm;
import de.uni_freiburg.informatik.ultimate.logic.FunctionSymbol;
import de.uni_freiburg.informatik.ultimate.logic.Sort;
import de.uni_freiburg.informatik.ultimate.logic.Term;
import de.uni_freiburg.informatik.ultimate.logic.Theory;
/**
* This class is used to convert a trichotomy lemma.
* That is, a number 'x' must be one of the following:
* '(= x 0), (< x 0), or (> x 0)'
*
* @author Christian Schilling
*/
public class LemmaTrichotomyConverter extends AConverter {
/**
* @param appendable appendable to write the proof to
* @param theory the theory
* @param converter term converter
* @param simplifier computation simplifier
*/
public LemmaTrichotomyConverter(final Appendable appendable,
final Theory theory, final TermConverter converter,
final ComputationSimplifier simplifier) {
super(appendable, theory, converter, simplifier);
}
/**
* This method converts a trichotomy lemma.
* The lemma is always a ternary disjunction, where one disjunct has the
* form '(= x 0)' (equality, 'e'), one disjunct has the form
* '(not (<= x 0))' (greater, 'g'), and one disjunct is the less ('l')
* disjunct. The order can vary.
*
* The 'l' disjunct depends on the sort of 'x'. For integer 'x', the form
* is '(<= y 0)', where 'y' is equivalent to 'x + 1'. For real 'x' the form
* is '(< x 0)'.
*
* The conversion first brings the disjunction to the normal form
* '(e | l | g)' (only internally). Since afterwards there can only occur
* resolution nodes, we can set our own order here.
* For real 'x' the lemma is then proven with a single rule.
* For integer 'x' the rule has an open obligation 'y = x + 1', which is
* finally proven by the simplifier.
*
* @param lemma the ternary disjunction
* @return the disjunction (possibly reordered)
*/
public ApplicationTerm convert(ApplicationTerm lemma) {
assert (lemma.getFunction() == mTheory.mOr);
final Term[] oldDisjunction = lemma.getParameters();
assert ((oldDisjunction.length == 3)
&& (unquote(oldDisjunction[0]) != null)
&& (unquote(oldDisjunction[1]) != null)
&& (unquote(oldDisjunction[2]) != null));
final FunctionSymbol first = unquote(oldDisjunction[0]).getFunction();
final FunctionSymbol second = unquote(oldDisjunction[1]).getFunction();
final Sort sort;
/* bring the disjuncts to the order 'e | l | g' */
if (first == mTheory.mNot) {
assert (second.getParameterSorts().length == 2);
sort = second.getParameterSorts()[0];
final Term[] newDisjunction = new Term[3];
newDisjunction[2] = oldDisjunction[0];
// 'gel'
if (second.getName() == "=") {
assert ((unquote(oldDisjunction[2]).getFunction().getName()
== "<=")
|| (unquote(oldDisjunction[2]).getFunction().getName()
== "<"));
newDisjunction[0] = oldDisjunction[1];
newDisjunction[1] = oldDisjunction[2];
} else {
// 'gle'
assert (((second.getName() == "<=")
|| (second.getName() == "<"))
&& (unquote(oldDisjunction[2]).getFunction().getName()
== "="));
newDisjunction[0] = oldDisjunction[2];
newDisjunction[1] = oldDisjunction[1];
}
lemma = mTheory.term(mTheory.mOr, newDisjunction);
} else {
assert (first.getParameterSorts().length == 2);
sort = first.getParameterSorts()[0];
if (first.getName() == "=") {
// 'egl'
if (second == mTheory.mNot) {
assert ((unquote(oldDisjunction[2]).getFunction().
getName() == "<=")
|| (unquote(oldDisjunction[2]).getFunction().
getName() == "<"));
final Term[] newDisjunction = new Term[3];
newDisjunction[0] = oldDisjunction[0];
newDisjunction[1] = oldDisjunction[2];
newDisjunction[2] = oldDisjunction[1];
lemma = mTheory.term(mTheory.mOr, newDisjunction);
} else {
// 'elg'
assert (((second.getName() == "<=")
|| (second.getName() == "<"))
&& (unquote(oldDisjunction[2]).getFunction()
== mTheory.mNot));
// nothing to do here
}
} else {
assert ((first.getName() == "<=")
|| (first.getName() == "<"));
final Term[] newDisjunction = new Term[3];
newDisjunction[1] = oldDisjunction[0];
// 'lge'
if (second == mTheory.mNot) {
assert (unquote(oldDisjunction[2]).getFunction().
getName() == "=");
newDisjunction[0] = oldDisjunction[2];
newDisjunction[2] = oldDisjunction[1];
} else {
// 'leg'
assert ((second.getName() == "=")
&& (unquote(oldDisjunction[2]).getFunction()
== mTheory.mNot));
newDisjunction[0] = oldDisjunction[1];
newDisjunction[2] = oldDisjunction[2];
}
lemma = mTheory.term(mTheory.mOr, newDisjunction);
}
}
// write rule
mConverter.convert(lemma);
// integer case
if (sort == mTheory.getNumericSort()) {
writeString("\" by (rule trichotomy_int, ");
writeString(mSimplifier.getRule());
writeString(")\n");
} else {
// real case
assert (sort == mTheory.getRealSort());
writeString("\" by (rule trichotomy_real)\n");
}
// result may have been modified, so return it
return lemma;
}
/**
* This method returns the ApplicationTerm from a disjunct.
* If the disjunct is negated, it will be returned unchanged and
* is unpacked from the :quoted literals otherwise.
*
* @param term the quoted term (must be an AnnotatedTerm)
* @return the inner term
*/
private ApplicationTerm unquote(Term term) {
if (term instanceof ApplicationTerm) {
assert (((ApplicationTerm)term).getFunction() == mTheory.mNot);
return (ApplicationTerm)term;
}
assert ((term instanceof AnnotatedTerm)
&& (((AnnotatedTerm)term).getAnnotations().length == 1)
&& (((AnnotatedTerm)term).getAnnotations()[0].getKey()
== ":quoted")
&& (((AnnotatedTerm)term).getSubterm() instanceof ApplicationTerm));
return (ApplicationTerm)((AnnotatedTerm)term).getSubterm();
}
}