All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hu.bme.mit.theta.solver.javasmt.JavaSMTSolver Maven / Gradle / Ivy

/*
 *  Copyright 2024 Budapest University of Technology and Economics
 *
 *  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 hu.bme.mit.theta.solver.javasmt;

import com.google.common.collect.ImmutableList;
import hu.bme.mit.theta.common.container.Containers;
import hu.bme.mit.theta.core.decl.ConstDecl;
import hu.bme.mit.theta.core.decl.Decl;
import hu.bme.mit.theta.core.model.Valuation;
import hu.bme.mit.theta.core.type.Expr;
import hu.bme.mit.theta.core.type.LitExpr;
import hu.bme.mit.theta.core.type.Type;
import hu.bme.mit.theta.core.type.arraytype.ArrayType;
import hu.bme.mit.theta.core.type.booltype.BoolType;
import hu.bme.mit.theta.core.type.bvtype.BvLitExpr;
import hu.bme.mit.theta.core.type.bvtype.BvType;
import hu.bme.mit.theta.core.type.enumtype.EnumLitExpr;
import hu.bme.mit.theta.core.type.enumtype.EnumType;
import hu.bme.mit.theta.core.type.functype.FuncType;
import hu.bme.mit.theta.solver.Solver;
import hu.bme.mit.theta.solver.SolverStatus;
import hu.bme.mit.theta.solver.Stack;
import hu.bme.mit.theta.solver.UCSolver;
import hu.bme.mit.theta.solver.impl.StackImpl;
import org.sosy_lab.java_smt.api.BasicProverEnvironment;
import org.sosy_lab.java_smt.api.BooleanFormula;
import org.sosy_lab.java_smt.api.Formula;
import org.sosy_lab.java_smt.api.Model;
import org.sosy_lab.java_smt.api.Model.ValueAssignment;
import org.sosy_lab.java_smt.api.SolverContext;
import org.sosy_lab.java_smt.api.SolverException;

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

final class JavaSMTSolver implements UCSolver, Solver {

    private final JavaSMTSymbolTable symbolTable;
    private final JavaSMTTransformationManager transformationManager;
    private final JavaSMTTermTransformer termTransformer;

    private final SolverContext context;
    private final BasicProverEnvironment solver;

    private final Stack> assertions;

    private Valuation model;
    private Collection> unsatCore;


    private final Map> assumptions;
    private SolverStatus status;

    public JavaSMTSolver(final JavaSMTSymbolTable symbolTable,
                         final JavaSMTTransformationManager transformationManager,
                         final JavaSMTTermTransformer termTransformer,
                         final SolverContext context,
                         final BasicProverEnvironment solver) {
        this.symbolTable = symbolTable;
        this.transformationManager = transformationManager;
        this.termTransformer = termTransformer;
        this.context = context;
        this.solver = solver;

        assertions = new StackImpl<>();
        assumptions = Containers.createMap();
    }

    ////

    @Override
    public void add(final Expr assertion) {
        checkNotNull(assertion);
        final BooleanFormula term = (BooleanFormula) transformationManager.toTerm(
                assertion);
        add(assertion, term);
    }

    Object add(final Expr assertion, final BooleanFormula term) {
        assertions.add(assertion);
        Object ret;
        try {
            ret = solver.addConstraint(term);
        } catch (InterruptedException e) {
            throw new JavaSMTSolverException(e);
        }
        clearState();
        return ret;
    }


    @Override
    public void track(final Expr assertion) {
        add(assertion);
    }

    @Override
    public Collection> getUnsatCore() {
        checkState(status == SolverStatus.UNSAT, "Cannot get unsat core if status is not UNSAT");

        if (unsatCore == null) {
            unsatCore = extractUnsatCore();
        }

        assert unsatCore != null;
        return Collections.unmodifiableCollection(unsatCore);
    }


    private Collection> extractUnsatCore() {
        assert status == SolverStatus.UNSAT;
        assert unsatCore == null;

        final Collection> unsatCore = new LinkedList<>();

        final List jsmtUnsatCore = solver.getUnsatCore();

        for (final Formula term : jsmtUnsatCore) {
            final Expr assumption = (Expr) termTransformer.toExpr(term);

            assert assumption != null;
            unsatCore.add(assumption);
        }

        return unsatCore;
    }


    @Override
    public SolverStatus check() {
        try {
            final boolean unsat = solver.isUnsat();
            status = unsat ? SolverStatus.UNSAT : SolverStatus.SAT;
            return status;
        } catch (SolverException | InterruptedException e) {
            throw new JavaSMTSolverException(e);
        }
    }

    @Override
    public void push() {
        assertions.push();
        try {
            solver.push();
        } catch (InterruptedException e) {
            throw new JavaSMTSolverException(e);
        }
    }

    @Override
    public void pop(final int n) {
        assertions.pop(n);
        for (int i = 0; i < n; i++) {
            solver.pop();
        }
        clearState();
    }

    @Override
    public void reset() {
        throw new JavaSMTSolverException("Cannot reset JavaSMT right now.");
    }

    @Override
    public SolverStatus getStatus() {
        checkState(status != null, "Solver status is unknown.");
        return status;
    }

    @Override
    public Valuation getModel() {
        checkState(status == SolverStatus.SAT, "Cannot get model if status is not SAT.");

        if (model == null) {
            model = extractModel();
        }

        return model;
    }

    private Valuation extractModel() {
        assert status == SolverStatus.SAT;
        assert model == null;

        final Model model;
        try {
            model = solver.getModel();
            return new JavaSMTModel(model);
        } catch (SolverException e) {
            throw new JavaSMTSolverException(e);
        }
    }

    @Override
    public Collection> getAssertions() {
        return assertions.toCollection();
    }

    private void clearState() {
        status = null;
        model = null;
        unsatCore = null;
    }

    public SolverContext getContext() {
        return context;
    }

    public BasicProverEnvironment getSolver() {
        return solver;
    }

    @Override
    public void close() {
        context.close();
    }

    ////

    private final class JavaSMTModel extends Valuation {

        private final Model model;
        private final Map, LitExpr> constToExpr;
        private volatile Collection> constDecls = null;

        public JavaSMTModel(final Model model) {
            this.model = model;
            constToExpr = Containers.createMap();
        }

        @Override
        public Collection> getDecls() {
            Collection> result = constDecls;
            if (result == null) {
                result = constDeclsOf(model);
                constDecls = result;
            }
            return result;
        }

        @Override
        public  Optional> eval(final Decl decl) {
            checkNotNull(decl);

            if (!(decl instanceof ConstDecl)) {
                return Optional.empty();
            }

            final ConstDecl constDecl = (ConstDecl) decl;

            LitExpr val = constToExpr.get(constDecl);
            if (val == null) {
                val = extractLiteral(constDecl);
                if (val != null) {
                    constToExpr.put(constDecl, val);
                }
            }

            @SuppressWarnings("unchecked") final LitExpr tVal = (LitExpr) val;
            return Optional.ofNullable(tVal);
        }

        private  LitExpr extractLiteral(final ConstDecl decl) {
            final Formula formula = transformationManager.toSymbol(decl);
            final Type type = decl.getType();
            if (type instanceof FuncType) {
                return extractFuncLiteral(formula);
            } else if (type instanceof ArrayType) {
                return extractArrayLiteral(formula);
            } else if (type instanceof BvType) {
                return extractBvConstLiteral(formula);
            } else if (type instanceof EnumType enumType) {
                return extractEnumLiteral(formula, enumType);
            } else {
                return extractConstLiteral(formula);
            }
        }

        private LitExpr extractFuncLiteral(final Formula formula) {
            final Expr expr = termTransformer.toExpr(formula);
            return (LitExpr) expr;
        }

        private LitExpr extractArrayLiteral(final Formula formula) {
            final Expr expr = termTransformer.toExpr(formula);
            return (LitExpr) expr;
        }

        private LitExpr extractBvConstLiteral(final Formula formula) {
            final Formula term = model.eval(formula);
            if (term == null) {
                return null;
            } else {
                return (BvLitExpr) termTransformer.toExpr(term);
            }
        }

        private LitExpr extractEnumLiteral(Formula formula, EnumType enumType) {
            final Formula term = model.eval(formula);
            if (term == null) {
                return null;
            }
            return enumType.litFromLongName(term.toString());
        }

        private LitExpr extractConstLiteral(final Formula formula) {
            final Formula term = model.eval(formula);
            if (term == null) {
                return null;
            } else {
                return (LitExpr) termTransformer.toExpr(term);
            }
        }

        @Override
        public Map, LitExpr> toMap() {
            getDecls().forEach(this::eval);
            return Collections.unmodifiableMap(constToExpr);
        }

        ////

        private Collection> constDeclsOf(final Model model) {
            final ImmutableList.Builder> builder = ImmutableList.builder();
            for (final Formula symbol : model.asList().stream().map(ValueAssignment::getKey).toList()) {
                if (symbolTable.definesSymbol(symbol)) {
                    final ConstDecl constDecl = symbolTable.getConst(symbol);
                    builder.add(constDecl);
                }
            }
            return builder.build();
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy