/*
* Copyright (C) 2009-2012 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.logic;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Map;
/**
* A logging script variant. This is actually a wrapper around a concrete
* implementation of the {@link Script} interface that produces an interaction
* file in (almost) SMTLIB 2 compliant format. We still have some extra
* commands like "simplify", "reset", or "get-interpolants".
* @author Juergen Christ
*/
public class LoggingScript implements Script {
/**
* The actual script.
*/
private final Script mScript;
/**
* The interaction log writer.
*/
private final PrintWriter mPw;
/**
* The auxiliary class to print terms and sorts.
*/
private final PrintTerm mTermPrinter = new PrintTerm();
/**
* Common subexpression elimination support if requeste by user. Will be
* <code>null</code> if cse should not be performed.
*/
private final FormulaLet mLetter;
/**
* Create a new script logging the commands by the user. Most commands
* are not supported, e.g., checkSat always returns unknown. Furthermore,
* common subexpression elimination is not used in the output.
* @param file The name of the logging file (should end in .smt2).
* @param autoFlush Automatically flush the output stream after every
* command.
* @throws FileNotFoundException If the file cannot be opened.
*/
public LoggingScript(String file, boolean autoFlush)
throws FileNotFoundException {
this (new NoopScript(), file, autoFlush);
}
/**
* Create a new script logging the interaction between the user and the
* wrapped script into a file. This constructor sets up logging to not use
* common subexpression elimination.
* @param script The wrapped script.
* @param file The name of the logging file (should end in .smt2).
* @param autoFlush Automatically flush the output stream after every
* command.
* @throws FileNotFoundException If the file cannot be opened.
*/
public LoggingScript(Script script, String file, boolean autoFlush)
throws FileNotFoundException {
this(script, file, autoFlush, false);
}
/**
* Create a new script logging the interaction between the user and the
* wrapped script into a file. This constructor can be used to set up
* logging using common subexpression elimination.
* @param script The wrapped script.
* @param file The name of the logging file (should end in .smt2).
* @param autoFlush Automatically flush the output stream after every
* command.
* @param useCSE Use common subexpression elimination in output
* (introduces let terms)
* @throws FileNotFoundException If the file cannot be opened.
*/
public LoggingScript(Script script, String file, boolean autoFlush,
boolean useCSE)
throws FileNotFoundException {
mScript = script;
OutputStream out;
if (file.equals("<stdout>")) {
out = System.out;
} else if (file.equals("<stderr>")) {
out = System.err;
} else {
out = new FileOutputStream(file);
}
mPw = new PrintWriter(
new BufferedWriter(new OutputStreamWriter(out)), autoFlush);
mLetter = useCSE ? new FormulaLet() : null;
}
private final Term formatTerm(Term input) {
return mLetter == null ? input : new FormulaLet().let(input);
}
@Override
public void setLogic(String logic)
throws UnsupportedOperationException, SMTLIBException {
mPw.println("(set-logic " + logic + ")");
mScript.setLogic(logic);
}
@Override
public void setLogic(Logics logic)
throws UnsupportedOperationException, SMTLIBException {
mPw.println("(set-logic " + logic.name() + ")");
mScript.setLogic(logic);
}
@Override
public void setOption(String opt, Object value)
throws UnsupportedOperationException, SMTLIBException {
mPw.print("(set-option ");
mPw.print(opt);
mPw.print(' ');
mPw.print(PrintTerm.quoteObjectIfString(value));
mPw.println(")");
mScript.setOption(opt, value);
}
@Override
public void setInfo(String info, Object value) {
mPw.print("(set-info ");
mPw.print(info);
mPw.print(' ');
mPw.print(PrintTerm.quoteObjectIfString(value));
mPw.println(")");
mScript.setInfo(info, value);
}
@Override
public void declareSort(String sort, int arity) throws SMTLIBException {
mPw.print("(declare-sort ");
mPw.print(PrintTerm.quoteIdentifier(sort));
mPw.print(' ');
mPw.print(arity);
mPw.println(")");
mScript.declareSort(sort, arity);
}
@Override
public void defineSort(String sort, Sort[] sortParams, Sort definition)
throws SMTLIBException {
mPw.print("(define-sort ");
mPw.print(PrintTerm.quoteIdentifier(sort));
mPw.print(" (");
String sep = "";
for (final Sort p : sortParams) {
mPw.print(sep);
mTermPrinter.append(mPw, p);
sep = " ";
}
mPw.print(") ");
mTermPrinter.append(mPw, definition);
mPw.println(")");
mScript.defineSort(sort, sortParams, definition);
}
@Override
public void declareFun(String fun, Sort[] paramSorts, Sort resultSort)
throws SMTLIBException {
mPw.print("(declare-fun ");
mPw.print(PrintTerm.quoteIdentifier(fun));
mPw.print(" (");
String sep = "";
for (final Sort p : paramSorts) {
mPw.print(sep);
mTermPrinter.append(mPw, p);
sep = " ";
}
mPw.print(") ");
mTermPrinter.append(mPw, resultSort);
mPw.println(")");
mScript.declareFun(fun, paramSorts, resultSort);
}
@Override
public void defineFun(String fun, TermVariable[] params, Sort resultSort,
Term definition) throws SMTLIBException {
mPw.print("(define-fun ");
mPw.print(PrintTerm.quoteIdentifier(fun));
mPw.print(" (");
String sep = "(";
for (final TermVariable t : params) {
mPw.print(sep);
mPw.print(t);
mPw.print(' ');
mTermPrinter.append(mPw, t.getSort());
mPw.print(')');
sep = " (";
}
mPw.print(") ");
mTermPrinter.append(mPw, resultSort);
mPw.print(' ');
mTermPrinter.append(mPw, formatTerm(definition));
mPw.println(")");
mScript.defineFun(fun, params, resultSort, definition);
}
@Override
public void push(int levels) throws SMTLIBException {
mPw.println("(push " + levels + ")");
mScript.push(levels);
}
@Override
public void pop(int levels) throws SMTLIBException {
mPw.println("(pop " + levels + ")");
mScript.pop(levels);
}
@Override
public LBool assertTerm(Term term) throws SMTLIBException {
mPw.print("(assert ");
mTermPrinter.append(mPw, formatTerm(term));
mPw.println(")");
return mScript.assertTerm(term);
}
@Override
public LBool checkSat() throws SMTLIBException {
mPw.println("(check-sat)");
return mScript.checkSat();
}
@Override
public LBool checkSatAssuming(Term... assumptions) throws SMTLIBException {
mPw.print("(check-sat-assuming (");
String sep = "";
for (final Term t : assumptions) {
mPw.print(sep);
mTermPrinter.append(mPw, formatTerm(t));
sep = " ";
}
mPw.println("))");
return mScript.checkSatAssuming(assumptions);
}
@Override
public Term[] getAssertions() throws SMTLIBException {
mPw.println("(get-assertions)");
return mScript.getAssertions();
}
@Override
public Term getProof() throws SMTLIBException,
UnsupportedOperationException {
mPw.println("(get-proof)");
return mScript.getProof();
}
@Override
public Term[] getUnsatCore() throws SMTLIBException,
UnsupportedOperationException {
mPw.println("(get-unsat-core)");
return mScript.getUnsatCore();
}
@Override
public Map<Term, Term> getValue(Term[] terms) throws SMTLIBException,
UnsupportedOperationException {
mPw.print("(get-value (");
String sep = "";
for (final Term t : terms) {
mPw.print(sep);
mTermPrinter.append(mPw, formatTerm(t));
sep = " ";
}
mPw.println("))");
return mScript.getValue(terms);
}
@Override
public Assignments getAssignment() throws SMTLIBException,
UnsupportedOperationException {
mPw.println("(get-assignment)");
return mScript.getAssignment();
}
@Override
public Object getOption(String opt) throws UnsupportedOperationException {
mPw.println("(get-option " + opt + ")");
return mScript.getOption(opt);
}
@Override
public Object getInfo(String info) throws UnsupportedOperationException {
mPw.println("(get-info " + info + ")");
return mScript.getInfo(info);
}
@Override
public Term simplify(Term term) throws SMTLIBException {
mPw.print("(simplify ");
mTermPrinter.append(mPw, term);
mPw.println(")");
return mScript.simplify(term);
}
@Override
public void reset() {
mPw.println("(reset)");
mScript.reset();
}
@Override
public Term[] getInterpolants(Term[] partition) throws SMTLIBException,
UnsupportedOperationException {
mPw.print("(get-interpolants");
for (final Term t : partition) {
mPw.print(' ');
mTermPrinter.append(mPw, t);
}
mPw.println(')');
return mScript.getInterpolants(partition);
}
// [a,b,c], [0,1,0] -> a (b) c
// c
// a b
@Override
public Term[] getInterpolants(Term[] partition, int[] startOfSubtree)
throws SMTLIBException, UnsupportedOperationException {
mPw.print("(get-interpolants ");
mTermPrinter.append(mPw, partition[0]);
for (int i = 1; i < partition.length; ++i) {
int prevStart = startOfSubtree[i - 1];
while (startOfSubtree[i] < prevStart) {
mPw.print(')');
prevStart = startOfSubtree[prevStart - 1];
}
mPw.print(' ');
if (startOfSubtree[i] == i) {
mPw.print('(');
}
mTermPrinter.append(mPw, partition[i]);
}
mPw.println(')');
return mScript.getInterpolants(partition, startOfSubtree);
}
@Override
public void exit() {
mPw.println("(exit)");
mPw.flush();
mPw.close();
mScript.exit();
}
@Override
public Sort sort(String sortname, Sort... params) throws SMTLIBException {
return mScript.sort(sortname, params);
}
@Override
public Sort sort(String sortname, BigInteger[] indices, Sort... params)
throws SMTLIBException {
return mScript.sort(sortname, indices, params);
}
@Override
public Term term(String funcname, Term... params) throws SMTLIBException {
return mScript.term(funcname, params);
}
@Override
public Term term(String funcname, BigInteger[] indices, Sort returnSort,
Term... params) throws SMTLIBException {
return mScript.term(funcname, indices, returnSort, params);
}
@Override
public TermVariable variable(String varname, Sort sort)
throws SMTLIBException {
return mScript.variable(varname, sort);
}
@Override
public Term quantifier(int quantor, TermVariable[] vars, Term body,
Term[]... patterns) throws SMTLIBException {
return mScript.quantifier(quantor, vars, body, patterns);
}
@Override
public Term let(TermVariable[] vars, Term[] values, Term body)
throws SMTLIBException {
return mScript.let(vars, values, body);
}
@Override
public Term annotate(Term t, Annotation... annotations)
throws SMTLIBException {
return mScript.annotate(t, annotations);
}
@Override
public Term numeral(String num) throws SMTLIBException {
return mScript.numeral(num);
}
@Override
public Term numeral(BigInteger num) throws SMTLIBException {
return mScript.numeral(num);
}
@Override
public Term decimal(String decimal) throws SMTLIBException {
return mScript.decimal(decimal);
}
@Override
public Term decimal(BigDecimal decimal) throws SMTLIBException {
return mScript.decimal(decimal);
}
@Override
public Term string(String str) throws SMTLIBException {
return mScript.string(str);
}
@Override
public Term hexadecimal(String hex) throws SMTLIBException {
return mScript.hexadecimal(hex);
}
@Override
public Term binary(String bin) throws SMTLIBException {
return mScript.binary(bin);
}
@Override
public Sort[] sortVariables(String... names) throws SMTLIBException {
return mScript.sortVariables(names);
}
@Override
public Model getModel() throws SMTLIBException,
UnsupportedOperationException {
mPw.println("(get-model)");
return mScript.getModel();
}
@Override
public Iterable<Term[]> checkAllsat(Term[] predicates)
throws SMTLIBException, UnsupportedOperationException {
final PrintTerm pt = new PrintTerm();
mPw.print("(check-allsat (");
String spacer = "";
for (final Term p : predicates) {
mPw.print(spacer);
pt.append(mPw, p);
spacer = " ";
}
mPw.println("))");
return mScript.checkAllsat(predicates);
}
@Override
public Term[] findImpliedEquality(Term[] x, Term[] y) {
final PrintTerm pt = new PrintTerm();
mPw.print("(find-implied-equality (");
String spacer = "";
for (final Term p : x) {
mPw.print(spacer);
pt.append(mPw, p);
spacer = " ";
}
mPw.print(") (");
spacer = "";
for (final Term p : x) {
mPw.print(spacer);
pt.append(mPw, p);
spacer = " ";
}
mPw.println("))");
return mScript.findImpliedEquality(x, y);
}
@Override
public QuotedObject echo(QuotedObject msg) {
mPw.print("(echo ");
mPw.print(msg);
mPw.println(')');
return mScript.echo(msg);
}
/**
* Write a comment to the generated SMTLIB dump file. Note that this
* function is only available in the LoggingScript and not in the interface
* {@link Script} since it only makes sense for logging and not for solving.
* @param comment The comment to write to the dump file.
*/
public void comment(String comment) {
mPw.print("; ");
mPw.println(comment);
}
@Override
public void resetAssertions() {
mPw.println("(reset-assertions)");
mScript.resetAssertions();
}
@Override
public Term[] getUnsatAssumptions() throws SMTLIBException,
UnsupportedOperationException {
mPw.println("(get-unsat-assumptions)");
return mScript.getUnsatAssumptions();
}
}