org.sosy_lab.solver.z3.Z3SmtLogger.java Source code

Java tutorial

Introduction

Here is the source code for org.sosy_lab.solver.z3.Z3SmtLogger.java

Source

/*
 *  CPAchecker is a tool for configurable software verification.
 *  This file is part of CPAchecker.
 *
 *  Copyright (C) 2007-2014  Dirk Beyer
 *  All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *
 *  CPAchecker web page:
 *    http://cpachecker.sosy-lab.org
 */
package org.sosy_lab.solver.z3;

import static org.sosy_lab.solver.z3.Z3NativeApi.*;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

import javax.annotation.Nullable;

import org.sosy_lab.common.configuration.Configuration;
import org.sosy_lab.common.configuration.InvalidConfigurationException;
import org.sosy_lab.common.configuration.Option;
import org.sosy_lab.common.configuration.Options;
import org.sosy_lab.common.io.Path;
import org.sosy_lab.common.io.PathCounterTemplate;

import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.io.FileWriteMode;

class Z3SmtLogger {

    @Options(deprecatedPrefix = "cpa.predicate.solver.z3.logger", prefix = "solver.z3.logger")
    private static class Z3Settings {

        private final @Nullable PathCounterTemplate basicLogfile;

        @Option(secure = true, description = "Export solver queries in Smtlib2 format, "
                + "there are small differences for different solvers, "
                + "choose target-solver.", values = { Z3, MATHSAT5 }, toUppercase = true)
        private String target = Z3;

        private Z3Settings(Configuration config, @Nullable PathCounterTemplate logfile)
                throws InvalidConfigurationException {
            config.inject(this);
            basicLogfile = logfile;
        }
    }

    private static final String MATHSAT5 = "MATHSAT5";
    private static final String Z3 = "Z3";
    // TODO support for smtinterpol?

    private final @Nullable Path logfile;
    private final Z3Settings settings;
    private final long z3context;

    private final HashSet<Long> declarations = Sets.newHashSet();

    private int itpIndex = 0; // each interpolation gets its own index
    private final HashMap<Long, String> interpolationFormulas = Maps.newHashMap(); // for mathsat-compatibility

    Z3SmtLogger(long z3context, Configuration config, @Nullable PathCounterTemplate logfile)
            throws InvalidConfigurationException {
        this(z3context, new Z3Settings(config, logfile));
    }

    private Z3SmtLogger(long pZ3context, Z3Settings pSettings) {
        z3context = pZ3context;
        settings = pSettings;

        if (settings.basicLogfile != null) {
            this.logfile = settings.basicLogfile.getFreshPath();
            log("", false); // create or clean the file
        } else {
            this.logfile = null;
        }
    }

    /** returns a new instance with a new logfile. */
    public Z3SmtLogger cloneWithNewLogfile() {
        return new Z3SmtLogger(z3context, settings);
    }

    public void logOption(String option, String value) {
        if (logfile == null) {
            return;
        }
        logBracket("set-option :" + option + " " + value);
    }

    public void logVarDeclaration(long name, long type) {
        if (logfile == null) {
            return;
        }
        if (declarations.add(name)) {
            logBracket("declare-fun " + ast_to_string(z3context, name) + " () " + sort_to_string(z3context, type));
        }
    }

    public void logFunctionDeclaration(long symbol, long[] inputTypes, long returnType) {
        if (logfile == null) {
            return;
        }
        if (declarations.add(symbol)) {
            StringBuilder s = new StringBuilder();
            s.append("declare-fun ").append(get_symbol_string(z3context, symbol)).append(" (");
            for (long it : inputTypes) {
                s.append(sort_to_string(z3context, it)).append(" ");
            }
            s.append(") ").append(sort_to_string(z3context, returnType));

            logBracket(s.toString());
        }
    }

    public void logPush(int n) {
        if (logfile == null) {
            return;
        }
        logBracket("push " + n);
    }

    public void logPop(int n) {
        if (logfile == null) {
            return;
        }
        logBracket("pop " + n);
    }

    public void logAssert(long expr) {
        //    if (smtlogfile == null) { return; }
        //    logBracket("assert " + ast_to_string(z3context, expr));
        logInterpolationAssert(expr); // for mathsat, to use "one" declarations-file
    }

    public void logInterpolationAssert(long expr) {
        if (logfile == null) {
            return;
        }
        itpIndex++;
        String formula = ast_to_string(z3context, expr);

        switch (settings.target) {
        case Z3:
            logBracket("assert " + formula);
            break;

        case MATHSAT5:
            String name = "itpId" + itpIndex;
            logBracket("assert (! " + formula + " :interpolation-group " + name + ")");
            interpolationFormulas.put(expr, name);
            break;
        default:
            throw new AssertionError();
        }
    }

    public void logCheck() {
        if (logfile == null) {
            return;
        }
        logBracket("check-sat");
    }

    public void logGetModel() {
        if (logfile == null) {
            return;
        }
        logBracket("get-model");
    }

    public void logInterpolation(List<Long> formulasOfA, List<Long> formulasOfB, long conjunctionA,
            long conjunctionB) {
        if (logfile == null) {
            return;
        }

        StringBuilder itpQuery = new StringBuilder();
        switch (settings.target) {
        case Z3:
            itpQuery.append("get-interpolant ").append(ast_to_string(z3context, conjunctionA)).append(" ")
                    .append(ast_to_string(z3context, conjunctionB));
            break;

        case MATHSAT5:
            itpQuery.append("get-interpolant (");

            for (long f : formulasOfA) {
                Preconditions.checkArgument(interpolationFormulas.containsKey(f));
                itpQuery.append(interpolationFormulas.get(f)).append(" ");
            }

            itpQuery.append(")");
            break;
        default:
            throw new AssertionError();
        }

        logCheck(); // TODO remove check?
        logBracket(itpQuery.toString());
    }

    public void logSeqInterpolation(long[] interpolationFormulas) {
        if (logfile == null) {
            return;
        }

        StringBuilder itpQuery = new StringBuilder();
        switch (settings.target) {
        case Z3:
            itpQuery.append("get-interpolants ");
            for (long f : interpolationFormulas) {
                itpQuery.append(ast_to_string(z3context, f));
            }
            break;

        case MATHSAT5:
            throw new AssertionError("not supported via SMT-input/output??");

        default:
            throw new AssertionError();
        }

        logCheck(); // TODO remove check?
        logBracket(itpQuery.toString());
    }

    public void logBracket(String s) {
        if (logfile == null) {
            return;
        }
        log("(" + s + ")\n", true);
    }

    private synchronized void log(String s, boolean append) {
        try {
            if (append) {
                logfile.asCharSink(Charset.defaultCharset(), FileWriteMode.APPEND).write(s);
            } else {
                logfile.asCharSink(Charset.defaultCharset()).write(s);
            }
        } catch (IOException e) {
            throw new AssertionError("IO-Error in smtlogfile", e);
        }
    }

}