org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5FormulaCreator.java Source code

Java tutorial

Introduction

Here is the source code for org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5FormulaCreator.java

Source

/*
 *  JavaSMT is an API wrapper for a collection of SMT solvers.
 *  This file is part of JavaSMT.
 *
 *  Copyright (C) 2007-2016  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.
 */
package org.sosy_lab.java_smt.solvers.mathsat5;

import static com.google.common.base.Preconditions.checkArgument;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.MSAT_TAG_AND;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.MSAT_TAG_ARRAY_READ;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.MSAT_TAG_ARRAY_WRITE;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.MSAT_TAG_EQ;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.MSAT_TAG_IFF;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.MSAT_TAG_ITE;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.MSAT_TAG_LEQ;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.MSAT_TAG_NOT;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.MSAT_TAG_OR;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.MSAT_TAG_PLUS;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_decl_get_name;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_decl_get_tag;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_declare_function;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_get_array_element_type;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_get_array_index_type;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_get_array_type;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_get_bool_type;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_get_bv_type;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_get_bv_type_size;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_get_fp_type;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_get_fp_type_exp_width;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_get_fp_type_mant_width;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_get_integer_type;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_get_rational_type;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_is_array_type;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_is_bool_type;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_is_bv_type;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_is_fp_roundingmode_type;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_is_fp_type;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_is_integer_type;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_is_rational_type;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_make_constant;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_make_term;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_arity;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_get_arg;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_get_decl;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_get_type;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_is_constant;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_is_false;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_is_number;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_is_true;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_is_uf;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_term_repr;
import static org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5NativeApi.msat_type_repr;

import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Longs;
import com.google.common.primitives.UnsignedInteger;
import com.google.common.primitives.UnsignedLong;
import java.math.BigInteger;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.sosy_lab.common.rationals.Rational;
import org.sosy_lab.java_smt.api.ArrayFormula;
import org.sosy_lab.java_smt.api.BitvectorFormula;
import org.sosy_lab.java_smt.api.BooleanFormula;
import org.sosy_lab.java_smt.api.FloatingPointFormula;
import org.sosy_lab.java_smt.api.Formula;
import org.sosy_lab.java_smt.api.FormulaType;
import org.sosy_lab.java_smt.api.FormulaType.ArrayFormulaType;
import org.sosy_lab.java_smt.api.FormulaType.FloatingPointType;
import org.sosy_lab.java_smt.api.FunctionDeclarationKind;
import org.sosy_lab.java_smt.api.visitors.FormulaVisitor;
import org.sosy_lab.java_smt.basicimpl.FormulaCreator;
import org.sosy_lab.java_smt.basicimpl.FunctionDeclarationImpl;
import org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5Formula.Mathsat5ArrayFormula;
import org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5Formula.Mathsat5BitvectorFormula;
import org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5Formula.Mathsat5BooleanFormula;
import org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5Formula.Mathsat5FloatingPointFormula;
import org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5Formula.Mathsat5FloatingPointRoundingModeFormula;
import org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5Formula.Mathsat5IntegerFormula;
import org.sosy_lab.java_smt.solvers.mathsat5.Mathsat5Formula.Mathsat5RationalFormula;

class Mathsat5FormulaCreator extends FormulaCreator<Long, Long, Long, Long> {

    private static final Pattern FLOATING_POINT_PATTERN = Pattern.compile("^(\\d+)_(\\d+)_(\\d+)$");
    private static final Pattern BITVECTOR_PATTERN = Pattern.compile("^(\\d+)_(\\d+)$");

    Mathsat5FormulaCreator(final Long msatEnv) {
        super(msatEnv, msat_get_bool_type(msatEnv), msat_get_integer_type(msatEnv),
                msat_get_rational_type(msatEnv));
    }

    @Override
    public Long makeVariable(Long type, String varName) {
        long funcDecl = msat_declare_function(getEnv(), varName, type);
        return msat_make_constant(getEnv(), funcDecl);
    }

