/*
* Copyright (C) 2009-2016 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.interpolate;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Set;
import de.uni_freiburg.informatik.ultimate.logic.ApplicationTerm;
import de.uni_freiburg.informatik.ultimate.logic.FunctionSymbol;
import de.uni_freiburg.informatik.ultimate.logic.NonRecursive;
import de.uni_freiburg.informatik.ultimate.logic.Rational;
import de.uni_freiburg.informatik.ultimate.logic.SMTLIBException;
import de.uni_freiburg.informatik.ultimate.logic.Script;
import de.uni_freiburg.informatik.ultimate.logic.Script.LBool;
import de.uni_freiburg.informatik.ultimate.logic.Sort;
import de.uni_freiburg.informatik.ultimate.logic.Term;
import de.uni_freiburg.informatik.ultimate.logic.TermTransformer;
import de.uni_freiburg.informatik.ultimate.logic.TermVariable;
import de.uni_freiburg.informatik.ultimate.logic.Theory;
import de.uni_freiburg.informatik.ultimate.smtinterpol.Config;
import de.uni_freiburg.informatik.ultimate.smtinterpol.LogProxy;
import de.uni_freiburg.informatik.ultimate.smtinterpol.convert.Clausifier;
import de.uni_freiburg.informatik.ultimate.smtinterpol.convert.SMTAffineTerm;
import de.uni_freiburg.informatik.ultimate.smtinterpol.convert.SharedTerm;
import de.uni_freiburg.informatik.ultimate.smtinterpol.dpll.Clause;
import de.uni_freiburg.informatik.ultimate.smtinterpol.dpll.DPLLAtom;
import de.uni_freiburg.informatik.ultimate.smtinterpol.dpll.IAnnotation;
import de.uni_freiburg.informatik.ultimate.smtinterpol.dpll.Literal;
import de.uni_freiburg.informatik.ultimate.smtinterpol.proof.LeafNode;
import de.uni_freiburg.informatik.ultimate.smtinterpol.proof.ProofNode;
import de.uni_freiburg.informatik.ultimate.smtinterpol.proof.ResolutionNode;
import de.uni_freiburg.informatik.ultimate.smtinterpol.proof.ResolutionNode.Antecedent;
import de.uni_freiburg.informatik.ultimate.smtinterpol.proof.SourceAnnotation;
import de.uni_freiburg.informatik.ultimate.smtinterpol.smtlib2.SMTInterpol;
import de.uni_freiburg.informatik.ultimate.smtinterpol.theory.cclosure.CCAnnotation;
import de.uni_freiburg.informatik.ultimate.smtinterpol.theory.cclosure.CCEquality;
import de.uni_freiburg.informatik.ultimate.smtinterpol.theory.linar.BoundConstraint;
import de.uni_freiburg.informatik.ultimate.smtinterpol.theory.linar.InfinitNumber;
import de.uni_freiburg.informatik.ultimate.smtinterpol.theory.linar.LAAnnotation;
import de.uni_freiburg.informatik.ultimate.smtinterpol.theory.linar.LAEquality;
import de.uni_freiburg.informatik.ultimate.smtinterpol.theory.linar.LinVar;
import de.uni_freiburg.informatik.ultimate.smtinterpol.theory.linar.MutableAffinTerm;
/**
* This interpolator computes the interpolants of a refutation
* for the partitions specified by the user.
* It works in a non-recursive way
* on the proof tree generated during SMT solving.
*
* @author Jochen Hoenicke, Tanja Schindler
*
*/
public class Interpolator extends NonRecursive {
SMTInterpol mSmtSolver;
Script mCheckingSolver;
LogProxy mLogger;
Theory mTheory;
int mNumInterpolants;
/**
* Array encoding the tree-structure for tree interpolants.
* The interpolants are always required to be in post-order
* tree traversal.
* The i-th element of this array contains the lowest index
* occuring in the sub-tree with the i-th element as root node.
* This is the index of the lower left-most node in the sub-tree.
* The nodes between m_startOfSubtrees[i] and i form the sub-tree
* with the root i.
*
* To traverse the children of a node the following pattern can
* be used:
* <pre>
* for (int child = node-1; child >= m_startOfSubtrees[node];
* child = m_startOfSubtrees[child] - 1) {
* ...
* }
* </pre>
* To find the parent of a node do:
* <pre>
* int parent = node + 1;
* while (m_startOfSubtrees[parent] > node) parent++;
* </pre>
*/
int[] mStartOfSubtrees;
HashMap<SharedTerm, Occurrence> mSymbolPartition;
HashMap<DPLLAtom, LitInfo> mLiteralInfos;
HashMap<String, Integer> mPartitions;
HashMap<Clause, Interpolant[]> mInterpolants;
/**
* The interpolants which have already been computed.
* Used to store the interpolants preceding a resolution before combining them.
* In the end of the interpolation, it contains only the interpolants
* for the refutation, corresponding to the specified partitions.
*/
private final ArrayDeque<Interpolant[]> mInterpolated =
new ArrayDeque<Interpolant[]>();
/**
* This class goes through the nodes of the proof tree
* for the input clause.
* It checks if the interpolant for a clause already exists,
* and if not, it enqueues new walkers depending on the node type.
* @param clause the clause to interpolate
*/
public static class ProofTreeWalker implements Walker {
private final Clause mClause;
public ProofTreeWalker(Clause clause){
mClause = clause;
}
@Override
public void walk(NonRecursive engine){
final Interpolator proofTreeWalker =
((Interpolator) engine);
if(proofTreeWalker.checkCacheForInterpolants(mClause)) {
return;
}
if (!(mClause.getProof().isLeaf())) {
((Interpolator) engine).walkResolutionNode(mClause);
}
else{
((Interpolator) engine).walkLeafNode(mClause);
}
}
}
/**
* This class combines the interpolants preceding a resolution step
* and adds the interpolant of the resolvent to the Interpolated stack.
* @param the pivot of the resolution step
*/
public static class CombineInterpolants implements Walker {
private final Literal mPivot;
public CombineInterpolants(Literal pivot){
mPivot = pivot;
}
@Override
public void walk(NonRecursive engine){
((Interpolator) engine).combine(mPivot);
}
}
/**
* This class summarizes a hyper-resolution step
* by adding the interpolants to the cache, checking for inductivity,
* and providing debug messages.
*/
public static class SummarizeResolution implements Walker{
private final Clause mClause;
public SummarizeResolution(Clause clause){
mClause = clause;
}
@Override
public void walk(NonRecursive engine){
((Interpolator) engine).summarize(mClause);
}
}
public Interpolator(LogProxy logger, SMTInterpol smtSolver,
Script checkingSolver, Theory theory,
Set<String>[] partitions, int[] startOfSubTrees) {
mPartitions = new HashMap<String, Integer>();
for (int i = 0; i < partitions.length; i++) {
final Integer part = i;
for (final String name: partitions[i]) {
mPartitions.put(name, part);
}
}
mLogger = logger;
mSmtSolver = smtSolver;
mCheckingSolver = checkingSolver;
mTheory = theory;
mNumInterpolants = partitions.length - 1;
mStartOfSubtrees = startOfSubTrees;
mSymbolPartition = new HashMap<SharedTerm, Occurrence>();
mLiteralInfos = new HashMap<DPLLAtom, LitInfo>();
mInterpolants = new HashMap<Clause,Interpolant[]>();
}
public Term[] getInterpolants(Clause refutation) {
colorLiterals(refutation, new HashSet<Clause>());
final Interpolant[] eqitps = interpolate(refutation);
final Term[] itpTerms = new Term[eqitps.length];
for (int i = 0; i < eqitps.length; i++) {
itpTerms[i] = unfoldLAs(eqitps[i]);
}
return itpTerms;
}
public Interpolant[] interpolate(Clause clause) {
if (mInterpolants.containsKey(clause)){
mLogger.debug("Clause {0} has been interpolated before.", clause);
return mInterpolants.get(clause);
}
if (mSmtSolver.isTerminationRequested()) {
throw new SMTLIBException("Timeout exceeded");
}
Interpolant[] interpolants = null;
run(new ProofTreeWalker(clause));
// collect the final interpolants from the Interpolated stack
interpolants = collectInterpolated();
return interpolants;
}
/**
* Enqueue walkers for the single steps in a hyper-resolution step.
* @param clause the resolvent clause
*/
private void walkResolutionNode(Clause clause){
if (mSmtSolver.isTerminationRequested()) {
throw new SMTLIBException("Timeout exceeded");
}
// get primary and antecedents
final ResolutionNode resNode = (ResolutionNode) clause.getProof();
final Clause prim = resNode.getPrimary();
final Antecedent[] assump = resNode.getAntecedents();
final int antNumber = assump.length;
enqueueWalker(new SummarizeResolution(clause));
// enqueue walkers for primary and antecedents in reverse order
// alternating with Combine walkers
for(int i = antNumber-1; i>=0; i--){
enqueueWalker(new CombineInterpolants(assump[i].mPivot));
enqueueWalker(new ProofTreeWalker(assump[i].mAntecedent));
}
enqueueWalker(new ProofTreeWalker(prim));
}
/**
* Interpolate a proof tree leaf depending on its type.
* @param clause the clause to interpolate
*/
private void walkLeafNode(Clause clause){
if (mSmtSolver.isTerminationRequested()) {
throw new SMTLIBException("Timeout exceeded");
}
final LeafNode leaf = (LeafNode) clause.getProof();
Interpolant[] interpolants = new Interpolant[mNumInterpolants];
if (leaf.getLeafKind() == LeafNode.EQ) {
assert clause.getSize() == 2;
Literal l1 = clause.getLiteral(0);
Literal l2 = clause.getLiteral(1);
assert l1.getSign() != l2.getSign();
if (l1.getAtom() instanceof LAEquality) {
l1 = clause.getLiteral(1);
l2 = clause.getLiteral(0);
}
interpolants = computeEQInterpolant(
(CCEquality) l1.getAtom(), (LAEquality) l2.getAtom(),
l1.getSign());
} else if (leaf.hasSourceAnnotation()) {
final SourceAnnotation annot =
(SourceAnnotation) leaf.getTheoryAnnotation();
final int partition = mPartitions.containsKey(annot.getAnnotation())
? mPartitions.get(annot.getAnnotation()) : 0;
interpolants = new Interpolant[mNumInterpolants];
for (int i = 0; i < mNumInterpolants; i++) {
interpolants[i] = new Interpolant(
mStartOfSubtrees[i] <= partition && partition <= i
? mTheory.mFalse : mTheory.mTrue);
}
} else if (leaf.getLeafKind() == LeafNode.THEORY_CC) {
final CCInterpolator ipolator = new CCInterpolator(this);
final Term[] interpolantTerms = ipolator.computeInterpolants(
clause, (CCAnnotation) leaf.getTheoryAnnotation());
interpolants = new Interpolant[mNumInterpolants];
for (int j = 0; j < mNumInterpolants; j++) {
interpolants[j] = new Interpolant(interpolantTerms[j]);
}
} else if (leaf.getLeafKind() == LeafNode.THEORY_LA) {
final LAInterpolator ipolator =
new LAInterpolator(this,
(LAAnnotation) leaf.getTheoryAnnotation());
interpolants = ipolator.computeInterpolants();
} else {
throw new UnsupportedOperationException("Cannot interpolate " + leaf);
}
HashSet<Literal> lits = null;
if (Config.DEEP_CHECK_INTERPOLANTS && mCheckingSolver != null) {
lits = new HashSet<Literal>();
for (int i = 0; i < clause.getSize(); i++) {
lits.add(clause.getLiteral(i));
}
checkInductivity(lits, interpolants);
}
// add the interpolants to the stack and the cache
mInterpolated.add(interpolants);
mInterpolants.put(clause, interpolants);
mLogger.debug("Interpolating leaf {0} yields ...", clause);
for(int i = 0; i <= mNumInterpolants -1; i++){
mLogger.debug(interpolants[i]);
}
}
/**
* Combine the interpolants preceding a resolution step
* depending on the type of the pivot.
* @param pivot the pivot of the resolution step
*/
private void combine(Literal pivot){
final LitInfo pivInfo = mLiteralInfos.get(pivot.getAtom());
final Interpolant[] assInterp = collectInterpolated();
final Interpolant[] primInterp = collectInterpolated();
final Interpolant[] interp = new Interpolant[mNumInterpolants];
for (int i = 0; i < mNumInterpolants; i++) {
mLogger.debug("Pivot {2}{3} on interpolants {0} and {1} gives...",
primInterp[i], assInterp[i],
pivot.getSMTFormula(mTheory), pivInfo);
if (pivInfo.isALocal(i)) {
interp[i] = new Interpolant(mTheory.or(
primInterp[i].mTerm, assInterp[i].mTerm));
} else if (pivInfo.isBLocal(i)) {
interp[i] = new Interpolant(mTheory.and(
primInterp[i].mTerm, assInterp[i].mTerm));
} else if (pivInfo.isAB(i)) {
interp[i] = new Interpolant(
mTheory.ifthenelse(pivot.getSMTFormula(mTheory),
primInterp[i].mTerm, assInterp[i].mTerm));
} else {
if (pivot.getAtom() instanceof CCEquality
|| pivot.getAtom() instanceof LAEquality) {
Interpolant eqIpol, neqIpol;
if (pivot.getSign() > 0) {
eqIpol = assInterp[i];
neqIpol = primInterp[i];
} else {
eqIpol = primInterp[i];
neqIpol = assInterp[i];
}
interp[i] = mixedEqInterpolate(
eqIpol, neqIpol, pivInfo.mMixedVar);
} else if (pivot.getAtom() instanceof BoundConstraint) {
interp[i] = mixedPivotLA(assInterp[i], primInterp[i], pivInfo.mMixedVar);
} else {
throw new UnsupportedOperationException(
"Cannot handle mixed literal " + pivot);
}
}
mLogger.debug(interp[i]);
}
// add the interpolants to the Interpolated stack
mInterpolated.add(interp);
}
/**
* Summarize the results of a hyper-resolution step.
* @param clause the interpolated clause
*/
private void summarize(Clause clause){
Interpolant[] interpolants = null;
interpolants = mInterpolated.getLast();
HashSet<Literal> lits = null;
if (Config.DEEP_CHECK_INTERPOLANTS && mCheckingSolver != null) {
lits = new HashSet<Literal>();
for (int i = 0; i < clause.getSize(); i++) {
lits.add(clause.getLiteral(i));
}
checkInductivity(lits, interpolants);
}
mInterpolants.put(clause, interpolants);
mLogger.debug("...which is the resulting interpolant for clause {0} ", clause);
}
/**
* Get the last interpolant array from the Interpolated stack.
*/
protected final Interpolant[] collectInterpolated() {
return mInterpolated.removeLast();
}
/**
* Check if a clause has been interpolated before.
* If so, add the interpolant array to the Interpolated stack.
* @param clause the clause to interpolate
* @return true iff clause has been interpolated before
*/
public boolean checkCacheForInterpolants(Clause clause){
Interpolant[] interpolants = new Interpolant[mNumInterpolants];
if (mInterpolants.containsKey(clause)){
interpolants = mInterpolants.get(clause);
//add the interpolant to the interpolated stack
mInterpolated.add(interpolants);
return true;
}
return false;
}
class Occurrence {
BitSet mInA;
BitSet mInB;
public Occurrence() {
mInA = new BitSet(mNumInterpolants + 1);
mInB = new BitSet(mNumInterpolants + 1);
}
public Occurrence(BitSet inA, BitSet inB) {
mInA = inA;
mInB = inB;
}
public void occursIn(int partition) {
for (int i = 0; i <= mNumInterpolants; i++) {
if (i < partition || mStartOfSubtrees[i] > partition) {
mInB.set(i);
} else {
mInA.set(i);
}
}
}
public boolean isALocalInSomeChild(int partition) {
for (int i = partition - 1; i >= mStartOfSubtrees[partition]; ) {
if (mInA.get(i)) {
return true;
}
i = mStartOfSubtrees[i] - 1;
}
return false;
}
public boolean contains(int partition) {
if (!mInA.get(partition)) {
return false;
}
if (mInB.get(partition)) {
return true;
}
for (int i = partition - 1; i >= mStartOfSubtrees[partition]; ) {
if (!mInB.get(i)) {
return false;
}
i = mStartOfSubtrees[i] - 1;
}
return true;
}
public boolean isAorShared(int partition) {
return mInA.get(partition);
}
public boolean isBorShared(int partition) {
return mInB.get(partition);
}
public boolean isALocal(int partition) {
return mInA.get(partition) && !mInB.get(partition);
}
public boolean isBLocal(int partition) {
return mInB.get(partition) && !mInA.get(partition);
}
public boolean isAB(int partition) {
return mInA.get(partition) && mInB.get(partition);
}
public boolean isMixed(int partition) {
return !mInA.get(partition) && !mInB.get(partition);
}
@Override
public String toString() {
return "[" + mInA + "|" + mInB + "]";
}
/**
* Find the first A-local colored node. Every occurrence
* has a A-local chain from such a node to the root
* node and all other nodes are not A-local.
* @return the first A-local colored node.
*/
public int getALocalColor() {
int color = mInA.nextSetBit(0);
if (mInB.get(color)) {
color = mInB.nextClearBit(color);
}
return color;
}
}
class LitInfo extends Occurrence {
TermVariable mMixedVar;
/** Tells for an equality whether the A part is the Lhs or
* the Rhs.
*/
Occurrence mLhsOccur;
/**
* Gives for an inequality the A part.
*/
MutableAffinTerm[] mAPart;
public LitInfo() {
super();
}
public LitInfo(BitSet inA, BitSet inB) {
super(inA, inB);
}
public TermVariable getMixedVar() {
return mMixedVar;
}
public Occurrence getLhsOccur() {
return mLhsOccur;
}
public MutableAffinTerm getAPart(int p) {
return mAPart[p];
}
}
private Term unfoldLAs(Interpolant interpolant) {
final TermTransformer substitutor = new TermTransformer() {
@Override
public void convert(Term term) {
if (term instanceof LATerm) {
term = ((LATerm) term).mF;
}
super.convert(term);
}
};
return substitutor.transform(interpolant.mTerm);
}
private void checkInductivity(Collection<Literal> clause, Interpolant[] ipls) {
final int old = mLogger.getLoglevel();// NOPMD
mLogger.setLoglevel(LogProxy.LOGLEVEL_ERROR);
mCheckingSolver.push(1);
/* initialize auxMaps, which maps for each partition the auxiliary
* variables for mixed literals to a new fresh constant.
*/
@SuppressWarnings("unchecked") // because Java Generics are broken :(
final
HashMap<TermVariable, Term>[] auxMaps = new HashMap[ipls.length];
for (final Literal lit : clause) {
final LitInfo info = getLiteralInfo(lit.getAtom());
for (int part = 0; part < ipls.length; part++) {
if (info.isMixed(part)) {
final TermVariable tv = info.mMixedVar;
final String name = ".check" + part + "." + tv.getName();
mCheckingSolver.declareFun(name, new Sort[0], tv.getSort());
final Term term = mCheckingSolver.term(name);
if (auxMaps[part] == null) {
auxMaps[part] = new HashMap<TermVariable, Term>();
}
auxMaps[part].put(tv, term);
}
}
}
final Term[] interpolants = new Term[ipls.length];
for (int part = 0; part < ipls.length; part++) {
final Term ipl = unfoldLAs(ipls[part]);
if (auxMaps[part] == null) {
interpolants[part] = ipl;
} else {
final TermVariable[] tvs = new TermVariable[auxMaps[part].size()];
final Term[] values = new Term[auxMaps[part].size()];
int i = 0;
for (final Entry<TermVariable, Term> entry : auxMaps[part].entrySet()) {
tvs[i] = entry.getKey();
values[i] = entry.getValue();
i++;
}
interpolants[part] = mTheory.let(tvs, values, ipl);
}
}
for (int part = 0; part < ipls.length; part++) {
mCheckingSolver.push(1);
for (final Entry<String, Integer> entry: mPartitions.entrySet()) {
if (entry.getValue() == part) {
mCheckingSolver.assertTerm(mTheory.term(entry.getKey()));
}
}
for (Literal lit : clause) {
lit = lit.negate();
final LitInfo info = mLiteralInfos.get(lit.getAtom());
if (info.contains(part)) {
mCheckingSolver.assertTerm(lit.getSMTFormula(mTheory));
} else if (info.isBLocal(part)) {
// nothing to do, literal cannot be mixed in sub-tree.
} else if (info.isALocalInSomeChild(part)) {
// nothing to do, literal cannot be mixed in node
// or some direct children
} else if (lit.getAtom() instanceof CCEquality) {
// handle mixed (dis)equalities.
final CCEquality cceq = (CCEquality) lit.getAtom();
Term lhs = cceq.getLhs().toSMTTerm(mTheory);
Term rhs = cceq.getRhs().toSMTTerm(mTheory);
for (int child = part - 1; child >= mStartOfSubtrees[part];
child = mStartOfSubtrees[child] - 1) {
if (info.isMixed(child)) {
if (info.getLhsOccur().isALocal(child)) {
lhs = auxMaps[child].get(info.mMixedVar);
} else {
assert info.getLhsOccur().isBLocal(child);
rhs = auxMaps[child].get(info.mMixedVar);
}
}
}
if (info.isMixed(part)) {
if (info.getLhsOccur().isALocal(part)) {
rhs = auxMaps[part].get(info.mMixedVar);
} else {
assert info.getLhsOccur().isBLocal(part);
lhs = auxMaps[part].get(info.mMixedVar);
}
mCheckingSolver.assertTerm(mTheory.term("=", lhs, rhs));
} else {
mCheckingSolver.assertTerm(mTheory.term(lit.getSign() < 0 ? "distinct" : "=", lhs, rhs));
}
} else if (lit.negate() instanceof LAEquality) {
// handle mixed LA disequalities.
final InterpolatorAffineTerm at = new InterpolatorAffineTerm();
final LAEquality eq = (LAEquality) lit.negate();
for (int child = part - 1; child >= mStartOfSubtrees[part];
child = mStartOfSubtrees[child] - 1) {
if (info.isMixed(child)) {
// child and node are A-local.
at.add(Rational.MONE, info.getAPart(child));
at.add(Rational.ONE, auxMaps[child].get(info.mMixedVar));
}
}
if (info.isMixed(part)) {
assert (info.mMixedVar != null);
at.add(Rational.ONE, info.getAPart(part));
at.add(Rational.MONE, auxMaps[part].get(info.mMixedVar));
final Term t = at.toSMTLib(mTheory, eq.getVar().isInt());
final Term zero = eq.getVar().isInt()
? mTheory.numeral(BigInteger.ZERO)
: mTheory.decimal(BigDecimal.ZERO);
mCheckingSolver.assertTerm(mTheory.term("=", t, zero));
} else {
assert !at.isConstant();
at.add(Rational.ONE, eq.getVar());
at.add(eq.getBound().negate());
final Term t = at.toSMTLib(mTheory, eq.getVar().isInt());
final Term zero = eq.getVar().isInt()
? mTheory.numeral(BigInteger.ZERO)
: mTheory.decimal(BigDecimal.ZERO);
mCheckingSolver.assertTerm(mTheory.term("distinct", t, zero));
}
} else {
// handle mixed LA inequalities and equalities.
LinVar lv;
InfinitNumber bound;
if (lit.getAtom() instanceof BoundConstraint) {
final BoundConstraint bc = (BoundConstraint) lit.getAtom();
bound = lit.getSign() > 0 ? bc.getBound() : bc.getInverseBound();
lv = bc.getVar();
} else {
assert lit.getAtom() instanceof LAEquality;
final LAEquality eq = (LAEquality) lit;
lv = eq.getVar();
bound = new InfinitNumber(eq.getBound(), 0);
}
// check if literal is mixed in part or some child partiton.
final InterpolatorAffineTerm at = new InterpolatorAffineTerm();
for (int child = part - 1; child >= mStartOfSubtrees[part];
child = mStartOfSubtrees[child] - 1) {
if (info.isMixed(child)) {
// child and node are A-local.
at.add(Rational.MONE, info.getAPart(child));
at.add(Rational.ONE, auxMaps[child].get(info.mMixedVar));
}
}
if (info.isMixed(part)) {
assert (info.mMixedVar != null);
at.add(Rational.ONE, info.getAPart(part));
at.add(Rational.MONE, auxMaps[part].get(info.mMixedVar));
} else {
assert !at.isConstant();
at.add(Rational.ONE, lv);
at.add(bound.negate());
}
if (lit.getAtom() instanceof BoundConstraint) {
if (lit.getSign() < 0) {
at.negate();
}
mCheckingSolver.assertTerm(at.toLeq0(mTheory));
} else {
final boolean isInt = at.isInt();
final Term t = at.toSMTLib(mTheory, isInt);
final Term zero = isInt
? mTheory.numeral(BigInteger.ZERO)
: mTheory.decimal(BigDecimal.ZERO);
Term eqTerm = mTheory.term("=", t, zero);
if (!info.isMixed(part)
&& lit.getSign() < 0) {
eqTerm = mTheory.term("not", eqTerm);
}
mCheckingSolver.assertTerm(eqTerm);
}
}
}
for (int child = part - 1; child >= mStartOfSubtrees[part];
child = mStartOfSubtrees[child] - 1) {
mCheckingSolver.assertTerm(interpolants[child]);
}
mCheckingSolver.assertTerm(mTheory.term("not", interpolants[part]));
if (mCheckingSolver.checkSat() != LBool.UNSAT) {
throw new AssertionError();
}
mCheckingSolver.pop(1);
}
mCheckingSolver.pop(1);
mLogger.setLoglevel(old);
}
/**
* Compute the interpolant for a Nelson-Oppen equality clause. This is a
* theory lemma of the form equality implies equality, where one equality
* is congruence closure and one is linear arithmetic.
* @param ccEq the congruence closure equality atom
* @param laEq the linear arithmetic equality atom
* @param sign the sign of l1 in the conflict clause. This is -1 if
* l1 implies l2, and +1 if l2 implies l1.
*/
private Interpolant[] computeEQInterpolant(CCEquality ccEq, LAEquality laEq,
int sign) {
Interpolant[] interpolants = null;
final LitInfo ccInfo = getLiteralInfo(ccEq);
final LitInfo laInfo = getLiteralInfo(laEq);
interpolants = new Interpolant[mNumInterpolants];
for (int p = 0; p < mNumInterpolants; p++) {
Term interpolant;
if (ccInfo.isAorShared(p) && laInfo.isAorShared(p)) {
interpolant = mTheory.mFalse; // both literals in A.
} else if (ccInfo.isBorShared(p) && laInfo.isBorShared(p)) {
interpolant = mTheory.mTrue; // both literals in B.
} else {
final InterpolatorAffineTerm iat = new InterpolatorAffineTerm();
final Rational factor = ccEq.getLAFactor();
TermVariable mixed = null;
boolean negate = false;
// Get A part of ccEq:
if (ccInfo.isALocal(p)) {
iat.add(factor, ccEq.getLhs().getFlatTerm());
iat.add(factor.negate(), ccEq.getRhs().getSharedTerm());
if (sign == 1) {
negate = true;
}
} else if (ccInfo.isMixed(p)) {
// mixed;
if (sign == 1) {
mixed = ccInfo.getMixedVar();
}
if (ccInfo.mLhsOccur.isALocal(p)) {
iat.add(factor, ccEq.getLhs().getFlatTerm());
iat.add(factor.negate(), ccInfo.getMixedVar());
} else {
iat.add(factor, ccInfo.getMixedVar());
iat.add(factor.negate(), ccEq.getRhs().getFlatTerm());
}
} else {
// both sides in B, A part is empty
}
// Get A part of laEq:
if (laInfo.isALocal(p)) {
iat.add(Rational.MONE, laEq.getVar());
iat.add(laEq.getBound());
if (sign == -1) {
negate = true;
}
} else if (laInfo.isMixed(p)) {
if (sign == -1) {
mixed = laInfo.getMixedVar();
}
iat.add(Rational.MONE, laInfo.getAPart(p));
iat.add(Rational.ONE, laInfo.getMixedVar());
} else {
// both sides in B, A part is empty
}
iat.mul(iat.getGCD().inverse());
// Now solve it.
if (mixed != null) { // NOPMD
final Rational mixedFactor = iat.getSummands().remove(mixed);
assert mixedFactor.isIntegral();
final boolean isInt = mixed.getSort().getName().equals("Int");
if (isInt && mixedFactor.abs() != Rational.ONE) { // NOPMD
if (mixedFactor.signum() > 0) {
iat.negate();
}
final Term sharedTerm = iat.toSMTLib(mTheory, isInt);
interpolant =
mTheory.equals(mixed, mTheory.term(
"div", sharedTerm,
mTheory.numeral(mixedFactor.numerator())));
final FunctionSymbol divisible = mTheory.getFunctionWithResult(
"divisible",
new BigInteger[] {mixedFactor.numerator().abs()},
null, mTheory.getSort("Int"));
interpolant = mTheory.and(
interpolant, mTheory.term(divisible, sharedTerm));
} else {
iat.mul(mixedFactor.negate().inverse());
final Term sharedTerm = iat.toSMTLib(mTheory, isInt);
interpolant =
mTheory.equals(mixed, sharedTerm);
}
} else {
if (iat.isConstant()) {
if (iat.getConstant() != InfinitNumber.ZERO) {
negate ^= true;
}
interpolant = negate ? mTheory.mFalse : mTheory.mTrue;
} else {
final boolean isInt = iat.isInt();
final Term term = iat.toSMTLib(mTheory, isInt);
final Term zero = iat.isInt()
? mTheory.numeral(BigInteger.ZERO)
: mTheory.decimal(BigDecimal.ZERO);
interpolant = negate ? mTheory.distinct(term, zero)
: mTheory.equals(term, zero);
}
}
}
interpolants[p] = new Interpolant(interpolant);
}
return interpolants;
}
public void colorLiterals(Clause root, HashSet<Clause> visited) {
if (visited.contains(root)) {
return;
}
final ProofNode pn = root.getProof();
if (pn.isLeaf()) {
final LeafNode ln = (LeafNode) pn;
if (ln.hasSourceAnnotation()) {
final SourceAnnotation annot =
(SourceAnnotation) ln.getTheoryAnnotation();
final int partition = mPartitions.containsKey(annot.getAnnotation())
? mPartitions.get(annot.getAnnotation()) : 0;
for (int i = 0; i < root.getSize(); i++) {
final Literal lit = root.getLiteral(i);
final DPLLAtom atom = lit.getAtom();
LitInfo info = mLiteralInfos.get(atom);
if (info == null) {
info = new LitInfo();
mLiteralInfos.put(atom, info);
}
if (!info.contains(partition)) {
info.occursIn(partition);
if (atom instanceof CCEquality) {
final CCEquality eq = (CCEquality)atom;
addOccurrence(eq.getLhs().getFlatTerm(), partition);
addOccurrence(eq.getRhs().getFlatTerm(), partition);
} else if (atom instanceof BoundConstraint) {
final LinVar lv = ((BoundConstraint) atom).getVar();
addOccurrence(lv, partition);
} else if (atom instanceof LAEquality) {
final LinVar lv = ((LAEquality) atom).getVar();
addOccurrence(lv, partition);
}
}
}
}
} else {
final ResolutionNode rn = (ResolutionNode) pn;
colorLiterals(rn.getPrimary(), visited);
for (final Antecedent a : rn.getAntecedents()) {
colorLiterals(a.mAntecedent, visited);
}
}
visited.add(root);
}
Occurrence getOccurrence(SharedTerm shared) {
Occurrence result = mSymbolPartition.get(shared);
if (result == null) {
result = new Occurrence();
final IAnnotation annot = shared.getAnnotation();
// TODO Here we need to change something if we have quantifiers.
if (annot instanceof SourceAnnotation) {
final Integer partition = mPartitions.get(
((SourceAnnotation) annot).getAnnotation());
if (partition == null) {
for (int p = 0; p < mNumInterpolants;p++) {
result.occursIn(p);
}
} else {
result.occursIn(partition);
}
}
mSymbolPartition.put(shared, result);
}
return result;
}
void addOccurrence(SharedTerm term, int part) {
getOccurrence(term).occursIn(part);
if (term.getTerm() instanceof SMTAffineTerm
&& term.getLinVar() != null) {
addOccurrence(term.getLinVar(), part);
} else {
if (term.getTerm() instanceof ApplicationTerm) {
final ApplicationTerm at = (ApplicationTerm) term.getTerm();
if (!at.getFunction().isInterpreted()) {
final Clausifier c = term.getClausifier();
for (final Term p : at.getParameters()) {
addOccurrence(c.getSharedTerm(p), part);
}
}
}
}
}
void addOccurrence(LinVar var, int part) {
if (var.isInitiallyBasic()) {
for (final LinVar c : var.getLinTerm().keySet()) {
addOccurrence(c.getSharedTerm(), part);
}
} else {
addOccurrence(var.getSharedTerm(), part);
}
}
LitInfo getLiteralInfo(DPLLAtom lit) {
LitInfo result = mLiteralInfos.get(lit);
if (result == null) {
result = colorMixedLiteral(lit);
}
return result;
}
/**
* Compute the LitInfo for a mixed Literal.
*/
public LitInfo colorMixedLiteral(DPLLAtom atom) {
LitInfo info = mLiteralInfos.get(atom);
assert info == null;
final ArrayList<SharedTerm> subterms = new ArrayList<SharedTerm>();
/* The sort of the auxiliary variable created for this atom. We need
* this since we internally represent integral constants in LIRA logics
* as Int even if they should have sort Real.
*/
Sort auxSort;
if (atom instanceof CCEquality) {
final CCEquality eq = (CCEquality)atom;
final SharedTerm l = eq.getLhs().getFlatTerm();
final SharedTerm r = eq.getRhs().getFlatTerm();
subterms.add(l);
subterms.add(r);
if (l.getSort() == r.getSort()) {
auxSort = l.getSort();
} else {
assert mTheory.getLogic().isIRA();
// IRA-Hack
auxSort = mTheory.getRealSort();
}
} else {
LinVar lv = null;
if (atom instanceof BoundConstraint) {
lv = ((BoundConstraint) atom).getVar();
} else if (atom instanceof LAEquality) {
lv = ((LAEquality) atom).getVar();
}
Collection<LinVar> components;
if (lv.isInitiallyBasic()) {
components = lv.getLinTerm().keySet();
} else {
components = Collections.singleton(lv);
}
boolean allInt = true;
for (final LinVar c : components) {
// IRA-Hack
allInt &= c.isInt();
subterms.add(c.getSharedTerm());
}
auxSort = allInt ? mTheory.getNumericSort() : mTheory.getRealSort();
}
info = computeMixedOccurrence(subterms);
mLiteralInfos.put(atom, info);
final BitSet shared = new BitSet();
shared.or(info.mInA);
shared.or(info.mInB);
if (shared.nextClearBit(0) >= mNumInterpolants) {
return info;
}
info.mMixedVar = mTheory.createFreshTermVariable("litaux", auxSort);
if (atom instanceof CCEquality) {
final CCEquality eq = (CCEquality)atom;
info.mLhsOccur = getOccurrence(eq.getLhs().getFlatTerm());
} else if (atom instanceof BoundConstraint
|| atom instanceof LAEquality) {
LinVar lv = null;
if (atom instanceof BoundConstraint) {
lv = ((BoundConstraint) atom).getVar();
} else {
lv = ((LAEquality) atom).getVar();
}
assert lv.isInitiallyBasic() : "Not initially basic: " + lv + " atom: " + atom;
info.mAPart = new MutableAffinTerm[mNumInterpolants];
for (int part = 0; part < mNumInterpolants; part++) {
if (!info.isMixed(part)) {
continue;
}
final MutableAffinTerm sumApart = new MutableAffinTerm();
for (final Entry<LinVar, BigInteger> en : lv.getLinTerm().entrySet()) {
final LinVar var = en.getKey();
final Occurrence occ =
getOccurrence(en.getKey().getSharedTerm());
if (occ.isALocal(part)) {
final Rational coeff =
Rational.valueOf(en.getValue(), BigInteger.ONE);
sumApart.add(coeff, var);
}
}
info.mAPart[part] = sumApart;
}
}
return info;
}
private LitInfo computeMixedOccurrence(ArrayList<SharedTerm> subterms) {
LitInfo info;
BitSet inA = null, inB = null;
for (final SharedTerm st : subterms) {
final Occurrence occInfo = getOccurrence(st);
if (inA == null) {
inA = (BitSet) occInfo.mInA.clone();
inB = (BitSet) occInfo.mInB.clone();
} else {
inA.and(occInfo.mInA);
inB.and(occInfo.mInB);
}
}
info = new LitInfo(inA, inB);
return info;
}
/**
* This term transformer substitutes an auxiliary variable by an
* arbitrary term. This is used for the LA and UF resolution rule.
* For the UF resolution rule, it will replace the auxiliary variable
* by the term that must be equal to it due to an EQ(x,s) term in the
* other interpolant. For the LA resolution rule, this will replace
* the auxiliary variable by -s1/c1 - i in F1/F2 (see paper).
*
* The replacement term may contain other auxiliary variables
* that will be replaced later. It may only contain auxiliary variables
* for equalities with the negated equality in the clause or auxiliary
* variables for LA literals that are bound by a surrounding LATerm.
*
* @author hoenicke
*/
public static class Substitutor extends TermTransformer {
TermVariable mTermVar;
Term mReplacement;
public Substitutor(TermVariable termVar, Term replacement) {
mTermVar = termVar;
mReplacement = replacement;
}
@Override
public void convert(Term term) {
if (term instanceof LATerm) {
final LATerm laTerm = (LATerm) term;
final Term[] oldTerms = laTerm.mS.getSummands().keySet()
.toArray(new Term[laTerm.mS.getSummands().size()]);
/* recurse into LA term */
enqueueWalker(new Walker() {
@Override
public void walk(NonRecursive engine) {
final Substitutor me = (Substitutor) engine;
final Term result = me.getConverted();
final Term[] newTerms = me.getConverted(oldTerms);
if (result == laTerm.mF && newTerms == oldTerms) {
me.setResult(laTerm);
return;
}
final InterpolatorAffineTerm newS =
new InterpolatorAffineTerm();
for (int i = 0; i < oldTerms.length; i++) {
newS.add(laTerm.mS.getSummands().get(oldTerms[i]),
newTerms[i]);
}
newS.add(laTerm.mS.getConstant());
me.setResult(new LATerm(newS, laTerm.mK, result));
}
});
pushTerm(laTerm.mF);
pushTerms(oldTerms);
return;
} else if (term.equals(mTermVar)) {
setResult(mReplacement);
} else {
super.convert(term);
}
}
}
/**
* Substitute termVar by replacement in mainTerm. This will also work
* correctly with LATerms.
* @param mainTerm the term where the replacement is done.
* @param termVar the variable to replace.
* @param replacement the replacement term.
* @return the substituted term.
*/
Term substitute(Term mainTerm,
final TermVariable termVar, final Term replacement) {
return new Substitutor(termVar, replacement).transform(mainTerm);
}
class EQInterpolator extends TermTransformer {
Interpolant mI2;
TermVariable mAuxVar;
EQInterpolator(Interpolant i2, TermVariable auxVar) {
mI2 = i2;
mAuxVar = auxVar;
}
@Override
public void convert(Term term) {
assert term != mAuxVar;
if (term instanceof LATerm) {
final LATerm laTerm = (LATerm) term;
/* recurse into LA term */
enqueueWalker(new Walker() {
@Override
public void walk(NonRecursive engine) {
final EQInterpolator me = (EQInterpolator) engine;
final Term result = me.getConverted();
if (result == laTerm.mF) {
me.setResult(laTerm);
} else {
me.setResult(new LATerm(laTerm.mS, laTerm.mK, result));
}
}
});
pushTerm(laTerm.mF);
return;
} else if (term instanceof ApplicationTerm) {
final ApplicationTerm appTerm = (ApplicationTerm) term;
if (appTerm.getParameters().length == 2
&& (appTerm.getParameters()[0] == mAuxVar
|| appTerm.getParameters()[1] == mAuxVar)) {
assert appTerm.getFunction().isIntern()
&& appTerm.getFunction().getName().equals("=")
&& appTerm.getParameters().length == 2;
Term s = appTerm.getParameters()[1];
if (s == mAuxVar) {
s = appTerm.getParameters()[0];
}
setResult(substitute(mI2.mTerm, mAuxVar, s));
return;
}
}
super.convert(term);
}
}
/**
* Compute the interpolant for the resolution rule with a mixed equality
* as pivot. This is I1[I2(s_i)] for I1[x=s_i] and I2(x).
* @param eqIpol the interpolant I1[x=s_i].
* @param neqIpol the interpolant I2(x).
* @param mixedVar the auxiliary variable x.
* @return the resulting interpolant.
*/
private Interpolant mixedEqInterpolate(Interpolant eqIpol,
Interpolant neqIpol, TermVariable mixedVar) {
final TermTransformer ipolator = new EQInterpolator(neqIpol, mixedVar);
return new Interpolant(ipolator.transform(eqIpol.mTerm));
}
static abstract class MixedLAInterpolator extends TermTransformer {
TermVariable mMixedVar;
Term mI2;
LATerm mLA1;
public MixedLAInterpolator(Term i2, TermVariable mixed) {
mMixedVar = mixed;
mLA1 = null;
mI2 = i2;
}
abstract Term interpolate(LATerm la1, LATerm la2);
@Override
public void convert(Term term) {
assert term != mMixedVar;
if (term instanceof LATerm) {
final LATerm laTerm = (LATerm) term;
if (laTerm.mS.getSummands().get(mMixedVar) != null) { // NOPMD
if (mLA1 == null) {
/* We are inside I1. Remember the lainfo and push I2
* on the convert stack. Also enqueue a walker that
* will remove m_LA1 once we are finished with I2.
*/
beginScope();
mLA1 = laTerm;
enqueueWalker(new Walker() {
@Override
public void walk(NonRecursive engine) {
((MixedLAInterpolator) engine).mLA1 = null;
((MixedLAInterpolator) engine).endScope();
}
});
pushTerm(mI2);
return;
} else {
/* We are inside I2. Interpolate the LAInfos.
*/
setResult(interpolate(mLA1, (LATerm) term));
return;
}
} else {
/* this is a LA term not involving the mixed variable */
enqueueWalker(new Walker() {
@Override
public void walk(NonRecursive engine) {
final MixedLAInterpolator me = (MixedLAInterpolator) engine;
final Term result = me.getConverted();
if (result == laTerm.mF) {
me.setResult(laTerm);
} else {
me.setResult(
new LATerm(laTerm.mS, laTerm.mK, result));
}
}
});
pushTerm(laTerm.mF);
return;
}
} else {
super.convert(term);
}
}
}
class RealInterpolator extends MixedLAInterpolator {
public RealInterpolator(Term i2, TermVariable mixedVar) {
super(i2, mixedVar);
}
@Override
public Term interpolate(LATerm la1, LATerm la2) {
//retrieve c1,c2,s2,s2
final InterpolatorAffineTerm s1 = new InterpolatorAffineTerm(la1.mS);
final Rational c1 = s1.getSummands().remove(mMixedVar);
final InterpolatorAffineTerm s2 = new InterpolatorAffineTerm(la2.mS);
final Rational c2 = s2.getSummands().remove(mMixedVar);
assert (c1.signum() * c2.signum() == -1);
InfinitNumber newK = la1.mK.mul(c2.abs())
.add(la2.mK.mul(c1.abs()));
//compute c1s2 + c2s1
final InterpolatorAffineTerm c1s2c2s1 = new InterpolatorAffineTerm();
c1s2c2s1.add(c1.abs(), s2);
c1s2c2s1.add(c2.abs(), s1);
Term newF;
if (s1.getConstant().mEps > 0
|| s2.getConstant().mEps > 0) {
// One of the inequalities is strict. In this case
// c1s2c2s1 must also be a strict inequality and it is not
// possible that c1s2c2s1 == 0 holds. Hence, we do not need
// to substitute a shared term.
newF = c1s2c2s1.toLeq0(mTheory);
newK = InfinitNumber.EPSILON.negate();
} else if (la1.mK.less(InfinitNumber.ZERO)) {
//compute -s1/c1
final InterpolatorAffineTerm s1divc1 = new InterpolatorAffineTerm(s1);
s1divc1.mul(c1.inverse().negate());
final Term s1DivByc1 = s1divc1.toSMTLib(mTheory, false);
newF = substitute(la2.mF, mMixedVar, s1DivByc1);
newK = la2.mK;
} else if (la2.mK.less(InfinitNumber.ZERO)) {
//compute s2/c2
final InterpolatorAffineTerm s2divc2 = new InterpolatorAffineTerm(s2);
s2divc2.mul(c2.inverse().negate());
final Term s2DivByc2 = s2divc2.toSMTLib(mTheory, false);
newF = substitute(la1.mF, mMixedVar, s2DivByc2);
newK = la1.mK;
} else {
final InterpolatorAffineTerm s1divc1 = new InterpolatorAffineTerm(s1);
s1divc1.mul(c1.inverse().negate());
final Term s1DivByc1 = s1divc1.toSMTLib(mTheory, false);
final Term f1 = substitute(la1.mF, mMixedVar, s1DivByc1);
final Term f2 = substitute(la2.mF, mMixedVar, s1DivByc1);
newF = mTheory.and(f1, f2);
if (c1s2c2s1.isConstant()) {
if (c1s2c2s1.getConstant().less(InfinitNumber.ZERO)) {
newF = mTheory.mTrue;
}
} else {
final InterpolatorAffineTerm s3 =
new InterpolatorAffineTerm(c1s2c2s1);
s3.add(InfinitNumber.EPSILON);
newF = mTheory.or(s3.toLeq0(mTheory), newF);
}
newK = InfinitNumber.ZERO;
}
final LATerm la3 = new LATerm(c1s2c2s1, newK, newF);
return la3;
}
}
class IntegerInterpolator extends MixedLAInterpolator {
public IntegerInterpolator(Term i2, TermVariable mixedVar) {
super(i2, mixedVar);
}
@Override
public Term interpolate(LATerm la1, LATerm la2) {
//retrieve c1,c2,s1,s2
final InterpolatorAffineTerm s1 = new InterpolatorAffineTerm(la1.mS);
final Rational c1 = s1.getSummands().remove(mMixedVar);
final InterpolatorAffineTerm s2 = new InterpolatorAffineTerm(la2.mS);
final Rational c2 = s2.getSummands().remove(mMixedVar);
assert (c1.isIntegral() && c2.isIntegral());
assert (c1.signum() * c2.signum() == -1);
final Rational absc1 = c1.abs();
final Rational absc2 = c2.abs();
//compute c1s2 + c2s1
final InterpolatorAffineTerm c1s2c2s1 = new InterpolatorAffineTerm();
c1s2c2s1.add(absc1, s2);
c1s2c2s1.add(absc2, s1);
//compute newk = c2k1 + c1k2 + c1c2;
final Rational c1c2 = absc1.mul(absc2);
final InfinitNumber newK = la1.mK.mul(absc2).add(la2.mK.mul(absc1))
.add(new InfinitNumber(c1c2, 0));
assert newK.isIntegral();
final Rational k1c1 = la1.mK.mA.add(Rational.ONE).div(absc1).ceil();
final Rational k2c2 = la2.mK.mA.add(Rational.ONE).div(absc2).ceil();
Rational kc;
Rational theC;
InterpolatorAffineTerm theS;
if (k1c1.compareTo(k2c2) < 0) {
theC = c1;
theS = s1;
kc = k1c1;
} else {
theC = c2;
theS = s2;
kc = k2c2;
}
final BigInteger cNum = theC.numerator().abs();
Term newF = mTheory.mFalse;
// Use -s/c as start value.
InterpolatorAffineTerm sPlusOffset = new InterpolatorAffineTerm();
sPlusOffset.add(theC.signum() > 0 ? Rational.MONE : Rational.ONE, theS);
Rational offset = Rational.ZERO;
if (theC.signum() < 0) {
sPlusOffset.add(theC.abs().add(Rational.MONE));
}
while (offset.compareTo(kc) <= 0) {
Term x;
if (mSmtSolver.isTerminationRequested()) {
throw new SMTLIBException("Timeout exceeded");
}
x = sPlusOffset.toSMTLib(mTheory, true);
if (!cNum.equals(BigInteger.ONE)) {
x = mTheory.term("div", x, mTheory.numeral(cNum));
}
Term F1 = substitute(la1.mF, mMixedVar, x);
Term F2 = substitute(la2.mF, mMixedVar, x);
if (offset.compareTo(kc) == 0) {
if (theS == s1) {
F1 = mTheory.mTrue;
} else {
F2 = mTheory.mTrue;
}
}
newF = mTheory.or(newF, mTheory.and(F1, F2));
sPlusOffset = sPlusOffset.add(theC.negate());
offset = offset.add(c1c2);
}
final LATerm la3 = new LATerm(c1s2c2s1, newK, newF);
return la3;
}
}
/**
* Compute the interpolant for the resolution rule with a mixed inequality
* as pivot. This is I1[I2(LA3)] for I1[LA1] and I2[LA2].
* Note that we use only one auxiliary variable, which corresponds to
* x_1 and -x_2 in the paper.
* @param leqItp the interpolant I1[LA1].
* @param sgItp the interpolant I2[LA2].
* @param mixedVar the auxiliary variable x used in the la term.
* @return the resulting interpolant.
*/
public Interpolant mixedPivotLA(Interpolant leqItp,
Interpolant sgItp, TermVariable mixedVar) {
final MixedLAInterpolator ipolator;
if (mixedVar.getSort().getName().equals("Real")) {
ipolator = new RealInterpolator(sgItp.mTerm, mixedVar);
} else {
ipolator = new IntegerInterpolator(sgItp.mTerm, mixedVar);
}
final Interpolant newI = new Interpolant(ipolator.transform(leqItp.mTerm));
return newI;
}
}