package bixie.prover.princess;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import org.joogie.cfgPlugin.CFGPlugin;
import org.joogie.cfgPlugin.Util.Dag;
import scala.collection.Iterator;
import scala.collection.JavaConversions;
import scala.collection.Seq;
import scala.collection.immutable.List;
import scala.collection.immutable.Set;
import scala.collection.mutable.ArrayBuffer;
import ap.SimpleAPI;
import ap.SimpleAPI.ProverStatus$;
import ap.basetypes.IdealInt$;
import ap.parser.ConstantSubstVisitor$;
import ap.parser.IAtom;
import ap.parser.IAtom$;
import ap.parser.IBinFormula;
import ap.parser.IBinJunctor;
import ap.parser.IBoolLit;
import ap.parser.IConstant;
import ap.parser.IConstant$;
import ap.parser.IExpression;
import ap.parser.IExpression$;
import ap.parser.IFormula;
import ap.parser.IFormulaITE;
import ap.parser.IFunApp;
import ap.parser.IIntLit;
import ap.parser.INot;
import ap.parser.IPlus;
import ap.parser.ITerm;
import ap.parser.ITermITE;
import ap.parser.IVariable;
import ap.parser.PredicateSubstVisitor$;
import ap.parser.SymbolCollector$;
import ap.terfor.ConstantTerm;
import ap.terfor.preds.Predicate;
import bixie.prover.Prover;
import bixie.prover.ProverExpr;
import bixie.prover.ProverFun;
import bixie.prover.ProverListener;
import bixie.prover.ProverResult;
import bixie.prover.ProverType;
public class PrincessProver implements Prover {
/*
public static ProverExpr[] explain(ProverExpr axioms, ProverExpr hypothesis) {
final Seq rawRes =
AbductorDillig$.MODULE$.apply(((FormulaExpr)axioms).formula,
((FormulaExpr)hypothesis).formula);
final ProverExpr[] res = new ProverExpr [rawRes.size()];
for (int i = 0; i < rawRes.size(); ++i)
res[i] = new FormulaExpr((IFormula)rawRes.apply(i));
return res;
}
public static ProverExpr[] explainSimply(ProverExpr axioms,
ProverExpr hypothesis,
ProverExpr[] symsToAvoid) {
final ArrayBuffer<ConstantTerm> constsToAvoid =
new ArrayBuffer<ConstantTerm>();
final ArrayBuffer<Predicate> predsToAvoid =
new ArrayBuffer<Predicate>();
for (int i = 0; i < symsToAvoid.length; ++i) {
if (symsToAvoid[i] instanceof TermExpr) {
ITerm t = ((TermExpr)symsToAvoid[i]).term;
constsToAvoid.$plus$eq(((IConstant)t).c());
}
if (symsToAvoid[i] instanceof FormulaExpr) {
IFormula f = ((FormulaExpr)symsToAvoid[i]).formula;
predsToAvoid.$plus$eq(((IAtom)f).pred());
}
}
final Seq rawRes =
AbductorDillig$.MODULE$.apply(((FormulaExpr)axioms).formula,
((FormulaExpr)hypothesis).formula,
constsToAvoid.toList(),
predsToAvoid.toList());
final ProverExpr[] res = new ProverExpr [rawRes.size()];
for (int i = 0; i < rawRes.size(); ++i)
res[i] = new FormulaExpr((IFormula)rawRes.apply(i));
return res;
}
*/
private SimpleAPI api;
public PrincessProver() {
ap.util.Debug.enableAllAssertions(false);
api = SimpleAPI.spawn();
// api = SimpleAPI.spawnWithScalaLog();
// api = SimpleAPI.spawnWithAssertions();
}
public PrincessProver(String basename) {
ap.util.Debug.enableAllAssertions(false);
api = SimpleAPI.spawnWithLog(basename);
}
public ProverType getBooleanType() {
return BoolType.INSTANCE;
}
public ProverType getIntType() {
return IntType.INSTANCE;
}
public ProverType getArrayType(ProverType[] argTypes, ProverType resType) {
return new ArrayType(argTypes.length);
}
public ProverExpr mkBoundVariable(int deBruijnIndex, ProverType type) {
if (type.equals(getBooleanType())) {
return mkEq(new TermExpr(new IVariable(deBruijnIndex), getIntType()),
mkLiteral(0));
} else {
return new TermExpr(new IVariable(deBruijnIndex), type);
}
}
public ProverExpr mkVariable(String name, ProverType type) {
if (type.equals(getIntType())) {
return new TermExpr(api.createConstant(name), type);
}
if (type.equals(getBooleanType())) {
return new FormulaExpr(api.createBooleanVariable(name));
}
// array types
return new TermExpr(api.createConstant(name), type);
// throw new RuntimeException();
}
public ProverFun mkUnintFunction(String name, ProverType[] argTypes,
ProverType resType) {
return new PrincessFun(api.createFunction(name, argTypes.length),
resType);
}
/**
* Define a new interpreted function. The body is supposed to contain bound
* variables with indexes <code>0, 1, ..., (n-1)</code> representing the
* arguments of the function.
*/
public ProverFun mkDefinedFunction(String name, ProverType[] argTypes,
final ProverExpr body) {
return new ProverFun() {
public ProverExpr mkExpr(ProverExpr[] args) {
final ArrayBuffer<ITerm> argsBuf = new ArrayBuffer<ITerm>();
for (int i = 0; i < args.length; ++i) {
ITerm termArg;
if (args[i].getType() == BoolType.INSTANCE)
termArg = new ITermITE(((FormulaExpr) args[i]).formula,
new IIntLit(IdealInt$.MODULE$.apply(0)),
new IIntLit(IdealInt$.MODULE$.apply(1)));
else
termArg = ((TermExpr) args[i]).term;
argsBuf.$plus$eq(termArg);
}
final List<ITerm> argsList = argsBuf.toList();
if (body instanceof TermExpr)
return new TermExpr(IExpression$.MODULE$.subst(
((TermExpr) body).term, argsList, 0),
body.getType());
else
return new FormulaExpr(IExpression$.MODULE$.subst(
((FormulaExpr) body).formula, argsList, 0));
}
};
}
public ProverExpr mkAll(ProverExpr body, ProverType type) {
return new FormulaExpr(
IExpression$.MODULE$.all(((FormulaExpr) body).formula));
}
public ProverExpr mkEx(ProverExpr body, ProverType type) {
return new FormulaExpr(
IExpression$.MODULE$.ex(((FormulaExpr) body).formula));
}
public ProverExpr mkTrigger(ProverExpr body, ProverExpr[] triggers) {
final ArrayBuffer<IExpression> triggerExprs = new ArrayBuffer<IExpression> ();
for (int i = 0; i < triggers.length; ++i) {
if (triggers[i] instanceof TermExpr)
triggerExprs.$plus$eq(((TermExpr)triggers[i]).term);
else
triggerExprs.$plus$eq(((FormulaExpr)triggers[i]).formula);
}
return new FormulaExpr(IExpression.trig(((FormulaExpr)body).formula,
triggerExprs));
}
public ProverExpr mkEq(ProverExpr left, ProverExpr right) {
if (left instanceof TermExpr)
return new FormulaExpr(
((TermExpr) left).term.$eq$eq$eq(((TermExpr) right).term));
else
return new FormulaExpr(
((FormulaExpr) left).formula
.$less$eq$greater(((FormulaExpr) right).formula));
}
public ProverExpr mkLiteral(boolean value) {
return new FormulaExpr(new IBoolLit(value));
}
public ProverExpr mkNot(ProverExpr body) {
return new FormulaExpr(new INot(((FormulaExpr) body).formula));
}
public ProverExpr mkAnd(ProverExpr left, ProverExpr right) {
return new FormulaExpr(new IBinFormula(IBinJunctor.And(),
((FormulaExpr) left).formula, ((FormulaExpr) right).formula));
}
public ProverExpr mkAnd(ProverExpr[] args) {
final ArrayBuffer<IFormula> argsBuf = new ArrayBuffer<IFormula>();
for (int i = 0; i < args.length; ++i)
argsBuf.$plus$eq(((FormulaExpr) args[i]).formula);
return new FormulaExpr(IExpression$.MODULE$.and(argsBuf));
}
public ProverExpr mkOr(ProverExpr left, ProverExpr right) {
return new FormulaExpr(new IBinFormula(IBinJunctor.Or(),
((FormulaExpr) left).formula, ((FormulaExpr) right).formula));
}
public ProverExpr mkOr(ProverExpr[] args) {
final ArrayBuffer<IFormula> argsBuf = new ArrayBuffer<IFormula>();
for (int i = 0; i < args.length; ++i)
argsBuf.$plus$eq(((FormulaExpr) args[i]).formula);
return new FormulaExpr(IExpression$.MODULE$.or(argsBuf));
}
public ProverExpr mkImplies(ProverExpr left, ProverExpr right) {
return mkOr(mkNot(left), right);
}
public ProverExpr mkIte(ProverExpr cond, ProverExpr thenExpr,
ProverExpr elseExpr) {
if (thenExpr instanceof TermExpr)
return new TermExpr(new ITermITE(((FormulaExpr) cond).formula,
((TermExpr) thenExpr).term, ((TermExpr) elseExpr).term),
thenExpr.getType());
else
return new FormulaExpr(new IFormulaITE(
((FormulaExpr) cond).formula,
((FormulaExpr) thenExpr).formula,
((FormulaExpr) elseExpr).formula));
}
public ProverExpr mkLiteral(int value) {
return new TermExpr(new IIntLit(IdealInt$.MODULE$.apply(value)),
getIntType());
}
public ProverExpr mkLiteral(BigInteger value) {
return new TermExpr(new IIntLit(IdealInt$.MODULE$.apply(value
.toString())), getIntType());
}
public ProverExpr mkPlus(ProverExpr left, ProverExpr right) {
return new TermExpr(new IPlus(((TermExpr) left).term,
((TermExpr) right).term), getIntType());
}
public ProverExpr mkPlus(ProverExpr[] args) {
final ArrayBuffer<ITerm> argsBuf = new ArrayBuffer<ITerm>();
for (int i = 0; i < args.length; ++i)
argsBuf.$plus$eq(((TermExpr) args[i]).term);
return new TermExpr(IExpression$.MODULE$.sum(argsBuf), getIntType());
}
public ProverExpr mkMinus(ProverExpr left, ProverExpr right) {
return new TermExpr(new IPlus(((TermExpr) left).term,
((TermExpr) right).term.unary_$minus()), getIntType());
}
public ProverExpr mkNeg(ProverExpr arg) {
return new TermExpr(((TermExpr) arg).term.unary_$minus(), getIntType());
}
public ProverExpr mkMult(ProverExpr left, ProverExpr right) {
return new TermExpr(api.mult(((TermExpr) left).term,
((TermExpr) right).term),
getIntType());
}
public ProverExpr mkEDiv(ProverExpr num, ProverExpr denom) {
return new TermExpr(api.mulTheory().eDiv(((TermExpr) num).term,
((TermExpr) denom).term),
getIntType());
}
public ProverExpr mkEMod(ProverExpr num, ProverExpr denom) {
return new TermExpr(api.mulTheory().eMod(((TermExpr) num).term,
((TermExpr) denom).term),
getIntType());
}
public ProverExpr mkTDiv(ProverExpr num, ProverExpr denom) {
return new TermExpr(api.mulTheory().tDiv(((TermExpr) num).term,
((TermExpr) denom).term),
getIntType());
}
public ProverExpr mkTMod(ProverExpr num, ProverExpr denom) {
return new TermExpr(api.mulTheory().tMod(((TermExpr) num).term,
((TermExpr) denom).term),
getIntType());
}
public ProverExpr mkGeq(ProverExpr left, ProverExpr right) {
return new FormulaExpr(
((TermExpr) left).term.$greater$eq(((TermExpr) right).term));
}
public ProverExpr mkGt(ProverExpr left, ProverExpr right) {
return new FormulaExpr(
((TermExpr) left).term.$greater(((TermExpr) right).term));
}
public ProverExpr mkLeq(ProverExpr left, ProverExpr right) {
return new FormulaExpr(
((TermExpr) left).term.$less$eq(((TermExpr) right).term));
}
public ProverExpr mkLt(ProverExpr left, ProverExpr right) {
return new FormulaExpr(
((TermExpr) left).term.$less(((TermExpr) right).term));
}
public ProverExpr mkSelect(ProverExpr ar, ProverExpr[] indexes) {
final ArrayBuffer<ITerm> args = new ArrayBuffer<ITerm>();
args.$plus$eq(((TermExpr) ar).term);
for (int i = 0; i < indexes.length; ++i)
args.$plus$eq(((TermExpr) indexes[i]).term);
return new TermExpr(new IFunApp(api.selectFun(indexes.length),
args.toSeq()), getIntType());
}
public ProverExpr mkStore(ProverExpr ar, ProverExpr[] indexes,
ProverExpr value) {
final ArrayBuffer<ITerm> args = new ArrayBuffer<ITerm>();
args.$plus$eq(((TermExpr) ar).term);
for (int i = 0; i < indexes.length; ++i)
args.$plus$eq(((TermExpr) indexes[i]).term);
args.$plus$eq(((TermExpr) value).term);
return new TermExpr(new IFunApp(api.storeFun(indexes.length),
args.toSeq()), getIntType());
}
// ////////////////////////////////////////////////////////////////////////////
public void push() {
api.push();
}
public void pop() {
api.pop();
}
public void addAssertion(ProverExpr assertion) {
api.addAssertion(((FormulaExpr) assertion).formula);
}
// ////////////////////////////////////////////////////////////////////////////
public ProverResult checkSat(boolean block) {
return translateRes(api.checkSat(block));
}
private ProverResult translateRes(scala.Enumeration.Value result) {
if (result == ProverStatus$.MODULE$.Sat()
|| result == ProverStatus$.MODULE$.Invalid())
return ProverResult.Sat;
else if (result == ProverStatus$.MODULE$.Unsat()
|| result == ProverStatus$.MODULE$.Valid())
return ProverResult.Unsat;
else if (result == ProverStatus$.MODULE$.Unknown())
return ProverResult.Unknown;
else if (result == ProverStatus$.MODULE$.Running())
return ProverResult.Running;
else
return ProverResult.Error;
}
public ProverResult getResult(boolean block) {
return translateRes(api.getStatus(block));
}
public ProverResult getResult(long timeout) {
return translateRes(api.getStatus(timeout));
}
public ProverResult nextModel(boolean block) {
return translateRes(api.nextModel(block));
}
public ProverResult stop() {
return translateRes(api.stop());
}
public void setConstructProofs(boolean b) {
api.setConstructProofs(b);
}
public void setPartitionNumber(int num) {
api.setPartitionNumber(num);
}
public ProverExpr[] interpolate(int[][] partitionSeq) {
final ArrayBuffer<Set<Object>> args = new ArrayBuffer<Set<Object>>();
for (int i = 0; i < partitionSeq.length; ++i) {
final ArrayBuffer<Object> indexes = new ArrayBuffer<Object>();
for (int j = 0; j < partitionSeq[i].length; ++j)
indexes.$plus$eq(Integer.valueOf(partitionSeq[i][j]));
args.$plus$eq(indexes.toSet());
}
final Seq<IFormula> ints = api.getInterpolants(args.toSeq(),1000000);
final ProverExpr[] res = new ProverExpr[partitionSeq.length - 1];
for (int i = 0; i < partitionSeq.length - 1; ++i)
res[i] = new FormulaExpr(ints.apply(i));
return res;
}
public void addListener(ProverListener listener) {
throw new RuntimeException();
}
public ProverExpr evaluate(ProverExpr expr) {
if (expr instanceof TermExpr)
return new TermExpr(new IIntLit(api.eval(((TermExpr) expr).term)),
((TermExpr) expr).getType());
else
return new FormulaExpr(new IBoolLit(
api.eval(((FormulaExpr) expr).formula)));
}
public ProverExpr[] freeVariables(ProverExpr expr) {
final ArrayList<ProverExpr> res = new ArrayList<ProverExpr> ();
final scala.Tuple3<scala.collection.Set<IVariable>,
scala.collection.Set<ConstantTerm>,
scala.collection.Set<Predicate>> symTriple;
if (expr instanceof TermExpr)
symTriple = SymbolCollector$.MODULE$.varsConstsPreds(((TermExpr)expr).term);
else
symTriple = SymbolCollector$.MODULE$.varsConstsPreds(((FormulaExpr)expr).formula);
final Iterator<IVariable> it1 = symTriple._1().iterator();
while (it1.hasNext())
res.add(new TermExpr(it1.next(), getIntType()));
final Iterator<ConstantTerm> it2 = symTriple._2().iterator();
while (it2.hasNext())
res.add(new TermExpr(IConstant$.MODULE$.apply(it2.next()), getIntType()));
final Iterator<Predicate> it3 = symTriple._3().iterator();
final List<ITerm> emptyArgs = (new ArrayBuffer<ITerm>()).toList();
while (it3.hasNext())
res.add(new FormulaExpr(IAtom$.MODULE$.apply(it3.next(), emptyArgs)));
return res.toArray(new ProverExpr[0]);
}
/**
* Simultaneously substitute <code>from</code> with <code>to</code>
* in <code>target</code>. <code>from</code> has to be an array of
* free or bound variables.
*/
public ProverExpr substitute(ProverExpr target,
ProverExpr[] from, ProverExpr[] to) {
assert(from.length == to.length);
final scala.collection.mutable.HashMap<ConstantTerm, ITerm> constantSubst =
new scala.collection.mutable.HashMap<ConstantTerm, ITerm>();
final scala.collection.mutable.HashMap<Predicate, IFormula> predicateSubst =
new scala.collection.mutable.HashMap<Predicate, IFormula>();
for (int i = 0; i < from.length; ++i) {
if (from[i] instanceof TermExpr) {
final ConstantTerm c = ((IConstant)((TermExpr)from[i]).term).c();
final ITerm t = ((TermExpr)to[i]).term;
constantSubst.put(c, t);
} else {
final Predicate p = ((IAtom)((FormulaExpr)from[i]).formula).pred();
assert(p.arity() == 0);
final IFormula f = ((FormulaExpr)to[i]).formula;
predicateSubst.put(p, f);
}
}
// We currently just assume that there are no clashes between substituted
// terms and predicates/formulae, and that the substitutions can be
// carried out in sequence
if (target instanceof TermExpr) {
final ITerm t1 = ((TermExpr)target).term;
final ITerm t2 = ConstantSubstVisitor$.MODULE$.apply(t1, constantSubst);
final ITerm t3 = PredicateSubstVisitor$.MODULE$.apply(t2, predicateSubst);
return new TermExpr(t3, target.getType());
} else {
final IFormula f1 = ((FormulaExpr)target).formula;
final IFormula f2 = ConstantSubstVisitor$.MODULE$.apply(f1, constantSubst);
final IFormula f3 = PredicateSubstVisitor$.MODULE$.apply(f2, predicateSubst);
return new FormulaExpr(f3);
}
}
public void shutdown() {
api.shutDown();
}
public void reset() {
api.reset();
}
/*
*
* class CFGPlugin(cfg : Dag[Predicate], effectualNodes : Seq[Predicate],
* ineffectualityFlags : Seq[Predicate], minEffectualNodesCovered : Int)
* extends Plugin {
*/
public void setupCFGPlugin(Dag<IFormula> dag,
Collection<ProverExpr> blockVarExpr, Collection<ProverExpr> set,
int threshold) {
LinkedList<IFormula> scalaBlock = new LinkedList<IFormula>();
for (ProverExpr exp : blockVarExpr) {
scalaBlock.add(proverExpToIFormula(exp));
}
LinkedList<IFormula> scalaVar = new LinkedList<IFormula>();
for (ProverExpr exp : set) {
scalaVar.add(proverExpToIFormula(exp));
}
Seq<IFormula> scala_blocks = JavaConversions
.collectionAsScalaIterable(scalaBlock).toSeq();
Seq<IFormula> scala_rvars =
JavaConversions.collectionAsScalaIterable(scalaVar).toSeq();
api.setupTheoryPlugin(CFGPlugin.apply(dag, scala_blocks, scala_rvars,
threshold));
}
public IFormula proverExpToIFormula(ProverExpr exp) {
return ((FormulaExpr) exp).formula;
}
@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value="DM_DEFAULT_ENCODING")
public String proverExprToSMT(ProverExpr exp) {
PrintStream originalOut = scala.Console.out();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream newOut = new PrintStream(baos);
scala.Console.setOut(newOut);
ap.parser.SMTLineariser.apply(((FormulaExpr) exp).formula);
scala.Console.flush();
scala.Console.setOut(originalOut);
return baos.toString();
}
}