    @Override
    public Long extractInfo(Formula pT) {
        return Mathsat5FormulaManager.getMsatTerm(pT);
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T extends Formula> FormulaType<T> getFormulaType(T pFormula) {
        long env = getEnv();
        if (pFormula instanceof BitvectorFormula) {
            long type = msat_term_get_type(extractInfo(pFormula));
            checkArgument(msat_is_bv_type(env, type),
                    "BitvectorFormula with actual type " + msat_type_repr(type) + ": " + pFormula);
            return (FormulaType<T>) FormulaType.getBitvectorTypeWithSize(msat_get_bv_type_size(env, type));

        } else if (pFormula instanceof FloatingPointFormula) {
            long type = msat_term_get_type(extractInfo(pFormula));
            checkArgument(msat_is_fp_type(env, type),
                    "FloatingPointFormula with actual type " + msat_type_repr(type) + ": " + pFormula);
            return (FormulaType<T>) FormulaType.getFloatingPointType(msat_get_fp_type_exp_width(env, type),
                    msat_get_fp_type_mant_width(env, type));
        } else if (pFormula instanceof ArrayFormula<?, ?>) {
            FormulaType<T> arrayIndexType = getArrayFormulaIndexType((ArrayFormula<T, T>) pFormula);
            FormulaType<T> arrayElementType = getArrayFormulaElementType((ArrayFormula<T, T>) pFormula);
            return (FormulaType<T>) FormulaType.getArrayType(arrayIndexType, arrayElementType);
        }
        return super.getFormulaType(pFormula);
    }

    @Override
    public FormulaType<?> getFormulaType(Long pFormula) {
        long type = msat_term_get_type(pFormula);
        return getFormulaTypeFromTermType(type);
    }

    private FormulaType<?> getFormulaTypeFromTermType(Long type) {
        long env = getEnv();
        if (msat_is_bool_type(env, type)) {
            return FormulaType.BooleanType;
        } else if (msat_is_integer_type(env, type)) {
            return FormulaType.IntegerType;
        } else if (msat_is_rational_type(env, type)) {
            return FormulaType.RationalType;
        } else if (msat_is_bv_type(env, type)) {
            return FormulaType.getBitvectorTypeWithSize(msat_get_bv_type_size(env, type));
        } else if (msat_is_fp_type(env, type)) {
            return FormulaType.getFloatingPointType(msat_get_fp_type_exp_width(env, type),
                    msat_get_fp_type_mant_width(env, type));
        } else if (msat_is_fp_roundingmode_type(env, type)) {
            return FormulaType.FloatingPointRoundingModeType;
        } else if (msat_is_array_type(env, type)) {
            long indexType = msat_get_array_index_type(env, type);
            long elementType = msat_get_array_element_type(env, type);
            return FormulaType.getArrayType(getFormulaTypeFromTermType(indexType),
                    getFormulaTypeFromTermType(elementType));
        }
        throw new IllegalArgumentException("Unknown formula type " + msat_type_repr(type));
    }

    @Override
    public Long getBitvectorType(int pBitwidth) {
        return msat_get_bv_type(getEnv(), pBitwidth);
    }

    @Override
    public Long getFloatingPointType(FloatingPointType pType) {
        return msat_get_fp_type(getEnv(), pType.getExponentSize(), pType.getMantissaSize());
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T extends Formula> T encapsulate(FormulaType<T> pType, Long pTerm) {
        assert pType.equals(getFormulaType(pTerm)) || (pType.equals(FormulaType.RationalType)
                && getFormulaType(pTerm).equals(FormulaType.IntegerType)) : String
                        .format("Trying to encapsulate formula of type %s as %s", getFormulaType(pTerm), pType);
        if (pType.isBooleanType()) {
            return (T) new Mathsat5BooleanFormula(pTerm);
        } else if (pType.isIntegerType()) {
            return (T) new Mathsat5IntegerFormula(pTerm);
        } else if (pType.isRationalType()) {
            return (T) new Mathsat5RationalFormula(pTerm);
        } else if (pType.isArrayType()) {
            ArrayFormulaType<?, ?> arrFt = (ArrayFormulaType<?, ?>) pType;
            return (T) new Mathsat5ArrayFormula<>(pTerm, arrFt.getIndexType(), arrFt.getElementType());
        } else if (pType.isBitvectorType()) {
            return (T) new Mathsat5BitvectorFormula(pTerm);
        } else if (pType.isFloatingPointType()) {
            return (T) new Mathsat5FloatingPointFormula(pTerm);
        } else if (pType.isFloatingPointRoundingModeType()) {
            return (T) new Mathsat5FloatingPointRoundingModeFormula(pTerm);
        }
        throw new IllegalArgumentException("Cannot create formulas of type " + pType + " in MathSAT");
    }

    @Override
    public BooleanFormula encapsulateBoolean(Long pTerm) {
        assert getFormulaType(pTerm).isBooleanType();
        return new Mathsat5BooleanFormula(pTerm);
    }

    @Override
    public BitvectorFormula encapsulateBitvector(Long pTerm) {
        assert getFormulaType(pTerm).isBitvectorType();
        return new Mathsat5BitvectorFormula(pTerm);
    }

    @Override
    protected FloatingPointFormula encapsulateFloatingPoint(Long pTerm) {
        assert getFormulaType(pTerm).isFloatingPointType();
        return new Mathsat5FloatingPointFormula(pTerm);
    }

    @Override
    protected <TI extends Formula, TE extends Formula> ArrayFormula<TI, TE> encapsulateArray(Long pTerm,
            FormulaType<TI> pIndexType, FormulaType<TE> pElementType) {
        assert getFormulaType(pTerm).equals(FormulaType.getArrayType(pIndexType, pElementType));
        return new Mathsat5ArrayFormula<>(pTerm, pIndexType, pElementType);
    }

    @Override
    protected <TI extends Formula, TE extends Formula> FormulaType<TE> getArrayFormulaElementType(
            ArrayFormula<TI, TE> pArray) {
        return ((Mathsat5ArrayFormula<TI, TE>) pArray).getElementType();
    }

    @Override
    protected <TI extends Formula, TE extends Formula> FormulaType<TI> getArrayFormulaIndexType(
            ArrayFormula<TI, TE> pArray) {
        return ((Mathsat5ArrayFormula<TI, TE>) pArray).getIndexType();
    }

    @Override
    public Long getArrayType(Long pIndexType, Long pElementType) {
        return msat_get_array_type(getEnv(), pIndexType, pElementType);
    }

    @Override
    public <R> R visit(FormulaVisitor<R> visitor, Formula formula, final Long f) {
        int arity = msat_term_arity(f);
        if (msat_term_is_number(environment, f)) {
            return visitor.visitConstant(formula, convertValue(f, f));
        } else if (msat_term_is_true(environment, f)) {
            return visitor.visitConstant(formula, true);
        } else if (msat_term_is_false(environment, f)) {
            return visitor.visitConstant(formula, false);
        } else if (msat_term_is_constant(environment, f)) {
            return visitor.visitFreeVariable(formula, msat_term_repr(f));
        } else {

            ImmutableList.Builder<Formula> args = ImmutableList.builder();
            ImmutableList.Builder<FormulaType<?>> argTypes = ImmutableList.builder();
            for (int i = 0; i < arity; i++) {
                long arg = msat_term_get_arg(f, i);
                FormulaType<?> argumentType = getFormulaType(arg);
                args.add(encapsulate(argumentType, arg));
                argTypes.add(argumentType);
            }

            String name = msat_decl_get_name(msat_term_get_decl(f));
            return visitor.visitFunction(formula, args.build(), FunctionDeclarationImpl.of(name,
                    getDeclarationKind(f), argTypes.build(), getFormulaType(f), msat_term_get_decl(f)));
        }
    }

    String getName(long term) {
        if (msat_term_is_uf(environment, term)) {
            return msat_decl_get_name(msat_term_get_decl(term));
        }
        return msat_term_repr(term);
    }

    private FunctionDeclarationKind getDeclarationKind(long pF) {
        if (msat_term_is_uf(environment, pF)) {
            return FunctionDeclarationKind.UF;
        }

        assert !msat_term_is_constant(environment, pF) : "Variables should be handled somewhere else";

        long decl = msat_term_get_decl(pF);
        int tag = msat_decl_get_tag(environment, decl);
        switch (tag) {
        case MSAT_TAG_AND:
            return FunctionDeclarationKind.AND;
        case MSAT_TAG_NOT:
            return FunctionDeclarationKind.NOT;
        case MSAT_TAG_OR:
            return FunctionDeclarationKind.OR;
        case MSAT_TAG_IFF:
            return FunctionDeclarationKind.IFF;
        case MSAT_TAG_ITE:
            return FunctionDeclarationKind.ITE;

        case MSAT_TAG_PLUS:
            return FunctionDeclarationKind.ADD;
        case MSAT_TAG_LEQ:
            return FunctionDeclarationKind.LTE;
        case MSAT_TAG_EQ:
            return FunctionDeclarationKind.EQ;
        case MSAT_TAG_ARRAY_READ:
            return FunctionDeclarationKind.SELECT;
        case MSAT_TAG_ARRAY_WRITE:
            return FunctionDeclarationKind.STORE;
        default:
            return FunctionDeclarationKind.OTHER;
        }
    }

    Object convertValue(long key, long term) {

        // To get the correct type, we generate it from the key, not the value.
        FormulaType<?> type = getFormulaType(key);
        String repr = msat_term_repr(term);
        if (type.isBooleanType()) {
            return msat_term_is_true(getEnv(), term);
        } else if (type.isRationalType()) {
            return Rational.ofString(repr);
        } else if (type.isIntegerType()) {
            return new BigInteger(repr);
        } else if (type.isBitvectorType()) {
            return parseBitvector(repr);
        } else if (type.isFloatingPointType()) {
            return parseFloatingPoint(repr);
        } else {

            throw new IllegalArgumentException("Unexpected type: " + type);
        }
    }

    private Number parseFloatingPoint(String lTermRepresentation) {

        // the term is of the format "<VALUE>_<EXPWIDTH>_<MANTWIDTH>"
        Matcher matcher = FLOATING_POINT_PATTERN.matcher(lTermRepresentation);
        if (!matcher.matches()) {
            throw new NumberFormatException("Unknown floating-point format: " + lTermRepresentation);
        }

        int expWidth = Integer.parseInt(matcher.group(2));
        int mantWidth = Integer.parseInt(matcher.group(3));

        if (expWidth == 11 && mantWidth == 52) {
            return Double.longBitsToDouble(UnsignedLong.valueOf(matcher.group(1)).longValue());
        } else if (expWidth == 8 && mantWidth == 23) {
            return Float.intBitsToFloat(UnsignedInteger.valueOf(matcher.group(1)).intValue());
        }

        // TODO to be fully correct, we would need to interpret this string
        return new BigInteger(matcher.group(1));
    }

    //TODO: change this to the latest version
    // (if possible try to use a BitvectorFormula instance here)
    private static BigInteger parseBitvector(String lTermRepresentation) {
        // the term is of the format "<VALUE>_<WIDTH>"
        Matcher matcher = BITVECTOR_PATTERN.matcher(lTermRepresentation);
        if (!matcher.matches()) {
            throw new NumberFormatException("Unknown bitvector format: " + lTermRepresentation);
        }

        // TODO: calculate negative value?
        String term = matcher.group(1);
        return new BigInteger(term);
    }

    @Override
    public Long callFunctionImpl(FunctionDeclarationImpl<?, Long> declaration, List<Long> args) {
        return msat_make_term(environment, declaration.getSolverDeclaration(), Longs.toArray(args));
    }

    @Override
    protected Long getBooleanVarDeclarationImpl(Long pLong) {
        return msat_term_get_decl(pLong);
    }
}