Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
hu.bme.mit.theta.solver.javasmt.JavaSMTExprTransformer 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.cache.Cache;
import com.google.common.cache.CacheBuilder;
import hu.bme.mit.theta.common.DispatchTable;
import hu.bme.mit.theta.common.Tuple2;
import hu.bme.mit.theta.common.dsl.Env;
import hu.bme.mit.theta.core.decl.ConstDecl;
import hu.bme.mit.theta.core.decl.Decl;
import hu.bme.mit.theta.core.decl.ParamDecl;
import hu.bme.mit.theta.core.dsl.DeclSymbol;
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.anytype.Dereference;
import hu.bme.mit.theta.core.type.anytype.IteExpr;
import hu.bme.mit.theta.core.type.anytype.RefExpr;
import hu.bme.mit.theta.core.type.arraytype.ArrayEqExpr;
import hu.bme.mit.theta.core.type.arraytype.ArrayInitExpr;
import hu.bme.mit.theta.core.type.arraytype.ArrayLitExpr;
import hu.bme.mit.theta.core.type.arraytype.ArrayNeqExpr;
import hu.bme.mit.theta.core.type.arraytype.ArrayReadExpr;
import hu.bme.mit.theta.core.type.arraytype.ArrayWriteExpr;
import hu.bme.mit.theta.core.type.booltype.AndExpr;
import hu.bme.mit.theta.core.type.booltype.ExistsExpr;
import hu.bme.mit.theta.core.type.booltype.FalseExpr;
import hu.bme.mit.theta.core.type.booltype.ForallExpr;
import hu.bme.mit.theta.core.type.booltype.IffExpr;
import hu.bme.mit.theta.core.type.booltype.ImplyExpr;
import hu.bme.mit.theta.core.type.booltype.NotExpr;
import hu.bme.mit.theta.core.type.booltype.OrExpr;
import hu.bme.mit.theta.core.type.booltype.TrueExpr;
import hu.bme.mit.theta.core.type.booltype.XorExpr;
import hu.bme.mit.theta.core.type.bvtype.BvAddExpr;
import hu.bme.mit.theta.core.type.bvtype.BvAndExpr;
import hu.bme.mit.theta.core.type.bvtype.BvArithShiftRightExpr;
import hu.bme.mit.theta.core.type.bvtype.BvConcatExpr;
import hu.bme.mit.theta.core.type.bvtype.BvEqExpr;
import hu.bme.mit.theta.core.type.bvtype.BvExtractExpr;
import hu.bme.mit.theta.core.type.bvtype.BvLitExpr;
import hu.bme.mit.theta.core.type.bvtype.BvLogicShiftRightExpr;
import hu.bme.mit.theta.core.type.bvtype.BvMulExpr;
import hu.bme.mit.theta.core.type.bvtype.BvNegExpr;
import hu.bme.mit.theta.core.type.bvtype.BvNeqExpr;
import hu.bme.mit.theta.core.type.bvtype.BvNotExpr;
import hu.bme.mit.theta.core.type.bvtype.BvOrExpr;
import hu.bme.mit.theta.core.type.bvtype.BvPosExpr;
import hu.bme.mit.theta.core.type.bvtype.BvRotateLeftExpr;
import hu.bme.mit.theta.core.type.bvtype.BvRotateRightExpr;
import hu.bme.mit.theta.core.type.bvtype.BvSDivExpr;
import hu.bme.mit.theta.core.type.bvtype.BvSExtExpr;
import hu.bme.mit.theta.core.type.bvtype.BvSGeqExpr;
import hu.bme.mit.theta.core.type.bvtype.BvSGtExpr;
import hu.bme.mit.theta.core.type.bvtype.BvSLeqExpr;
import hu.bme.mit.theta.core.type.bvtype.BvSLtExpr;
import hu.bme.mit.theta.core.type.bvtype.BvSModExpr;
import hu.bme.mit.theta.core.type.bvtype.BvSRemExpr;
import hu.bme.mit.theta.core.type.bvtype.BvShiftLeftExpr;
import hu.bme.mit.theta.core.type.bvtype.BvSignChangeExpr;
import hu.bme.mit.theta.core.type.bvtype.BvSubExpr;
import hu.bme.mit.theta.core.type.bvtype.BvUDivExpr;
import hu.bme.mit.theta.core.type.bvtype.BvUGeqExpr;
import hu.bme.mit.theta.core.type.bvtype.BvUGtExpr;
import hu.bme.mit.theta.core.type.bvtype.BvULeqExpr;
import hu.bme.mit.theta.core.type.bvtype.BvULtExpr;
import hu.bme.mit.theta.core.type.bvtype.BvURemExpr;
import hu.bme.mit.theta.core.type.bvtype.BvXorExpr;
import hu.bme.mit.theta.core.type.bvtype.BvZExtExpr;
import hu.bme.mit.theta.core.type.enumtype.EnumEqExpr;
import hu.bme.mit.theta.core.type.enumtype.EnumLitExpr;
import hu.bme.mit.theta.core.type.enumtype.EnumNeqExpr;
import hu.bme.mit.theta.core.type.enumtype.EnumType;
import hu.bme.mit.theta.core.type.fptype.FpAbsExpr;
import hu.bme.mit.theta.core.type.fptype.FpAddExpr;
import hu.bme.mit.theta.core.type.fptype.FpAssignExpr;
import hu.bme.mit.theta.core.type.fptype.FpDivExpr;
import hu.bme.mit.theta.core.type.fptype.FpEqExpr;
import hu.bme.mit.theta.core.type.fptype.FpFromBvExpr;
import hu.bme.mit.theta.core.type.fptype.FpGeqExpr;
import hu.bme.mit.theta.core.type.fptype.FpGtExpr;
import hu.bme.mit.theta.core.type.fptype.FpIsInfiniteExpr;
import hu.bme.mit.theta.core.type.fptype.FpIsNanExpr;
import hu.bme.mit.theta.core.type.fptype.FpLeqExpr;
import hu.bme.mit.theta.core.type.fptype.FpLitExpr;
import hu.bme.mit.theta.core.type.fptype.FpLtExpr;
import hu.bme.mit.theta.core.type.fptype.FpMaxExpr;
import hu.bme.mit.theta.core.type.fptype.FpMinExpr;
import hu.bme.mit.theta.core.type.fptype.FpMulExpr;
import hu.bme.mit.theta.core.type.fptype.FpNegExpr;
import hu.bme.mit.theta.core.type.fptype.FpNeqExpr;
import hu.bme.mit.theta.core.type.fptype.FpPosExpr;
import hu.bme.mit.theta.core.type.fptype.FpRemExpr;
import hu.bme.mit.theta.core.type.fptype.FpRoundToIntegralExpr;
import hu.bme.mit.theta.core.type.fptype.FpRoundingMode;
import hu.bme.mit.theta.core.type.fptype.FpSqrtExpr;
import hu.bme.mit.theta.core.type.fptype.FpSubExpr;
import hu.bme.mit.theta.core.type.fptype.FpToBvExpr;
import hu.bme.mit.theta.core.type.fptype.FpToFpExpr;
import hu.bme.mit.theta.core.type.functype.FuncAppExpr;
import hu.bme.mit.theta.core.type.functype.FuncType;
import hu.bme.mit.theta.core.type.inttype.IntAddExpr;
import hu.bme.mit.theta.core.type.inttype.IntDivExpr;
import hu.bme.mit.theta.core.type.inttype.IntEqExpr;
import hu.bme.mit.theta.core.type.inttype.IntGeqExpr;
import hu.bme.mit.theta.core.type.inttype.IntGtExpr;
import hu.bme.mit.theta.core.type.inttype.IntLeqExpr;
import hu.bme.mit.theta.core.type.inttype.IntLitExpr;
import hu.bme.mit.theta.core.type.inttype.IntLtExpr;
import hu.bme.mit.theta.core.type.inttype.IntModExpr;
import hu.bme.mit.theta.core.type.inttype.IntMulExpr;
import hu.bme.mit.theta.core.type.inttype.IntNegExpr;
import hu.bme.mit.theta.core.type.inttype.IntNeqExpr;
import hu.bme.mit.theta.core.type.inttype.IntPosExpr;
import hu.bme.mit.theta.core.type.inttype.IntRemExpr;
import hu.bme.mit.theta.core.type.inttype.IntSubExpr;
import hu.bme.mit.theta.core.type.inttype.IntToRatExpr;
import hu.bme.mit.theta.core.type.rattype.RatAddExpr;
import hu.bme.mit.theta.core.type.rattype.RatDivExpr;
import hu.bme.mit.theta.core.type.rattype.RatEqExpr;
import hu.bme.mit.theta.core.type.rattype.RatGeqExpr;
import hu.bme.mit.theta.core.type.rattype.RatGtExpr;
import hu.bme.mit.theta.core.type.rattype.RatLeqExpr;
import hu.bme.mit.theta.core.type.rattype.RatLitExpr;
import hu.bme.mit.theta.core.type.rattype.RatLtExpr;
import hu.bme.mit.theta.core.type.rattype.RatMulExpr;
import hu.bme.mit.theta.core.type.rattype.RatNegExpr;
import hu.bme.mit.theta.core.type.rattype.RatNeqExpr;
import hu.bme.mit.theta.core.type.rattype.RatPosExpr;
import hu.bme.mit.theta.core.type.rattype.RatSubExpr;
import hu.bme.mit.theta.core.type.rattype.RatToIntExpr;
import hu.bme.mit.theta.core.utils.BvUtils;
import org.sosy_lab.java_smt.api.ArrayFormula;
import org.sosy_lab.java_smt.api.ArrayFormulaManager;
import org.sosy_lab.java_smt.api.BitvectorFormula;
import org.sosy_lab.java_smt.api.BitvectorFormulaManager;
import org.sosy_lab.java_smt.api.BooleanFormula;
import org.sosy_lab.java_smt.api.BooleanFormulaManager;
import org.sosy_lab.java_smt.api.EnumerationFormula;
import org.sosy_lab.java_smt.api.EnumerationFormulaManager;
import org.sosy_lab.java_smt.api.FloatingPointFormula;
import org.sosy_lab.java_smt.api.FloatingPointFormulaManager;
import org.sosy_lab.java_smt.api.FloatingPointRoundingMode;
import org.sosy_lab.java_smt.api.Formula;
import org.sosy_lab.java_smt.api.FormulaType;
import org.sosy_lab.java_smt.api.FormulaType.FloatingPointType;
import org.sosy_lab.java_smt.api.FunctionDeclaration;
import org.sosy_lab.java_smt.api.IntegerFormulaManager;
import org.sosy_lab.java_smt.api.NumeralFormula;
import org.sosy_lab.java_smt.api.NumeralFormula.IntegerFormula;
import org.sosy_lab.java_smt.api.NumeralFormula.RationalFormula;
import org.sosy_lab.java_smt.api.QuantifiedFormulaManager;
import org.sosy_lab.java_smt.api.RationalFormulaManager;
import org.sosy_lab.java_smt.api.SolverContext;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.google.common.base.Preconditions.checkState;
import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int;
import static hu.bme.mit.theta.core.utils.ExprUtils.extractFuncAndArgs;
final class JavaSMTExprTransformer {
private static final int CACHE_SIZE = 1000;
private final BooleanFormulaManager booleanFormulaManager;
private final IntegerFormulaManager integerFormulaManager;
private final RationalFormulaManager rationalFormulaManager;
private final BitvectorFormulaManager bitvectorFormulaManager;
private final FloatingPointFormulaManager floatingPointFormulaManager;
private final QuantifiedFormulaManager quantifiedFormulaManager;
private final ArrayFormulaManager arrayFormulaManager;
private final EnumerationFormulaManager enumFormulaManager;
private final JavaSMTTransformationManager transformer;
private final JavaSMTSymbolTable symbolTable;
private final SolverContext context;
private final Cache, Formula> exprToTerm;
private final DispatchTable table;
private final Env env;
public JavaSMTExprTransformer(final JavaSMTTransformationManager transformer, final JavaSMTSymbolTable symbolTable, final SolverContext context) {
this.symbolTable = symbolTable;
this.context = context;
this.transformer = transformer;
this.env = new Env();
booleanFormulaManager = orElseNull(() -> context.getFormulaManager().getBooleanFormulaManager());
integerFormulaManager = orElseNull(() -> context.getFormulaManager().getIntegerFormulaManager());
rationalFormulaManager = orElseNull(() -> context.getFormulaManager().getRationalFormulaManager());
bitvectorFormulaManager = orElseNull(() -> context.getFormulaManager().getBitvectorFormulaManager());
floatingPointFormulaManager = orElseNull(() -> context.getFormulaManager().getFloatingPointFormulaManager());
quantifiedFormulaManager = orElseNull(() -> context.getFormulaManager().getQuantifiedFormulaManager());
arrayFormulaManager = orElseNull(() -> context.getFormulaManager().getArrayFormulaManager());
enumFormulaManager = orElseNull(() -> context.getFormulaManager().getEnumerationFormulaManager());
exprToTerm = CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).build();
table = DispatchTable.builder()
// General
.addCase(RefExpr.class, this::transformRef)
.addCase(IteExpr.class, this::transformIte)
// Boolean
.addCase(FalseExpr.class, this::transformFalse)
.addCase(TrueExpr.class, this::transformTrue)
.addCase(NotExpr.class, this::transformNot)
.addCase(ImplyExpr.class, this::transformImply)
.addCase(IffExpr.class, this::transformIff)
.addCase(XorExpr.class, this::transformXor)
.addCase(AndExpr.class, this::transformAnd)
.addCase(OrExpr.class, this::transformOr)
.addCase(ExistsExpr.class, this::transformExists)
.addCase(ForallExpr.class, this::transformForall)
// Rationals
.addCase(RatLitExpr.class, this::transformRatLit)
.addCase(RatAddExpr.class, this::transformRatAdd)
.addCase(RatSubExpr.class, this::transformRatSub)
.addCase(RatPosExpr.class, this::transformRatPos)
.addCase(RatNegExpr.class, this::transformRatNeg)
.addCase(RatMulExpr.class, this::transformRatMul)
.addCase(RatDivExpr.class, this::transformRatDiv)
.addCase(RatEqExpr.class, this::transformRatEq)
.addCase(RatNeqExpr.class, this::transformRatNeq)
.addCase(RatGeqExpr.class, this::transformRatGeq)
.addCase(RatGtExpr.class, this::transformRatGt)
.addCase(RatLeqExpr.class, this::transformRatLeq)
.addCase(RatLtExpr.class, this::transformRatLt)
.addCase(RatToIntExpr.class, this::transformRatToInt)
// Integers
.addCase(IntLitExpr.class, this::transformIntLit)
.addCase(IntAddExpr.class, this::transformIntAdd)
.addCase(IntSubExpr.class, this::transformIntSub)
.addCase(IntPosExpr.class, this::transformIntPos)
.addCase(IntNegExpr.class, this::transformIntNeg)
.addCase(IntMulExpr.class, this::transformIntMul)
.addCase(IntDivExpr.class, this::transformIntDiv)
.addCase(IntModExpr.class, this::transformIntMod)
.addCase(IntRemExpr.class, this::transformIntRem)
.addCase(IntEqExpr.class, this::transformIntEq)
.addCase(IntNeqExpr.class, this::transformIntNeq)
.addCase(IntGeqExpr.class, this::transformIntGeq)
.addCase(IntGtExpr.class, this::transformIntGt)
.addCase(IntLeqExpr.class, this::transformIntLeq)
.addCase(IntLtExpr.class, this::transformIntLt)
.addCase(IntToRatExpr.class, this::transformIntToRat)
// Bitvectors
.addCase(BvLitExpr.class, this::transformBvLit)
.addCase(BvConcatExpr.class, this::transformBvConcat)
.addCase(BvExtractExpr.class, this::transformBvExtract)
.addCase(BvZExtExpr.class, this::transformBvZExt)
.addCase(BvSExtExpr.class, this::transformBvSExt)
.addCase(BvAddExpr.class, this::transformBvAdd)
.addCase(BvSubExpr.class, this::transformBvSub)
.addCase(BvPosExpr.class, this::transformBvPos)
.addCase(BvSignChangeExpr.class, this::transformBvSignChange)
.addCase(BvNegExpr.class, this::transformBvNeg)
.addCase(BvMulExpr.class, this::transformBvMul)
.addCase(BvUDivExpr.class, this::transformBvUDiv)
.addCase(BvSDivExpr.class, this::transformBvSDiv)
.addCase(BvSModExpr.class, this::transformBvSMod)
.addCase(BvURemExpr.class, this::transformBvURem)
.addCase(BvSRemExpr.class, this::transformBvSRem)
.addCase(BvAndExpr.class, this::transformBvAnd)
.addCase(BvOrExpr.class, this::transformBvOr)
.addCase(BvXorExpr.class, this::transformBvXor)
.addCase(BvNotExpr.class, this::transformBvNot)
.addCase(BvShiftLeftExpr.class, this::transformBvShiftLeft)
.addCase(BvArithShiftRightExpr.class, this::transformBvArithShiftRight)
.addCase(BvLogicShiftRightExpr.class, this::transformBvLogicShiftRight)
.addCase(BvRotateLeftExpr.class, this::transformBvRotateLeft)
.addCase(BvRotateRightExpr.class, this::transformBvRotateRight)
.addCase(BvEqExpr.class, this::transformBvEq)
.addCase(BvNeqExpr.class, this::transformBvNeq)
.addCase(BvUGeqExpr.class, this::transformBvUGeq)
.addCase(BvUGtExpr.class, this::transformBvUGt)
.addCase(BvULeqExpr.class, this::transformBvULeq)
.addCase(BvULtExpr.class, this::transformBvULt)
.addCase(BvSGeqExpr.class, this::transformBvSGeq)
.addCase(BvSGtExpr.class, this::transformBvSGt)
.addCase(BvSLeqExpr.class, this::transformBvSLeq)
.addCase(BvSLtExpr.class, this::transformBvSLt)
// Floating points
.addCase(FpLitExpr.class, this::transformFpLit)
.addCase(FpAddExpr.class, this::transformFpAdd)
.addCase(FpSubExpr.class, this::transformFpSub)
.addCase(FpPosExpr.class, this::transformFpPos)
.addCase(FpNegExpr.class, this::transformFpNeg)
.addCase(FpMulExpr.class, this::transformFpMul)
.addCase(FpDivExpr.class, this::transformFpDiv)
.addCase(FpEqExpr.class, this::transformFpEq)
.addCase(FpAssignExpr.class, this::transformFpAssign)
.addCase(FpGeqExpr.class, this::transformFpGeq)
.addCase(FpLeqExpr.class, this::transformFpLeq)
.addCase(FpGtExpr.class, this::transformFpGt)
.addCase(FpLtExpr.class, this::transformFpLt)
.addCase(FpNeqExpr.class, this::transformFpNeq)
.addCase(FpAbsExpr.class, this::transformFpAbs)
.addCase(FpRoundToIntegralExpr.class, this::transformFpRoundToIntegral)
.addCase(FpMaxExpr.class, this::transformFpMax)
.addCase(FpMinExpr.class, this::transformFpMin)
.addCase(FpSqrtExpr.class, this::transformFpSqrt)
.addCase(FpRemExpr.class, this::transformFpRem)
.addCase(FpIsNanExpr.class, this::transformFpIsNan)
.addCase(FpIsInfiniteExpr.class, this::transformFpIsInfinite)
.addCase(FpFromBvExpr.class, this::transformFpFromBv)
.addCase(FpToBvExpr.class, this::transformFpToBv)
.addCase(FpToFpExpr.class, this::transformFpToFp)
// Functions
.addCase(FuncAppExpr.class, this::transformFuncApp)
// Arrays
.addCase(ArrayReadExpr.class, this::transformArrayRead)
.addCase(ArrayWriteExpr.class, this::transformArrayWrite)
.addCase(ArrayEqExpr.class, this::transformArrayEq)
.addCase(ArrayNeqExpr.class, this::transformArrayNeq)
.addCase(ArrayLitExpr.class, this::transformArrayLit)
.addCase(ArrayInitExpr.class, this::transformArrayInit)
.addCase(Dereference.class, this::transformDereference)
// Enums
.addCase(EnumLitExpr.class, this::transformEnumLit)
.addCase(EnumNeqExpr.class, this::transformEnumNeq)
.addCase(EnumEqExpr.class, this::transformEnumEq)
.build();
}
private static T orElseNull(Supplier supplier) {
try {
return supplier.get();
} catch (UnsupportedOperationException uoe) {
return null;
}
}
private static FloatingPointRoundingMode transformRoundingMode(final FpRoundingMode fpRoundingMode) {
return switch (fpRoundingMode) {
case RNE -> FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN;
case RNA -> FloatingPointRoundingMode.NEAREST_TIES_AWAY;
case RTP -> FloatingPointRoundingMode.TOWARD_POSITIVE;
case RTN -> FloatingPointRoundingMode.TOWARD_NEGATIVE;
case RTZ -> FloatingPointRoundingMode.TOWARD_ZERO;
};
}
////
/*
* General
*/
public Formula toTerm(final Expr> expr) {
try {
return exprToTerm.get(expr, () -> table.dispatch(expr));
} catch (final ExecutionException e) {
throw new AssertionError("Unhandled case: " + expr, e);
}
}
private Formula transformRef(final RefExpr> expr) {
final Decl> decl = expr.getDecl();
if (decl instanceof ConstDecl) {
return transformer.toSymbol(decl);
} else if (decl instanceof ParamDecl) {
return (Formula) env.eval(DeclSymbol.of(decl));
} else {
throw new UnsupportedOperationException(
"Cannot transform reference for declaration: " + decl);
}
}
/*
* Booleans
*/
private Formula transformIte(final IteExpr> expr) {
final BooleanFormula condTerm = (BooleanFormula) toTerm(expr.getCond());
final Formula thenTerm = toTerm(expr.getThen());
final Formula elzeTerm = toTerm(expr.getElse());
return booleanFormulaManager.ifThenElse(condTerm, thenTerm, elzeTerm);
}
private Formula transformFalse(final FalseExpr expr) {
return booleanFormulaManager.makeFalse();
}
private Formula transformTrue(final TrueExpr expr) {
return booleanFormulaManager.makeTrue();
}
private Formula transformNot(final NotExpr expr) {
final BooleanFormula opTerm = (BooleanFormula) toTerm(expr.getOp());
return booleanFormulaManager.not(opTerm);
}
private Formula transformImply(final ImplyExpr expr) {
final BooleanFormula leftOpTerm = (BooleanFormula) toTerm(expr.getLeftOp());
final BooleanFormula rightOpTerm = (BooleanFormula) toTerm(expr.getRightOp());
return booleanFormulaManager.implication(leftOpTerm, rightOpTerm);
}
private Formula transformIff(final IffExpr expr) {
final BooleanFormula leftOpTerm = (BooleanFormula) toTerm(expr.getLeftOp());
final BooleanFormula rightOpTerm = (BooleanFormula) toTerm(expr.getRightOp());
return booleanFormulaManager.equivalence(leftOpTerm, rightOpTerm);
}
private Formula transformXor(final XorExpr expr) {
final BooleanFormula leftOpTerm = (BooleanFormula) toTerm(expr.getLeftOp());
final BooleanFormula rightOpTerm = (BooleanFormula) toTerm(expr.getRightOp());
return booleanFormulaManager.xor(leftOpTerm, rightOpTerm);
}
private Formula transformAnd(final AndExpr expr) {
final List opTerms = expr.getOps().stream()
.map(e -> (BooleanFormula) toTerm(e))
.toList();
return booleanFormulaManager.and(opTerms);
}
private Formula transformOr(final OrExpr expr) {
final List opTerms = expr.getOps().stream()
.map(e -> (BooleanFormula) toTerm(e))
.toList();
return booleanFormulaManager.or(opTerms);
}
private Formula transformExists(final ExistsExpr expr) {
env.push();
final List paramTerms = transformParamDecls(expr.getParamDecls());
final BooleanFormula opTerm = (BooleanFormula) toTerm(expr.getOp());
final BooleanFormula result = quantifiedFormulaManager.exists(paramTerms, opTerm);
env.pop();
return result;
}
private Formula transformForall(final ForallExpr expr) {
env.push();
final List paramTerms = transformParamDecls(expr.getParamDecls());
final BooleanFormula opTerm = (BooleanFormula) toTerm(expr.getOp());
final BooleanFormula result = quantifiedFormulaManager.forall(paramTerms, opTerm);
env.pop();
return result;
}
/*
* Rationals
*/
private List transformParamDecls(final List> paramDecls) {
final List paramTerms = new ArrayList<>(paramDecls.size());
for (final ParamDecl> paramDecl : paramDecls) {
final Formula paramSymbol = transformParamDecl(paramDecl);
paramTerms.add(paramSymbol);
env.define(DeclSymbol.of(paramDecl), paramSymbol);
}
return paramTerms;
}
private Formula transformParamDecl(final ParamDecl> paramDecl) {
final Type type = paramDecl.getType();
if (type instanceof FuncType, ?>) {
throw new UnsupportedOperationException("Only simple types are supported");
} else {
final FormulaType> sort = transformer.toSort(type);
return context.getFormulaManager().makeVariable(sort, paramDecl.getName());
}
}
private Formula transformRatLit(final RatLitExpr expr) {
var num = rationalFormulaManager.makeNumber(expr.getNum().toString());
var denom = rationalFormulaManager.makeNumber(expr.getDenom().toString());
return rationalFormulaManager.divide(num, denom);
}
private Formula transformRatAdd(final RatAddExpr expr) {
final List opTerms = expr.getOps().stream()
.map(e -> (RationalFormula) toTerm(e))
.toList();
return opTerms.stream().reduce(rationalFormulaManager::add).get();
}
private Formula transformRatSub(final RatSubExpr expr) {
final RationalFormula leftOpTerm = (RationalFormula) toTerm(
expr.getLeftOp());
final RationalFormula rightOpTerm = (RationalFormula) toTerm(
expr.getRightOp());
return rationalFormulaManager.subtract(leftOpTerm, rightOpTerm);
}
private Formula transformRatPos(final RatPosExpr expr) {
return toTerm(expr.getOp());
}
private Formula transformRatNeg(final RatNegExpr expr) {
final RationalFormula opTerm = (RationalFormula) toTerm(expr.getOp());
return rationalFormulaManager.negate(opTerm);
}
private Formula transformRatMul(final RatMulExpr expr) {
final List opTerms = expr.getOps().stream()
.map(e -> (RationalFormula) toTerm(e))
.toList();
return opTerms.stream().reduce(rationalFormulaManager::multiply).get();
}
private Formula transformRatDiv(final RatDivExpr expr) {
final RationalFormula leftOpTerm = (RationalFormula) toTerm(
expr.getLeftOp());
final RationalFormula rightOpTerm = (RationalFormula) toTerm(
expr.getRightOp());
return rationalFormulaManager.divide(leftOpTerm, rightOpTerm);
}
private Formula transformRatEq(final RatEqExpr expr) {
final RationalFormula leftOpTerm = (RationalFormula) toTerm(expr.getLeftOp());
final RationalFormula rightOpTerm = (RationalFormula) toTerm(expr.getRightOp());
return rationalFormulaManager.equal(leftOpTerm, rightOpTerm);
}
private Formula transformRatNeq(final RatNeqExpr expr) {
final RationalFormula leftOpTerm = (RationalFormula) toTerm(expr.getLeftOp());
final RationalFormula rightOpTerm = (RationalFormula) toTerm(expr.getRightOp());
return booleanFormulaManager.not(rationalFormulaManager.equal(leftOpTerm, rightOpTerm));
}
private Formula transformRatGeq(final RatGeqExpr expr) {
final RationalFormula leftOpTerm = (RationalFormula) toTerm(
expr.getLeftOp());
final RationalFormula rightOpTerm = (RationalFormula) toTerm(
expr.getRightOp());
return rationalFormulaManager.greaterOrEquals(leftOpTerm, rightOpTerm);
}
private Formula transformRatGt(final RatGtExpr expr) {
final RationalFormula leftOpTerm = (RationalFormula) toTerm(
expr.getLeftOp());
final RationalFormula rightOpTerm = (RationalFormula) toTerm(
expr.getRightOp());
return rationalFormulaManager.greaterThan(leftOpTerm, rightOpTerm);
}
/*
* Integers
*/
private Formula transformRatLeq(final RatLeqExpr expr) {
final RationalFormula leftOpTerm = (RationalFormula) toTerm(
expr.getLeftOp());
final RationalFormula rightOpTerm = (RationalFormula) toTerm(
expr.getRightOp());
return rationalFormulaManager.lessOrEquals(leftOpTerm, rightOpTerm);
}
private Formula transformRatLt(final RatLtExpr expr) {
final RationalFormula leftOpTerm = (RationalFormula) toTerm(
expr.getLeftOp());
final RationalFormula rightOpTerm = (RationalFormula) toTerm(
expr.getRightOp());
return rationalFormulaManager.lessThan(leftOpTerm, rightOpTerm);
}
private Formula transformRatToInt(final RatToIntExpr expr) {
return rationalFormulaManager.floor((NumeralFormula) toTerm(expr.getOp()));
}
private Formula transformIntLit(final IntLitExpr expr) {
return integerFormulaManager.makeNumber(expr.getValue().toString());
}
private Formula transformIntAdd(final IntAddExpr expr) {
final List opTerms = expr.getOps().stream()
.map(e -> (IntegerFormula) toTerm(e))
.toList();
return opTerms.stream().reduce(integerFormulaManager::add).get();
}
private Formula transformIntSub(final IntSubExpr expr) {
final IntegerFormula leftOpTerm = (IntegerFormula) toTerm(
expr.getLeftOp());
final IntegerFormula rightOpTerm = (IntegerFormula) toTerm(
expr.getRightOp());
return integerFormulaManager.subtract(leftOpTerm, rightOpTerm);
}
private Formula transformIntPos(final IntPosExpr expr) {
return toTerm(expr.getOp());
}
private Formula transformIntNeg(final IntNegExpr expr) {
final IntegerFormula opTerm = (IntegerFormula) toTerm(expr.getOp());
return integerFormulaManager.negate(opTerm);
}
private Formula transformIntMul(final IntMulExpr expr) {
final List opTerms = expr.getOps().stream()
.map(e -> (IntegerFormula) toTerm(e))
.toList();
return opTerms.stream().reduce(integerFormulaManager::multiply).get();
}
private Formula transformIntDiv(final IntDivExpr expr) {
final IntegerFormula leftOpTerm = (IntegerFormula) toTerm(
expr.getLeftOp());
final IntegerFormula rightOpTerm = (IntegerFormula) toTerm(
expr.getRightOp());
return integerFormulaManager.divide(leftOpTerm, rightOpTerm);
}
private Formula transformIntMod(final IntModExpr expr) {
final IntegerFormula leftOpTerm = (IntegerFormula) toTerm(
expr.getLeftOp());
final IntegerFormula rightOpTerm = (IntegerFormula) toTerm(
expr.getRightOp());
return integerFormulaManager.modulo(leftOpTerm, rightOpTerm);
}
private Formula transformIntRem(final IntRemExpr expr) {
final IntegerFormula leftOpTerm = (IntegerFormula) toTerm(
expr.getLeftOp());
final IntegerFormula rightOpTerm = (IntegerFormula) toTerm(
expr.getRightOp());
return booleanFormulaManager.ifThenElse(
integerFormulaManager.greaterOrEquals(rightOpTerm, integerFormulaManager.makeNumber(0)),
integerFormulaManager.modulo(leftOpTerm, rightOpTerm),
integerFormulaManager.negate(integerFormulaManager.modulo(leftOpTerm, rightOpTerm))
);
}
private Formula transformIntEq(final IntEqExpr expr) {
final IntegerFormula leftOpTerm = (IntegerFormula) toTerm(expr.getLeftOp());
final IntegerFormula rightOpTerm = (IntegerFormula) toTerm(expr.getRightOp());
return integerFormulaManager.equal(leftOpTerm, rightOpTerm);
}
private Formula transformIntNeq(final IntNeqExpr expr) {
final IntegerFormula leftOpTerm = (IntegerFormula) toTerm(expr.getLeftOp());
final IntegerFormula rightOpTerm = (IntegerFormula) toTerm(expr.getRightOp());
return booleanFormulaManager.not(integerFormulaManager.equal(leftOpTerm, rightOpTerm));
}
private Formula transformIntGeq(final IntGeqExpr expr) {
final IntegerFormula leftOpTerm = (IntegerFormula) toTerm(
expr.getLeftOp());
final IntegerFormula rightOpTerm = (IntegerFormula) toTerm(
expr.getRightOp());
return integerFormulaManager.greaterOrEquals(leftOpTerm, rightOpTerm);
}
private Formula transformIntGt(final IntGtExpr expr) {
final IntegerFormula leftOpTerm = (IntegerFormula) toTerm(
expr.getLeftOp());
final IntegerFormula rightOpTerm = (IntegerFormula) toTerm(
expr.getRightOp());
return integerFormulaManager.greaterThan(leftOpTerm, rightOpTerm);
}
private Formula transformIntLeq(final IntLeqExpr expr) {
final IntegerFormula leftOpTerm = (IntegerFormula) toTerm(
expr.getLeftOp());
final IntegerFormula rightOpTerm = (IntegerFormula) toTerm(
expr.getRightOp());
return integerFormulaManager.lessOrEquals(leftOpTerm, rightOpTerm);
}
/*
* Bitvectors
*/
private Formula transformIntLt(final IntLtExpr expr) {
final IntegerFormula leftOpTerm = (IntegerFormula) toTerm(
expr.getLeftOp());
final IntegerFormula rightOpTerm = (IntegerFormula) toTerm(
expr.getRightOp());
return integerFormulaManager.lessThan(leftOpTerm, rightOpTerm);
}
private Formula transformIntToRat(final IntToRatExpr expr) {
return rationalFormulaManager.sum(List.of((IntegerFormula) toTerm(expr.getOp())));
}
private Formula transformBvLit(final BvLitExpr expr) {
return bitvectorFormulaManager.makeBitvector(
expr.getType().getSize(),
BvUtils.neutralBvLitExprToBigInteger(expr));
}
private Formula transformBvEq(final BvEqExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.equal(leftOpTerm, rightOpTerm);
}
private Formula transformBvNeq(final BvNeqExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return booleanFormulaManager.not(bitvectorFormulaManager.equal(leftOpTerm, rightOpTerm));
}
private Formula transformBvConcat(final BvConcatExpr expr) {
final BitvectorFormula[] opTerms = expr.getOps().stream()
.map(e -> (BitvectorFormula) toTerm(e))
.toArray(BitvectorFormula[]::new);
return Stream.of(opTerms).skip(1).reduce(opTerms[0], bitvectorFormulaManager::concat);
}
private Formula transformBvExtract(final BvExtractExpr expr) {
final BitvectorFormula bitvecTerm = (BitvectorFormula) toTerm(expr.getBitvec());
final int from = expr.getFrom().getValue().intValue();
final int until = expr.getUntil().getValue().intValue();
return bitvectorFormulaManager.extract(bitvecTerm, until - 1, from);
}
private Formula transformBvZExt(final BvZExtExpr expr) {
final BitvectorFormula bitvecTerm = (BitvectorFormula) toTerm(expr.getOp());
final int extendWith = expr.getExtendType().getSize() - expr.getOp().getType().getSize();
return bitvectorFormulaManager.extend(bitvecTerm, extendWith, false);
}
private Formula transformBvSExt(final BvSExtExpr expr) {
final BitvectorFormula bitvecTerm = (BitvectorFormula) toTerm(expr.getOp());
final int extendWith = expr.getExtendType().getSize() - expr.getOp().getType().getSize();
return bitvectorFormulaManager.extend(bitvecTerm, extendWith, true);
}
private Formula transformBvAdd(final BvAddExpr expr) {
final BitvectorFormula[] opTerms = expr.getOps().stream()
.map(e -> (BitvectorFormula) toTerm(e))
.toArray(BitvectorFormula[]::new);
return Stream.of(opTerms).skip(1).reduce(opTerms[0], bitvectorFormulaManager::add);
}
private Formula transformBvSub(final BvSubExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.subtract(leftOpTerm, rightOpTerm);
}
private Formula transformBvPos(final BvPosExpr expr) {
return toTerm(expr.getOp());
}
private Formula transformBvSignChange(final BvSignChangeExpr expr) {
return (BitvectorFormula) toTerm(expr.getOp());
}
private Formula transformBvNeg(final BvNegExpr expr) {
final BitvectorFormula opTerm = (BitvectorFormula) toTerm(expr.getOp());
return bitvectorFormulaManager.negate(opTerm);
}
private Formula transformBvMul(final BvMulExpr expr) {
final BitvectorFormula[] opTerms = expr.getOps().stream()
.map(e -> (BitvectorFormula) toTerm(e))
.toArray(BitvectorFormula[]::new);
return Stream.of(opTerms).skip(1).reduce(opTerms[0], bitvectorFormulaManager::multiply);
}
private Formula transformBvUDiv(final BvUDivExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.divide(leftOpTerm, rightOpTerm, false);
}
private Formula transformBvSDiv(final BvSDivExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.divide(leftOpTerm, rightOpTerm, true);
}
private Formula transformBvSMod(final BvSModExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.smod(leftOpTerm, rightOpTerm);
}
private Formula transformBvURem(final BvURemExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.rem(leftOpTerm, rightOpTerm, false);
}
private Formula transformBvSRem(final BvSRemExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.rem(leftOpTerm, rightOpTerm, true);
}
private Formula transformBvAnd(final BvAndExpr expr) {
final BitvectorFormula[] opTerms = expr.getOps().stream()
.map(e -> (BitvectorFormula) toTerm(e))
.toArray(BitvectorFormula[]::new);
return Stream.of(opTerms).skip(1).reduce(opTerms[0], bitvectorFormulaManager::and);
}
private Formula transformBvOr(final BvOrExpr expr) {
final BitvectorFormula[] opTerms = expr.getOps().stream()
.map(e -> (BitvectorFormula) toTerm(e))
.toArray(BitvectorFormula[]::new);
return Stream.of(opTerms).skip(1).reduce(opTerms[0], bitvectorFormulaManager::or);
}
private Formula transformBvXor(final BvXorExpr expr) {
final BitvectorFormula[] opTerms = expr.getOps().stream()
.map(e -> (BitvectorFormula) toTerm(e))
.toArray(BitvectorFormula[]::new);
return Stream.of(opTerms).skip(1).reduce(opTerms[0], bitvectorFormulaManager::xor);
}
private Formula transformBvNot(final BvNotExpr expr) {
final BitvectorFormula opTerm = (BitvectorFormula) toTerm(expr.getOp());
return bitvectorFormulaManager.not(opTerm);
}
private Formula transformBvShiftLeft(final BvShiftLeftExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.shiftLeft(leftOpTerm, rightOpTerm);
}
private Formula transformBvArithShiftRight(final BvArithShiftRightExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.shiftRight(leftOpTerm, rightOpTerm, true);
}
private Formula transformBvLogicShiftRight(final BvLogicShiftRightExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.shiftRight(leftOpTerm, rightOpTerm, false);
}
private Formula transformBvRotateLeft(final BvRotateLeftExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.rotateLeft(leftOpTerm, rightOpTerm);
}
private Formula transformBvRotateRight(final BvRotateRightExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.rotateRight(leftOpTerm, rightOpTerm);
}
private Formula transformBvUGeq(final BvUGeqExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.greaterOrEquals(leftOpTerm, rightOpTerm, false);
}
private Formula transformBvUGt(final BvUGtExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.greaterThan(leftOpTerm, rightOpTerm, false);
}
private Formula transformBvULeq(final BvULeqExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.lessOrEquals(leftOpTerm, rightOpTerm, false);
}
private Formula transformBvULt(final BvULtExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.lessThan(leftOpTerm, rightOpTerm, false);
}
private Formula transformBvSGeq(final BvSGeqExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.greaterOrEquals(leftOpTerm, rightOpTerm, true);
}
private Formula transformBvSGt(final BvSGtExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.greaterThan(leftOpTerm, rightOpTerm, true);
}
/*
* Floating points
*/
private Formula transformBvSLeq(final BvSLeqExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.lessOrEquals(leftOpTerm, rightOpTerm, true);
}
private Formula transformBvSLt(final BvSLtExpr expr) {
final BitvectorFormula leftOpTerm = (BitvectorFormula) toTerm(expr.getLeftOp());
final BitvectorFormula rightOpTerm = (BitvectorFormula) toTerm(expr.getRightOp());
return bitvectorFormulaManager.lessThan(leftOpTerm, rightOpTerm, true);
}
private Formula transformFpLit(final FpLitExpr expr) {
return floatingPointFormulaManager.makeNumber(
BvUtils.neutralBvLitExprToBigInteger(expr.getExponent()),
BvUtils.neutralBvLitExprToBigInteger(expr.getSignificand()),
expr.getHidden(),
FloatingPointType.getFloatingPointType(expr.getType().getExponent(), expr.getType().getSignificand() - 1)
);
}
private Formula transformFpAdd(final FpAddExpr expr) {
final FloatingPointFormula[] opTerms = expr.getOps().stream()
.map(e -> (FloatingPointFormula) toTerm(e))
.toArray(FloatingPointFormula[]::new);
return Stream.of(opTerms).skip(1).reduce(opTerms[0],
(op1, op2) -> floatingPointFormulaManager.add(op1, op2,
transformFpRoundingMode(expr.getRoundingMode())
));
}
private Formula transformFpSub(final FpSubExpr expr) {
final FloatingPointFormula leftOpTerm = (FloatingPointFormula) toTerm(expr.getLeftOp());
final FloatingPointFormula rightOpTerm = (FloatingPointFormula) toTerm(expr.getRightOp());
return floatingPointFormulaManager.subtract(leftOpTerm, rightOpTerm, transformFpRoundingMode(expr.getRoundingMode()));
}
private Formula transformFpPos(final FpPosExpr expr) {
return toTerm(expr.getOp());
}
private Formula transformFpNeg(final FpNegExpr expr) {
final FloatingPointFormula opTerm = (FloatingPointFormula) toTerm(expr.getOp());
return floatingPointFormulaManager.negate(opTerm);
}
private Formula transformFpAbs(final FpAbsExpr expr) {
final FloatingPointFormula opTerm = (FloatingPointFormula) toTerm(expr.getOp());
return floatingPointFormulaManager.abs(opTerm);
}
private Formula transformFpIsNan(final FpIsNanExpr expr) {
final FloatingPointFormula opTerm = (FloatingPointFormula) toTerm(expr.getOp());
return floatingPointFormulaManager.isNaN(opTerm);
}
private Formula transformFpIsInfinite(final FpIsInfiniteExpr expr) {
final FloatingPointFormula opTerm = (FloatingPointFormula) toTerm(expr.getOp());
return floatingPointFormulaManager.isInfinity(opTerm);
}
private Formula transformFpSqrt(final FpSqrtExpr expr) {
final FloatingPointFormula opTerm = (FloatingPointFormula) toTerm(expr.getOp());
return floatingPointFormulaManager.sqrt(opTerm, transformFpRoundingMode(expr.getRoundingMode()));
}
private Formula transformFpRoundToIntegral(final FpRoundToIntegralExpr expr) {
final FloatingPointFormula opTerm = (FloatingPointFormula) toTerm(expr.getOp());
return floatingPointFormulaManager.round(opTerm, transformFpRoundingMode(expr.getRoundingMode()));
}
private Formula transformFpMul(final FpMulExpr expr) {
final FloatingPointFormula[] opTerms = expr.getOps().stream()
.map(e -> (FloatingPointFormula) toTerm(e))
.toArray(FloatingPointFormula[]::new);
return Stream.of(opTerms).skip(1).reduce(opTerms[0],
(op1, op2) -> floatingPointFormulaManager.multiply(op1, op2, transformFpRoundingMode(expr.getRoundingMode())));
}
private Formula transformFpDiv(final FpDivExpr expr) {
final FloatingPointFormula leftOpTerm = (FloatingPointFormula) toTerm(expr.getLeftOp());
final FloatingPointFormula rightOpTerm = (FloatingPointFormula) toTerm(expr.getRightOp());
return floatingPointFormulaManager.divide(leftOpTerm, rightOpTerm, transformFpRoundingMode(expr.getRoundingMode()));
}
private Formula transformFpRem(final FpRemExpr expr) {
final FloatingPointFormula leftOpTerm = (FloatingPointFormula) toTerm(expr.getLeftOp());
final FloatingPointFormula rightOpTerm = (FloatingPointFormula) toTerm(expr.getRightOp());
return floatingPointFormulaManager.remainder(leftOpTerm, rightOpTerm);
}
private Formula transformFpEq(final FpEqExpr expr) {
final Formula leftOpTerm = toTerm(expr.getLeftOp());
final Formula rightOpTerm = toTerm(expr.getRightOp());
return floatingPointFormulaManager.equalWithFPSemantics((FloatingPointFormula) leftOpTerm, (FloatingPointFormula) rightOpTerm);
}
private Formula transformFpAssign(final FpAssignExpr expr) {
final Formula leftOpTerm = toTerm(expr.getLeftOp());
final Formula rightOpTerm = toTerm(expr.getRightOp());
return floatingPointFormulaManager.assignment((FloatingPointFormula) leftOpTerm, (FloatingPointFormula) rightOpTerm);
}
private Formula transformFpNeq(final FpNeqExpr expr) {
final Formula leftOpTerm = toTerm(expr.getLeftOp());
final Formula rightOpTerm = toTerm(expr.getRightOp());
return booleanFormulaManager.not(floatingPointFormulaManager.equalWithFPSemantics((FloatingPointFormula) leftOpTerm, (FloatingPointFormula) rightOpTerm));
}
private Formula transformFpGeq(final FpGeqExpr expr) {
final Formula leftOpTerm = toTerm(expr.getLeftOp());
final Formula rightOpTerm = toTerm(expr.getRightOp());
return floatingPointFormulaManager.greaterOrEquals((FloatingPointFormula) leftOpTerm, (FloatingPointFormula) rightOpTerm);
}
private Formula transformFpLeq(final FpLeqExpr expr) {
final Formula leftOpTerm = toTerm(expr.getLeftOp());
final Formula rightOpTerm = toTerm(expr.getRightOp());
return floatingPointFormulaManager.lessOrEquals((FloatingPointFormula) leftOpTerm, (FloatingPointFormula) rightOpTerm);
}
private Formula transformFpGt(final FpGtExpr expr) {
final Formula leftOpTerm = toTerm(expr.getLeftOp());
final Formula rightOpTerm = toTerm(expr.getRightOp());
return floatingPointFormulaManager.greaterThan((FloatingPointFormula) leftOpTerm, (FloatingPointFormula) rightOpTerm);
}
private Formula transformFpLt(final FpLtExpr expr) {
final Formula leftOpTerm = toTerm(expr.getLeftOp());
final Formula rightOpTerm = toTerm(expr.getRightOp());
return floatingPointFormulaManager.lessThan((FloatingPointFormula) leftOpTerm, (FloatingPointFormula) rightOpTerm);
}
private FloatingPointRoundingMode transformFpRoundingMode(final FpRoundingMode roundingMode) {
return switch (roundingMode) {
case RNE -> FloatingPointRoundingMode.NEAREST_TIES_TO_EVEN;
case RNA -> FloatingPointRoundingMode.NEAREST_TIES_AWAY;
case RTP -> FloatingPointRoundingMode.TOWARD_POSITIVE;
case RTN -> FloatingPointRoundingMode.TOWARD_NEGATIVE;
case RTZ -> FloatingPointRoundingMode.TOWARD_ZERO;
};
}
private Formula transformFpMax(final FpMaxExpr expr) {
final FloatingPointFormula leftOpTerm = (FloatingPointFormula) toTerm(expr.getLeftOp());
final FloatingPointFormula rightOpTerm = (FloatingPointFormula) toTerm(expr.getRightOp());
return floatingPointFormulaManager.max(leftOpTerm, rightOpTerm);
}
private Formula transformFpMin(final FpMinExpr expr) {
final FloatingPointFormula leftOpTerm = (FloatingPointFormula) toTerm(expr.getLeftOp());
final FloatingPointFormula rightOpTerm = (FloatingPointFormula) toTerm(expr.getRightOp());
return floatingPointFormulaManager.min(leftOpTerm, rightOpTerm);
}
private Formula transformFpFromBv(final FpFromBvExpr expr) {
final BitvectorFormula val = (BitvectorFormula) toTerm(expr.getOp());
final FloatingPointType fpSort = FloatingPointType.getFloatingPointType(
expr.getFpType().getExponent(),
expr.getFpType().getSignificand() - 1);
return floatingPointFormulaManager.castFrom(val, expr.isSigned(), fpSort);
}
/*
* Arrays
*/
private Formula transformFpToBv(final FpToBvExpr expr) {
final FloatingPointFormula op = (FloatingPointFormula) toTerm(expr.getOp());
final FloatingPointRoundingMode roundingMode = transformRoundingMode(expr.getRoundingMode());
return floatingPointFormulaManager.castTo(op, expr.getSgn(), FormulaType.getBitvectorTypeWithSize(expr.getSize()), roundingMode);
}
private Formula transformFpToFp(final FpToFpExpr expr) {
final FloatingPointFormula op = (FloatingPointFormula) toTerm(expr.getOp());
return floatingPointFormulaManager.castTo(
op,
true, // ignored
FloatingPointType.getFloatingPointType(expr.getExpBits(), expr.getSignBits() - 1),
transformFpRoundingMode(expr.getRoundingMode()));
}
private Formula transformArrayRead(final ArrayReadExpr, ?> expr) {
final ArrayFormula arrayTerm = (ArrayFormula) toTerm(
expr.getArray());
final Formula indexTerm = toTerm(expr.getIndex());
return arrayFormulaManager.select(arrayTerm, indexTerm);
}
private Formula transformArrayWrite(final ArrayWriteExpr, ?> expr) {
final ArrayFormula arrayTerm = (ArrayFormula) toTerm(
expr.getArray());
final Formula indexTerm = toTerm(expr.getIndex());
final Formula elemTerm = toTerm(expr.getElem());
return arrayFormulaManager.store(arrayTerm, indexTerm, elemTerm);
}
private Formula transformArrayEq(final ArrayEqExpr, ?> expr) {
final ArrayFormula leftOpTerm = (ArrayFormula) toTerm(expr.getLeftOp());
final ArrayFormula rightOpTerm = (ArrayFormula) toTerm(expr.getRightOp());
return arrayFormulaManager.equivalence(leftOpTerm, rightOpTerm);
}
private Formula transformArrayNeq(final ArrayNeqExpr, ?> expr) {
return booleanFormulaManager.not(
(BooleanFormula) transformArrayEq(ArrayEqExpr.create(expr.getLeftOp(), expr.getRightOp()))
);
}
private Formula transformArrayLit(final ArrayLitExpr, ?> expr) {
final TE elseElem = (TE) toTerm(expr.getElseElem());
final FormulaType elemType = (FormulaType) transformer.toSort(expr.getType().getElemType());
final FormulaType indexType = (FormulaType) transformer.toSort(expr.getType().getIndexType());
var arr = arrayFormulaManager.makeArray(
elseElem,
indexType,
elemType);
for (Tuple2 extends LitExpr>, ? extends LitExpr>> element : expr.getElements()) {
final TI index = (TI) toTerm(element.get1());
final TE elem = (TE) toTerm(element.get2());
arr = arrayFormulaManager.store(arr, index, elem);
}
return arr;
}
/*
* Functions
*/
private Formula transformArrayInit(final ArrayInitExpr, ?> expr) {
final TE elseElem = (TE) toTerm(expr.getElseElem());
final FormulaType elemType = (FormulaType) transformer.toSort(expr.getType().getElemType());
final FormulaType indexType = (FormulaType) transformer.toSort(expr.getType().getIndexType());
var arr = arrayFormulaManager.makeArray(
elseElem,
indexType,
elemType);
for (Tuple2 extends Expr>, ? extends Expr>> element : expr.getElements()) {
final TI index = (TI) toTerm(element.get1());
final TE elem = (TE) toTerm(element.get2());
arr = arrayFormulaManager.store(arr, index, elem);
}
return arr;
}
private Formula transformFuncApp(final FuncAppExpr, ?> expr) {
final Tuple2, List>> funcAndArgs = extractFuncAndArgs(expr);
final Expr> func = funcAndArgs.get1();
if (func instanceof RefExpr) {
final RefExpr> ref = (RefExpr>) func;
final ConstDecl> decl = (ConstDecl>) ref.getDecl();
final String name = decl.getName();
final List> args = funcAndArgs.get2();
final List argTerms = args.stream()
.map(this::toTerm)
.toList();
final FunctionDeclaration> funcDecl;
if (symbolTable.definesConstAsFunction(decl)) {
funcDecl = symbolTable.getSymbolAsFunction(decl);
} else {
funcDecl = context.getFormulaManager().getUFManager().declareUF(
name,
transformer.toSort(expr.getType()),
argTerms.stream().map(context.getFormulaManager()::getFormulaType).collect(Collectors.toList()));
symbolTable.put(decl, funcDecl);
}
return context.getFormulaManager().getUFManager().callUF(funcDecl, argTerms);
} else {
throw new UnsupportedOperationException(
"Higher order functions are not supported: " + func);
}
}
private Formula transformDereference(final Dereference, ?, ?> expr) {
checkState(expr.getUniquenessIdx().isPresent(), "Incomplete dereferences (missing uniquenessIdx) are not handled properly.");
final var sort = transformer.toSort(expr.getArray().getType());
final var sortName = expr.getArray().getType().toString() + "-" + expr.getType().toString();
final var constSort = transformer.toSort(Int());
final var funcDecl = context.getFormulaManager().getUFManager().declareUF(
"deref-" + sortName.replaceAll(" ", "_"),
transformer.toSort(expr.getType()),
List.of(sort, sort, constSort));
final var func = context.getFormulaManager().getUFManager()
.callUF(funcDecl, toTerm(expr.getArray()), toTerm(expr.getOffset()), toTerm(expr.getUniquenessIdx().get()));
return func;
}
// Enums
private Formula transformEnumEq(EnumEqExpr enumEqExpr) {
return enumFormulaManager.equivalence((EnumerationFormula) toTerm(enumEqExpr.getLeftOp()), (EnumerationFormula) toTerm(enumEqExpr.getRightOp()));
}
private Formula transformEnumLit(EnumLitExpr enumLitExpr) {
return enumFormulaManager.makeConstant(EnumType.makeLongName(enumLitExpr.getType(), enumLitExpr.getValue()), (FormulaType.EnumerationFormulaType) transformer.toSort(enumLitExpr.getType()));
}
private Formula transformEnumNeq(EnumNeqExpr enumNeqExpr) {
return booleanFormulaManager.not(enumFormulaManager.equivalence((EnumerationFormula) toTerm(enumNeqExpr.getLeftOp()), (EnumerationFormula) toTerm(enumNeqExpr.getRightOp())));
}
public void reset() {
exprToTerm.invalidateAll();
}
}