From 91eaf3c2b2df95829c7e4c1e7d76673c48650075 Mon Sep 17 00:00:00 2001 From: RipplB Date: Wed, 27 Sep 2023 22:56:59 +0200 Subject: [PATCH 1/8] Make types have information about their possible domain size --- .../bme/mit/theta/core/type/DomainSize.java | 86 +++++++++++++++++++ .../java/hu/bme/mit/theta/core/type/Type.java | 2 +- .../theta/core/type/arraytype/ArrayType.java | 6 ++ .../theta/core/type/booltype/BoolType.java | 6 ++ .../mit/theta/core/type/bvtype/BvType.java | 29 ++----- .../mit/theta/core/type/fptype/FpType.java | 25 ++---- .../theta/core/type/functype/FuncType.java | 5 ++ .../mit/theta/core/type/inttype/IntType.java | 6 ++ .../mit/theta/core/type/rattype/RatType.java | 5 ++ .../hu/bme/mit/theta/xta/utils/ChanType.java | 5 ++ .../hu/bme/mit/theta/xta/utils/ClockType.java | 5 ++ .../hu/bme/mit/theta/xta/utils/RangeType.java | 6 ++ 12 files changed, 149 insertions(+), 37 deletions(-) create mode 100644 subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/DomainSize.java diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/DomainSize.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/DomainSize.java new file mode 100644 index 0000000000..9e38b6f708 --- /dev/null +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/DomainSize.java @@ -0,0 +1,86 @@ +package hu.bme.mit.theta.core.type; + +import com.google.common.base.Objects; + +import java.math.BigInteger; +import java.util.function.BinaryOperator; + +import static com.google.common.base.Preconditions.checkArgument; + +public class DomainSize { + + private final BigInteger finiteSize; + + private DomainSize(BigInteger value) { + finiteSize = value; + } + + public static DomainSize of(BigInteger val) { + checkArgument(val.signum() != -1, "DomainSize can't be negative"); + return new DomainSize(val); + } + + public static DomainSize of(long val) { + return of(BigInteger.valueOf(val)); + } + + public static final DomainSize INFINITY = new DomainSize(BigInteger.valueOf(-1)); + public static final DomainSize ZERO = of(0); + public static final DomainSize ONE = of(1); + public static final DomainSize TWO = of(2); + + private static DomainSize infiniteForAnyInfiniteApplyElse(DomainSize left, DomainSize right, BinaryOperator operator) { + if (left.isInfinite() || right.isInfinite()) + return INFINITY; + return of(operator.apply(left.finiteSize, right.finiteSize)); + } + + public boolean isInfinite() { + return equals(INFINITY); + } + + public boolean isBiggerThan(long limit) { + return this.equals(INFINITY) || finiteSize.compareTo(BigInteger.valueOf(limit)) > 0; + } + + public BigInteger getFiniteSize() { + return finiteSize; + } + + public static DomainSize add(DomainSize left, DomainSize right) { + return infiniteForAnyInfiniteApplyElse(left, right, BigInteger::add); + } + + public static DomainSize multiply(DomainSize left, DomainSize right) { + return infiniteForAnyInfiniteApplyElse(left, right, BigInteger::multiply); + } + + /** + * Raises a domain size to the power of the other. Returns {@link DomainSize#INFINITY} if either + * parameter is infinite or exponent is too large ( = can't fit into an integer) + */ + public static DomainSize pow(DomainSize base, DomainSize exponent) { + if (base.isInfinite() || exponent.isInfinite()) + return INFINITY; + int iExp; + try { + iExp = exponent.finiteSize.intValueExact(); + } catch (ArithmeticException exception) { + return INFINITY; + } + return of(base.finiteSize.pow(iExp)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DomainSize that = (DomainSize) o; + return Objects.equal(finiteSize, that.finiteSize); + } + + @Override + public int hashCode() { + return Objects.hashCode(finiteSize); + } +} diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/Type.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/Type.java index 20602eb8dd..38def58ad8 100644 --- a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/Type.java +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/Type.java @@ -16,5 +16,5 @@ package hu.bme.mit.theta.core.type; public interface Type { - + DomainSize getDomainSize(); } diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/arraytype/ArrayType.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/arraytype/ArrayType.java index 3e6c106a2f..bcde7b3991 100644 --- a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/arraytype/ArrayType.java +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/arraytype/ArrayType.java @@ -16,6 +16,7 @@ package hu.bme.mit.theta.core.type.arraytype; import hu.bme.mit.theta.common.Utils; +import hu.bme.mit.theta.core.type.DomainSize; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.Type; import hu.bme.mit.theta.core.type.abstracttype.EqExpr; @@ -97,4 +98,9 @@ public String toString() { final String indexString = String.format("([%s] -> %s)", indexType, elemType); return Utils.lispStringBuilder(TYPE_LABEL).add(indexString).toString(); } + + @Override + public DomainSize getDomainSize() { + return DomainSize.pow(elemType.getDomainSize(), indexType.getDomainSize()); + } } diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/booltype/BoolType.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/booltype/BoolType.java index 384a2a1415..233c92b454 100644 --- a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/booltype/BoolType.java +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/booltype/BoolType.java @@ -15,6 +15,7 @@ */ package hu.bme.mit.theta.core.type.booltype; +import hu.bme.mit.theta.core.type.DomainSize; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.abstracttype.Equational; import hu.bme.mit.theta.core.type.abstracttype.NeqExpr; @@ -59,4 +60,9 @@ public NeqExpr Neq(final Expr leftOp, final Expr r return BoolExprs.Xor(leftOp, rightOp); } + @Override + public DomainSize getDomainSize() { + return DomainSize.TWO; + } + } diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java index 410656f194..36023bf9ed 100644 --- a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/bvtype/BvType.java @@ -17,31 +17,15 @@ package hu.bme.mit.theta.core.type.bvtype; import hu.bme.mit.theta.common.Utils; +import hu.bme.mit.theta.core.type.DomainSize; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.Type; -import hu.bme.mit.theta.core.type.abstracttype.AddExpr; -import hu.bme.mit.theta.core.type.abstracttype.Additive; -import hu.bme.mit.theta.core.type.abstracttype.Castable; -import hu.bme.mit.theta.core.type.abstracttype.DivExpr; -import hu.bme.mit.theta.core.type.abstracttype.Divisible; -import hu.bme.mit.theta.core.type.abstracttype.EqExpr; -import hu.bme.mit.theta.core.type.abstracttype.Equational; -import hu.bme.mit.theta.core.type.abstracttype.GeqExpr; -import hu.bme.mit.theta.core.type.abstracttype.GtExpr; -import hu.bme.mit.theta.core.type.abstracttype.LeqExpr; -import hu.bme.mit.theta.core.type.abstracttype.LtExpr; -import hu.bme.mit.theta.core.type.abstracttype.ModExpr; -import hu.bme.mit.theta.core.type.abstracttype.MulExpr; -import hu.bme.mit.theta.core.type.abstracttype.Multiplicative; -import hu.bme.mit.theta.core.type.abstracttype.NegExpr; -import hu.bme.mit.theta.core.type.abstracttype.NeqExpr; -import hu.bme.mit.theta.core.type.abstracttype.Ordered; -import hu.bme.mit.theta.core.type.abstracttype.PosExpr; -import hu.bme.mit.theta.core.type.abstracttype.RemExpr; -import hu.bme.mit.theta.core.type.abstracttype.SubExpr; +import hu.bme.mit.theta.core.type.abstracttype.*; import hu.bme.mit.theta.core.type.fptype.FpRoundingMode; import hu.bme.mit.theta.core.type.fptype.FpType; +import java.math.BigInteger; + import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; import static hu.bme.mit.theta.core.type.fptype.FpExprs.FromBv; @@ -223,4 +207,9 @@ public GeqExpr Geq(Expr leftOp, Expr rightOp) { return BvExprs.UGeq(leftOp, rightOp); } } + + @Override + public DomainSize getDomainSize() { + return DomainSize.of(BigInteger.TWO.pow(size)); + } } diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/fptype/FpType.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/fptype/FpType.java index 9914300c06..5a9d50518c 100644 --- a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/fptype/FpType.java +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/fptype/FpType.java @@ -16,23 +16,11 @@ package hu.bme.mit.theta.core.type.fptype; import hu.bme.mit.theta.common.Utils; +import hu.bme.mit.theta.core.type.DomainSize; import hu.bme.mit.theta.core.type.Expr; -import hu.bme.mit.theta.core.type.abstracttype.AddExpr; -import hu.bme.mit.theta.core.type.abstracttype.Additive; -import hu.bme.mit.theta.core.type.abstracttype.DivExpr; -import hu.bme.mit.theta.core.type.abstracttype.EqExpr; -import hu.bme.mit.theta.core.type.abstracttype.Equational; -import hu.bme.mit.theta.core.type.abstracttype.GeqExpr; -import hu.bme.mit.theta.core.type.abstracttype.GtExpr; -import hu.bme.mit.theta.core.type.abstracttype.LeqExpr; -import hu.bme.mit.theta.core.type.abstracttype.LtExpr; -import hu.bme.mit.theta.core.type.abstracttype.MulExpr; -import hu.bme.mit.theta.core.type.abstracttype.Multiplicative; -import hu.bme.mit.theta.core.type.abstracttype.NegExpr; -import hu.bme.mit.theta.core.type.abstracttype.NeqExpr; -import hu.bme.mit.theta.core.type.abstracttype.Ordered; -import hu.bme.mit.theta.core.type.abstracttype.PosExpr; -import hu.bme.mit.theta.core.type.abstracttype.SubExpr; +import hu.bme.mit.theta.core.type.abstracttype.*; + +import java.math.BigInteger; import static com.google.common.base.Preconditions.checkArgument; @@ -155,4 +143,9 @@ public GtExpr Gt(Expr leftOp, Expr rightOp) { public GeqExpr Geq(Expr leftOp, Expr rightOp) { return FpExprs.Geq(leftOp, rightOp); } + + @Override + public DomainSize getDomainSize() { + return DomainSize.of(BigInteger.TWO.pow(significand).multiply(BigInteger.TWO.pow(exponent))); + } } diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/functype/FuncType.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/functype/FuncType.java index 529c041ca6..a1f2d7becd 100644 --- a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/functype/FuncType.java +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/functype/FuncType.java @@ -16,6 +16,7 @@ package hu.bme.mit.theta.core.type.functype; import hu.bme.mit.theta.common.Utils; +import hu.bme.mit.theta.core.type.DomainSize; import hu.bme.mit.theta.core.type.Type; import static com.google.common.base.Preconditions.checkNotNull; @@ -78,4 +79,8 @@ public String toString() { return Utils.lispStringBuilder(TYPE_LABEL).add(paramType).add(resultType).toString(); } + @Override + public DomainSize getDomainSize() { + throw new UnsupportedOperationException(); + } } diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntType.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntType.java index 1cbe3d1403..15567f0fb9 100644 --- a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntType.java +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/inttype/IntType.java @@ -15,6 +15,7 @@ */ package hu.bme.mit.theta.core.type.inttype; +import hu.bme.mit.theta.core.type.DomainSize; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.Type; import hu.bme.mit.theta.core.type.abstracttype.Additive; @@ -140,4 +141,9 @@ public Expr Cast(final Expr op, throw new ClassCastException("Int cannot be cast to " + type); } } + + @Override + public DomainSize getDomainSize() { + return DomainSize.INFINITY; + } } diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/rattype/RatType.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/rattype/RatType.java index 9aa15b0734..92a00b2880 100644 --- a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/rattype/RatType.java +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/rattype/RatType.java @@ -15,6 +15,7 @@ */ package hu.bme.mit.theta.core.type.rattype; +import hu.bme.mit.theta.core.type.DomainSize; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.abstracttype.Additive; import hu.bme.mit.theta.core.type.abstracttype.Equational; @@ -112,4 +113,8 @@ public RatGeqExpr Geq(final Expr leftOp, final Expr rightOp) { return RatExprs.Geq(leftOp, rightOp); } + @Override + public DomainSize getDomainSize() { + return DomainSize.INFINITY; + } } diff --git a/subprojects/xta/xta/src/main/java/hu/bme/mit/theta/xta/utils/ChanType.java b/subprojects/xta/xta/src/main/java/hu/bme/mit/theta/xta/utils/ChanType.java index 82b677a990..d6f5029a4e 100644 --- a/subprojects/xta/xta/src/main/java/hu/bme/mit/theta/xta/utils/ChanType.java +++ b/subprojects/xta/xta/src/main/java/hu/bme/mit/theta/xta/utils/ChanType.java @@ -15,6 +15,7 @@ */ package hu.bme.mit.theta.xta.utils; +import hu.bme.mit.theta.core.type.DomainSize; import hu.bme.mit.theta.core.type.Type; public final class ChanType implements Type { @@ -33,4 +34,8 @@ public String toString() { return "Chan"; } + @Override + public DomainSize getDomainSize() { + return DomainSize.ONE; + } } diff --git a/subprojects/xta/xta/src/main/java/hu/bme/mit/theta/xta/utils/ClockType.java b/subprojects/xta/xta/src/main/java/hu/bme/mit/theta/xta/utils/ClockType.java index 480e00b51b..5deb3f53d7 100644 --- a/subprojects/xta/xta/src/main/java/hu/bme/mit/theta/xta/utils/ClockType.java +++ b/subprojects/xta/xta/src/main/java/hu/bme/mit/theta/xta/utils/ClockType.java @@ -15,6 +15,7 @@ */ package hu.bme.mit.theta.xta.utils; +import hu.bme.mit.theta.core.type.DomainSize; import hu.bme.mit.theta.core.type.Type; public final class ClockType implements Type { @@ -33,4 +34,8 @@ public String toString() { return "Clock"; } + @Override + public DomainSize getDomainSize() { + return DomainSize.INFINITY; + } } diff --git a/subprojects/xta/xta/src/main/java/hu/bme/mit/theta/xta/utils/RangeType.java b/subprojects/xta/xta/src/main/java/hu/bme/mit/theta/xta/utils/RangeType.java index 1edde6a835..7fc1c5ad39 100644 --- a/subprojects/xta/xta/src/main/java/hu/bme/mit/theta/xta/utils/RangeType.java +++ b/subprojects/xta/xta/src/main/java/hu/bme/mit/theta/xta/utils/RangeType.java @@ -16,6 +16,7 @@ package hu.bme.mit.theta.xta.utils; import hu.bme.mit.theta.common.Utils; +import hu.bme.mit.theta.core.type.DomainSize; import hu.bme.mit.theta.core.type.Type; import hu.bme.mit.theta.core.type.inttype.IntExprs; import hu.bme.mit.theta.core.type.inttype.IntLitExpr; @@ -89,4 +90,9 @@ public String toString() { return Utils.lispStringBuilder("Range").add(lower).add(upper).toString(); } + @Override + public DomainSize getDomainSize() { + return DomainSize.of(upper - lower + 1); + } + } From cf9f5248740d78d91a657aa5c7f495d8877c6a4c Mon Sep 17 00:00:00 2001 From: RipplB Date: Tue, 18 Jun 2024 12:44:12 +0200 Subject: [PATCH 2/8] Introduce EnumType, Z3 support and XSTS use it --- build.gradle.kts | 2 +- .../bme/mit/theta/core/type/DomainSize.java | 162 +++++++------- .../theta/core/type/enumtype/EnumEqExpr.java | 78 +++++++ .../theta/core/type/enumtype/EnumLitExpr.java | 82 +++++++ .../theta/core/type/enumtype/EnumNeqExpr.java | 78 +++++++ .../theta/core/type/enumtype/EnumType.java | 114 ++++++++++ .../mit/theta/core/utils/ExprSimplifier.java | 202 +++++++----------- .../solver/z3legacy/Z3ExprTransformer.java | 148 +++---------- .../mit/theta/solver/z3legacy/Z3Solver.java | 20 +- .../solver/z3legacy/Z3TermTransformer.java | 55 ++--- .../solver/z3legacy/Z3TypeTransformer.java | 16 +- .../theta/solver/z3/Z3ExprTransformer.java | 148 ++++--------- .../hu/bme/mit/theta/solver/z3/Z3Solver.java | 20 +- .../theta/solver/z3/Z3TermTransformer.java | 59 ++--- .../theta/solver/z3/Z3TypeTransformer.java | 16 +- .../xsts/analysis/XstsEnumSemanticsTest.java | 37 ++++ .../bme/mit/theta/xsts/analysis/XstsTest.java | 6 +- .../src/test/resources/model/literals.xsts | 7 +- .../test/resources/model/literals_bad.xsts | 11 + .../src/test/resources/property/literals.prop | 2 +- .../xsts/dsl/CustomTypeDeclarationUtil.java | 46 ++++ .../xsts/dsl/XstsCustomLiteralSymbol.java | 31 +-- .../theta/xsts/dsl/XstsCustomTypeSymbol.java | 24 +-- .../mit/theta/xsts/dsl/XstsExpression.java | 108 +++------- .../mit/theta/xsts/dsl/XstsSpecification.java | 69 +++--- .../bme/mit/theta/xsts/dsl/XstsStatement.java | 12 +- .../mit/theta/xsts/type/XstsCustomType.java | 75 ++----- 27 files changed, 921 insertions(+), 707 deletions(-) create mode 100644 subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumEqExpr.java create mode 100644 subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumLitExpr.java create mode 100644 subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumNeqExpr.java create mode 100644 subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumType.java create mode 100644 subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsEnumSemanticsTest.java create mode 100644 subprojects/xsts/xsts-analysis/src/test/resources/model/literals_bad.xsts create mode 100644 subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/CustomTypeDeclarationUtil.java diff --git a/build.gradle.kts b/build.gradle.kts index da4081e007..710b02b927 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,7 +28,7 @@ buildscript { allprojects { group = "hu.bme.mit.theta" - version = "5.2.1" + version = "5.3.0" apply(from = rootDir.resolve("gradle/shared-with-buildSrc/mirrors.gradle.kts")) } diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/DomainSize.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/DomainSize.java index 9e38b6f708..8bc2d25a76 100644 --- a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/DomainSize.java +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/DomainSize.java @@ -1,3 +1,18 @@ +/* + * 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.core.type; import com.google.common.base.Objects; @@ -9,78 +24,77 @@ public class DomainSize { - private final BigInteger finiteSize; - - private DomainSize(BigInteger value) { - finiteSize = value; - } - - public static DomainSize of(BigInteger val) { - checkArgument(val.signum() != -1, "DomainSize can't be negative"); - return new DomainSize(val); - } - - public static DomainSize of(long val) { - return of(BigInteger.valueOf(val)); - } - - public static final DomainSize INFINITY = new DomainSize(BigInteger.valueOf(-1)); - public static final DomainSize ZERO = of(0); - public static final DomainSize ONE = of(1); - public static final DomainSize TWO = of(2); - - private static DomainSize infiniteForAnyInfiniteApplyElse(DomainSize left, DomainSize right, BinaryOperator operator) { - if (left.isInfinite() || right.isInfinite()) - return INFINITY; - return of(operator.apply(left.finiteSize, right.finiteSize)); - } - - public boolean isInfinite() { - return equals(INFINITY); - } - - public boolean isBiggerThan(long limit) { - return this.equals(INFINITY) || finiteSize.compareTo(BigInteger.valueOf(limit)) > 0; - } - - public BigInteger getFiniteSize() { - return finiteSize; - } - - public static DomainSize add(DomainSize left, DomainSize right) { - return infiniteForAnyInfiniteApplyElse(left, right, BigInteger::add); - } - - public static DomainSize multiply(DomainSize left, DomainSize right) { - return infiniteForAnyInfiniteApplyElse(left, right, BigInteger::multiply); - } - - /** - * Raises a domain size to the power of the other. Returns {@link DomainSize#INFINITY} if either - * parameter is infinite or exponent is too large ( = can't fit into an integer) - */ - public static DomainSize pow(DomainSize base, DomainSize exponent) { - if (base.isInfinite() || exponent.isInfinite()) - return INFINITY; - int iExp; - try { - iExp = exponent.finiteSize.intValueExact(); - } catch (ArithmeticException exception) { - return INFINITY; - } - return of(base.finiteSize.pow(iExp)); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - DomainSize that = (DomainSize) o; - return Objects.equal(finiteSize, that.finiteSize); - } - - @Override - public int hashCode() { - return Objects.hashCode(finiteSize); - } + public static final DomainSize INFINITY = new DomainSize(BigInteger.valueOf(-1)); + public static final DomainSize ZERO = of(0); + public static final DomainSize ONE = of(1); + public static final DomainSize TWO = of(2); + private final BigInteger finiteSize; + + private DomainSize(BigInteger value) { + finiteSize = value; + } + + public static DomainSize of(BigInteger val) { + checkArgument(val.signum() != -1, "DomainSize can't be negative"); + return new DomainSize(val); + } + + public static DomainSize of(long val) { + return of(BigInteger.valueOf(val)); + } + + private static DomainSize infiniteForAnyInfiniteApplyElse(DomainSize left, DomainSize right, BinaryOperator operator) { + if (left.isInfinite() || right.isInfinite()) + return INFINITY; + return of(operator.apply(left.finiteSize, right.finiteSize)); + } + + public static DomainSize add(DomainSize left, DomainSize right) { + return infiniteForAnyInfiniteApplyElse(left, right, BigInteger::add); + } + + public static DomainSize multiply(DomainSize left, DomainSize right) { + return infiniteForAnyInfiniteApplyElse(left, right, BigInteger::multiply); + } + + /** + * Raises a domain size to the power of the other. Returns {@link DomainSize#INFINITY} if either + * parameter is infinite or exponent is too large ( = can't fit into an integer) + */ + public static DomainSize pow(DomainSize base, DomainSize exponent) { + if (base.isInfinite() || exponent.isInfinite()) + return INFINITY; + int iExp; + try { + iExp = exponent.finiteSize.intValueExact(); + } catch (ArithmeticException exception) { + return INFINITY; + } + return of(base.finiteSize.pow(iExp)); + } + + public boolean isInfinite() { + return equals(INFINITY); + } + + public boolean isBiggerThan(long limit) { + return this.equals(INFINITY) || finiteSize.compareTo(BigInteger.valueOf(limit)) > 0; + } + + public BigInteger getFiniteSize() { + return finiteSize; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DomainSize that = (DomainSize) o; + return Objects.equal(finiteSize, that.finiteSize); + } + + @Override + public int hashCode() { + return Objects.hashCode(finiteSize); + } } diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumEqExpr.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumEqExpr.java new file mode 100644 index 0000000000..82e416ab7b --- /dev/null +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumEqExpr.java @@ -0,0 +1,78 @@ +/* + * 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.core.type.enumtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.BinaryExpr; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.LitExpr; +import hu.bme.mit.theta.core.type.abstracttype.EqExpr; +import hu.bme.mit.theta.core.type.booltype.BoolType; + +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; + +public class EnumEqExpr extends EqExpr { + + private static final int HASH_SEED = 5326; + private static final String OPERATOR_LABEL = "="; + + private EnumEqExpr(Expr leftOp, Expr rightOp) { + super(leftOp, rightOp); + } + + public static EnumEqExpr of(Expr leftOp, Expr rightOp) { + return new EnumEqExpr(leftOp, rightOp); + } + + @Override + public BinaryExpr with(Expr leftOp, Expr rightOp) { + if (leftOp == getLeftOp() && rightOp == getRightOp()) { + return this; + } else { + return EnumEqExpr.of(leftOp, rightOp); + } + } + + @Override + public BinaryExpr withLeftOp(Expr leftOp) { + return with(leftOp, getRightOp()); + } + + @Override + public BinaryExpr withRightOp(Expr rightOp) { + return with(getLeftOp(), rightOp); + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } + + @Override + public BoolType getType() { + return Bool(); + } + + @Override + public LitExpr eval(Valuation val) { + return EnumLitExpr.eq((EnumLitExpr) getLeftOp().eval(val), (EnumLitExpr) getRightOp().eval(val)); + } +} diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumLitExpr.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumLitExpr.java new file mode 100644 index 0000000000..e75d5e6c5e --- /dev/null +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumLitExpr.java @@ -0,0 +1,82 @@ +/* + * 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.core.type.enumtype; + +import com.google.common.base.Objects; +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.LitExpr; +import hu.bme.mit.theta.core.type.NullaryExpr; +import hu.bme.mit.theta.core.type.booltype.BoolLitExpr; + +import static com.google.common.base.Preconditions.checkArgument; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; + +public final class EnumLitExpr extends NullaryExpr implements LitExpr { + + private final EnumType type; + private final String value; + + private EnumLitExpr(EnumType type, String value) { + this.type = type; + this.value = value; + } + + public static EnumLitExpr of(EnumType type, String literalName) { + String value = EnumType.getShortName(literalName); + checkArgument(type.getValues().contains(value), "Invalid value %s for type %s", value, type.getName()); + return new EnumLitExpr(type, value); + } + + public static BoolLitExpr eq(EnumLitExpr l, EnumLitExpr r) { + return Bool(l.type.equals(r.type) && l.value.equals(r.value)); + } + + public static BoolLitExpr neq(EnumLitExpr l, EnumLitExpr r) { + return Bool(!l.type.equals(r.type) || !l.value.equals(r.value)); + } + + @Override + public EnumType getType() { + return type; + } + + public String getValue() { + return value; + } + + @Override + public LitExpr eval(Valuation val) { + return this; + } + + @Override + public String toString() { + return EnumType.makeLongName(type.getName(), value); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + EnumLitExpr that = (EnumLitExpr) o; + return Objects.equal(type, that.type) && Objects.equal(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hashCode(type, value); + } +} diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumNeqExpr.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumNeqExpr.java new file mode 100644 index 0000000000..f9cd0e1cb1 --- /dev/null +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumNeqExpr.java @@ -0,0 +1,78 @@ +/* + * 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.core.type.enumtype; + +import hu.bme.mit.theta.core.model.Valuation; +import hu.bme.mit.theta.core.type.BinaryExpr; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.LitExpr; +import hu.bme.mit.theta.core.type.abstracttype.NeqExpr; +import hu.bme.mit.theta.core.type.booltype.BoolType; + +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; + +public final class EnumNeqExpr extends NeqExpr { + + private static final int HASH_SEED = 7212; + private static final String OPERATOR_LABEL = "!="; + + private EnumNeqExpr(Expr leftOp, Expr rightOp) { + super(leftOp, rightOp); + } + + public static EnumNeqExpr of(Expr leftOp, Expr rightOp) { + return new EnumNeqExpr(leftOp, rightOp); + } + + @Override + public BinaryExpr with(Expr leftOp, Expr rightOp) { + if (leftOp == getLeftOp() && rightOp == getRightOp()) { + return this; + } else { + return EnumNeqExpr.of(leftOp, rightOp); + } + } + + @Override + public BinaryExpr withLeftOp(Expr leftOp) { + return with(leftOp, getRightOp()); + } + + @Override + public BinaryExpr withRightOp(Expr rightOp) { + return with(getLeftOp(), rightOp); + } + + @Override + protected int getHashSeed() { + return HASH_SEED; + } + + @Override + public String getOperatorLabel() { + return OPERATOR_LABEL; + } + + @Override + public BoolType getType() { + return Bool(); + } + + @Override + public LitExpr eval(Valuation val) { + return EnumLitExpr.neq((EnumLitExpr) getLeftOp().eval(val), (EnumLitExpr) getRightOp().eval(val)); + } +} diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumType.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumType.java new file mode 100644 index 0000000000..bbf47e3d49 --- /dev/null +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/type/enumtype/EnumType.java @@ -0,0 +1,114 @@ +/* + * 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.core.type.enumtype; + +import hu.bme.mit.theta.core.type.DomainSize; +import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.Type; +import hu.bme.mit.theta.core.type.abstracttype.EqExpr; +import hu.bme.mit.theta.core.type.abstracttype.Equational; +import hu.bme.mit.theta.core.type.abstracttype.NeqExpr; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import static com.google.common.base.Preconditions.checkArgument; + +public final class EnumType implements Equational, Type { + + public static final String FULLY_QUALIFIED_NAME_SEPARATOR = "."; + private final Map literals; + private final String name; + private int counter = 0; + + private EnumType(String name, Collection values) { + this.name = name; + this.literals = new LinkedHashMap<>(); + values.forEach(value -> literals.put(value, counter++)); + } + + public static EnumType of(String name, Collection values) { + return new EnumType(name, values); + } + + public static String makeLongName(String typeName, String literal) { + return String.format("%s%s%s", typeName, FULLY_QUALIFIED_NAME_SEPARATOR, literal); + } + + public static String makeLongName(EnumType type, String literal) { + return makeLongName(type.getName(), literal); + } + + public static String getShortName(String longName) { + if (!longName.contains(FULLY_QUALIFIED_NAME_SEPARATOR)) + return longName; + return longName.substring(longName.indexOf(FULLY_QUALIFIED_NAME_SEPARATOR) + FULLY_QUALIFIED_NAME_SEPARATOR.length()); + } + + @Override + public DomainSize getDomainSize() { + return DomainSize.of(literals.size()); + } + + @Override + public EqExpr Eq(Expr leftOp, Expr rightOp) { + return EnumEqExpr.of(leftOp, rightOp); + } + + @Override + public NeqExpr Neq(Expr leftOp, Expr rightOp) { + return EnumNeqExpr.of(leftOp, rightOp); + } + + public Set getValues() { + return literals.keySet(); + } + + public Set getLongValues() { + return literals.keySet().stream().map(val -> makeLongName(this, val)).collect(Collectors.toSet()); + } + + public String getName() { + return name; + } + + public int getIntValue(String literal) { + checkArgument(literals.containsKey(literal), String.format("Enum type %s does not contain literal '%s'", name, literal)); + return literals.get(literal); + } + + public EnumLitExpr litFromLongName(String longName) { + if (!longName.contains(FULLY_QUALIFIED_NAME_SEPARATOR)) + throw new RuntimeException(String.format("%s is an invalid enum longname")); + String[] parts = longName.split(Pattern.quote(FULLY_QUALIFIED_NAME_SEPARATOR)); + String type = parts[0]; + checkArgument(name.equals(type), String.format("%s does not belong to type %s", type, name)); + try { + return EnumLitExpr.of(this, parts[1]); + } catch (Exception e) { + throw new RuntimeException(String.format("%s is not valid for type %s", longName, name), e); + } + } + + @Override + public String toString() { + return String.format("EnumType{%s}", name); + } +} diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java index 485d923e9c..a79d7b109f 100644 --- a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java @@ -29,109 +29,15 @@ import hu.bme.mit.theta.core.type.arraytype.ArrayReadExpr; import hu.bme.mit.theta.core.type.arraytype.ArrayType; 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.BoolLitExpr; -import hu.bme.mit.theta.core.type.booltype.BoolType; -import hu.bme.mit.theta.core.type.booltype.FalseExpr; -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.BvType; -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.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.FpRoundToIntegralExpr; -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.fptype.FpType; -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.inttype.IntType; -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.type.rattype.RatType; +import hu.bme.mit.theta.core.type.booltype.*; +import hu.bme.mit.theta.core.type.bvtype.*; +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.*; +import hu.bme.mit.theta.core.type.inttype.*; +import hu.bme.mit.theta.core.type.rattype.*; import org.kframework.mpfr.BigFloat; import java.math.BigInteger; @@ -140,10 +46,7 @@ import java.util.List; import java.util.Optional; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.False; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Not; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.True; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.*; import static hu.bme.mit.theta.core.type.bvtype.BvExprs.Bv; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; import static hu.bme.mit.theta.core.type.rattype.RatExprs.Rat; @@ -165,7 +68,10 @@ public static ExprSimplifier create(final SimplifierLevel level) { return new ExprSimplifier(level); } - private final DispatchTable2> TABLE = DispatchTable2.>builder() + @SuppressWarnings("unchecked") + public Expr simplify(final Expr expr, final Valuation valuation) { + return (Expr) TABLE.dispatch(expr, valuation); + } private final DispatchTable2> TABLE = DispatchTable2.>builder() // Boolean @@ -241,6 +147,12 @@ public static ExprSimplifier create(final SimplifierLevel level) { .addCase(IntLtExpr.class, this::simplifyIntLt) + // Enum + + .addCase(EnumEqExpr.class, this::simplifyEnumEqExpr) + + .addCase(EnumNeqExpr.class, this::simplifyEnumNeqExpr) + // Array .addCase(ArrayReadExpr.class, this::simplifyArrayRead) @@ -387,19 +299,14 @@ public static ExprSimplifier create(final SimplifierLevel level) { .build(); - @SuppressWarnings("unchecked") - public Expr simplify(final Expr expr, final Valuation valuation) { - return (Expr) TABLE.dispatch(expr, valuation); + private Expr simplifyRef(final RefExpr expr, final Valuation val) { + return simplifyGenericRef(expr, val); } /* * General */ - private Expr simplifyRef(final RefExpr expr, final Valuation val) { - return simplifyGenericRef(expr, val); - } - // TODO Eliminate helper method once the Java compiler is able to handle // this kind of type inference private Expr simplifyGenericRef(final RefExpr expr, @@ -487,10 +394,6 @@ private Expr simplifyArrayWrite(final ArrayWriteExpr expr, final Valuat else return t.eval(val); } - /* - * Booleans - */ - private Expr simplifyNot(final NotExpr expr, final Valuation val) { final Expr op = simplify(expr.getOp(), val); if (op instanceof NotExpr) { @@ -504,6 +407,10 @@ private Expr simplifyNot(final NotExpr expr, final Valuation val) { return expr.with(op); } + /* + * Booleans + */ + private Expr simplifyImply(final ImplyExpr expr, final Valuation val) { final Expr leftOp = simplify(expr.getLeftOp(), val); final Expr rightOp = simplify(expr.getRightOp(), val); @@ -643,10 +550,6 @@ private Expr simplifyOr(final OrExpr expr, final Valuation val) { return expr.with(ops); } - /* - * Rationals - */ - private Expr simplifyRatAdd(final RatAddExpr expr, final Valuation val) { final List> ops = new ArrayList<>(); @@ -687,6 +590,10 @@ private Expr simplifyRatAdd(final RatAddExpr expr, final Valuation val) return expr.with(ops); } + /* + * Rationals + */ + private Expr simplifyRatSub(final RatSubExpr expr, final Valuation val) { final Expr leftOp = simplify(expr.getLeftOp(), val); final Expr rightOp = simplify(expr.getRightOp(), val); @@ -897,10 +804,6 @@ private Expr simplifyRatToInt(final RatToIntExpr expr, final Valuation return expr.with(op); } - /* - * Integers - */ - private Expr simplifyIntToRat(final IntToRatExpr expr, final Valuation val) { final Expr op = simplify(expr.getOp(), val); @@ -912,6 +815,10 @@ private Expr simplifyIntToRat(final IntToRatExpr expr, final Valuation return expr.with(op); } + /* + * Integers + */ + private Expr simplifyIntAdd(final IntAddExpr expr, final Valuation val) { final List> ops = new ArrayList<>(); @@ -1175,10 +1082,42 @@ private Expr simplifyIntLt(final IntLtExpr expr, final Valuation val) return expr.with(leftOp, rightOp); } + private Expr simplifyEnumEqExpr(final EnumEqExpr expr, final Valuation val) { + final Expr leftOp = simplify(expr.getLeftOp(), val); + final Expr rightOp = simplify(expr.getRightOp(), val); + + if (leftOp instanceof EnumLitExpr leftLit && rightOp instanceof EnumLitExpr rightLit) { + return Bool(leftLit.equals(rightLit)); + } + + if (leftOp instanceof RefExpr && rightOp instanceof RefExpr && level != LITERAL_ONLY && leftOp.equals(rightOp)) { + return True(); + } + + + return expr.with(leftOp, rightOp); + } + /* - * Bitvectors + * Enums */ + private Expr simplifyEnumNeqExpr(final EnumNeqExpr expr, final Valuation val) { + final Expr leftOp = simplify(expr.getLeftOp(), val); + final Expr rightOp = simplify(expr.getRightOp(), val); + + if (leftOp instanceof EnumLitExpr leftLit && rightOp instanceof EnumLitExpr rightLit) { + return Bool(!leftLit.equals(rightLit)); + } + + if (leftOp instanceof RefExpr && rightOp instanceof RefExpr && level != LITERAL_ONLY && leftOp.equals(rightOp)) { + return False(); + } + + + return expr.with(leftOp, rightOp); + } + private Expr simplifyBvConcat(final BvConcatExpr expr, final Valuation val) { final List> ops = new ArrayList<>(); @@ -1211,6 +1150,10 @@ private Expr simplifyBvConcat(final BvConcatExpr expr, final Valuation v return value; } + /* + * Bitvectors + */ + private Expr simplifyBvExtract(final BvExtractExpr expr, final Valuation val) { final Expr bitvec = simplify(expr.getBitvec(), val); @@ -2077,7 +2020,6 @@ private Expr simplifyFpLt(final FpLtExpr expr, final Valuation val) { return expr.with(leftOp, rightOp); } - private Expr simplifyFpNeq(final FpNeqExpr expr, final Valuation val) { final Expr leftOp = simplify(expr.getLeftOp(), val); final Expr rightOp = simplify(expr.getRightOp(), val); @@ -2155,4 +2097,6 @@ private Expr simplifyFpToFp(final FpToFpExpr expr, final Valuation val) return expr.with(op); } + + } diff --git a/subprojects/solver/solver-z3-legacy/src/main/java/hu/bme/mit/theta/solver/z3legacy/Z3ExprTransformer.java b/subprojects/solver/solver-z3-legacy/src/main/java/hu/bme/mit/theta/solver/z3legacy/Z3ExprTransformer.java index fdf8e4ac50..e219fa7260 100644 --- a/subprojects/solver/solver-z3-legacy/src/main/java/hu/bme/mit/theta/solver/z3legacy/Z3ExprTransformer.java +++ b/subprojects/solver/solver-z3-legacy/src/main/java/hu/bme/mit/theta/solver/z3legacy/Z3ExprTransformer.java @@ -18,12 +18,7 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.ImmutableList; -import com.microsoft.z3legacy.BitVecExpr; -import com.microsoft.z3legacy.BoolExpr; -import com.microsoft.z3legacy.Context; -import com.microsoft.z3legacy.FPExpr; -import com.microsoft.z3legacy.FPSort; -import com.microsoft.z3legacy.Sort; +import com.microsoft.z3legacy.*; import hu.bme.mit.theta.common.DispatchTable; import hu.bme.mit.theta.common.Tuple2; import hu.bme.mit.theta.common.dsl.Env; @@ -36,115 +31,18 @@ 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.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.arraytype.*; +import hu.bme.mit.theta.core.type.booltype.*; +import hu.bme.mit.theta.core.type.bvtype.*; +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.*; 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.type.inttype.*; +import hu.bme.mit.theta.core.type.rattype.*; import hu.bme.mit.theta.core.utils.BvUtils; import java.util.List; @@ -412,6 +310,14 @@ public Z3ExprTransformer(final Z3TransformationManager transformer, final Contex .addCase(Dereference.class, this::transformDereference) + // Enums + + .addCase(EnumLitExpr.class, this::transformEnumLit) + + .addCase(EnumEqExpr.class, this::transformEnumEq) + + .addCase(EnumNeqExpr.class, this::transformEnumNeq) + .build(); } @@ -1265,6 +1171,22 @@ private com.microsoft.z3legacy.Expr transformDereference(final Dereference LitExpr extractLiteral(final ConstDecl extractBvConstLiteral(final FuncDecl funcDecl) { } } + private LitExpr extractEnumLiteral(final ConstDecl constDecl, final FuncDecl funcDecl) { + return EnumLitExpr.of((EnumType) constDecl.getType(), z3Model.getConstInterp(funcDecl).toString()); + } + private LitExpr extractConstLiteral(final FuncDecl funcDecl) { final com.microsoft.z3legacy.Expr term = z3Model.getConstInterp(funcDecl); if (term == null) { diff --git a/subprojects/solver/solver-z3-legacy/src/main/java/hu/bme/mit/theta/solver/z3legacy/Z3TermTransformer.java b/subprojects/solver/solver-z3-legacy/src/main/java/hu/bme/mit/theta/solver/z3legacy/Z3TermTransformer.java index 3735daa6ce..a6944812b5 100644 --- a/subprojects/solver/solver-z3-legacy/src/main/java/hu/bme/mit/theta/solver/z3legacy/Z3TermTransformer.java +++ b/subprojects/solver/solver-z3-legacy/src/main/java/hu/bme/mit/theta/solver/z3legacy/Z3TermTransformer.java @@ -16,12 +16,9 @@ package hu.bme.mit.theta.solver.z3legacy; import com.google.common.collect.ImmutableList; -import com.microsoft.z3legacy.ArrayExpr; -import com.microsoft.z3legacy.ArraySort; -import com.microsoft.z3legacy.FPNum; -import com.microsoft.z3legacy.FuncDecl; -import com.microsoft.z3legacy.Model; -import com.microsoft.z3legacy.Z3Exception; +import com.microsoft.z3legacy.*; +import com.microsoft.z3legacy.enumerations.Z3_decl_kind; +import com.microsoft.z3legacy.enumerations.Z3_sort_kind; import hu.bme.mit.theta.common.TernaryOperator; import hu.bme.mit.theta.common.TriFunction; import hu.bme.mit.theta.common.Tuple2; @@ -30,23 +27,13 @@ import hu.bme.mit.theta.core.decl.ParamDecl; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.Type; -import hu.bme.mit.theta.core.type.abstracttype.AbstractExprs; -import hu.bme.mit.theta.core.type.abstracttype.EqExpr; import hu.bme.mit.theta.core.type.anytype.Exprs; +import hu.bme.mit.theta.core.type.abstracttype.*; import hu.bme.mit.theta.core.type.anytype.IteExpr; import hu.bme.mit.theta.core.type.anytype.PrimeExpr; import hu.bme.mit.theta.core.type.arraytype.ArrayReadExpr; import hu.bme.mit.theta.core.type.arraytype.ArrayType; 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.BoolType; -import hu.bme.mit.theta.core.type.booltype.FalseExpr; -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; @@ -99,6 +86,9 @@ 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.booltype.*; +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.fptype.FpRoundingMode; import hu.bme.mit.theta.core.type.fptype.FpSqrtExpr; import hu.bme.mit.theta.core.type.fptype.FpSubExpr; @@ -134,18 +124,13 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Preconditions.*; import static com.google.common.collect.ImmutableList.toImmutableList; import static hu.bme.mit.theta.common.Utils.head; import static hu.bme.mit.theta.common.Utils.tail; import static hu.bme.mit.theta.core.decl.Decls.Param; import static hu.bme.mit.theta.core.type.arraytype.ArrayExprs.Array; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.And; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Exists; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Forall; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.*; import static hu.bme.mit.theta.core.type.bvtype.BvExprs.BvType; import static hu.bme.mit.theta.core.type.functype.FuncExprs.App; import static hu.bme.mit.theta.core.type.functype.FuncExprs.Func; @@ -477,6 +462,12 @@ private Expr transformFpLit(final com.microsoft.z3legacy.Expr term) { return FpUtils.bigFloatToFpLitExpr(bigFloat, type); } + private Expr transformEnumLit(final com.microsoft.z3legacy.Expr term, final EnumType enumType) { + String longName = term.getFuncDecl().getName().toString(); + String literal = EnumType.getShortName(longName); + return EnumLitExpr.of(enumType, literal); + } + private Expr transformApp(final com.microsoft.z3legacy.Expr term, final Model model, final List> vars) { @@ -746,6 +737,22 @@ private Tuple2 { final com.microsoft.z3legacy.Expr[] args = term.getArgs(); checkArgument(args.length == 2, "Number of arguments must be two"); + if (args[0].getSort().getSortKind().equals(Z3_sort_kind.Z3_DATATYPE_SORT)) { + // binary operator is on enum types + // if either arg is a literal, we need special handling to get its type + // (references' decl kind is Z3_OP_UNINTERPRETED, literals' decl kind is Z3_OP_DT_CONSTRUCTOR) + int litIndex = -1; + for (int i = 0; i < 2; i++) { + if (args[i].getFuncDecl().getDeclKind().equals(Z3_decl_kind.Z3_OP_DT_CONSTRUCTOR)) + litIndex = i; + } + if (litIndex > -1) { + int refIndex = Math.abs(litIndex - 1); + final Expr refOp = transform(args[refIndex], model, vars); + final Expr litExpr = transformEnumLit(args[litIndex], (EnumType) refOp.getType()); + return function.apply(refOp, litExpr); + } + } final Expr op1 = transform(args[0], model, vars); final Expr op2 = transform(args[1], model, vars); return function.apply(op1, op2); diff --git a/subprojects/solver/solver-z3-legacy/src/main/java/hu/bme/mit/theta/solver/z3legacy/Z3TypeTransformer.java b/subprojects/solver/solver-z3-legacy/src/main/java/hu/bme/mit/theta/solver/z3legacy/Z3TypeTransformer.java index 425abec7d3..10beea35d3 100644 --- a/subprojects/solver/solver-z3-legacy/src/main/java/hu/bme/mit/theta/solver/z3legacy/Z3TypeTransformer.java +++ b/subprojects/solver/solver-z3-legacy/src/main/java/hu/bme/mit/theta/solver/z3legacy/Z3TypeTransformer.java @@ -17,17 +17,17 @@ import com.google.common.collect.Sets; import com.microsoft.z3legacy.Context; +import com.microsoft.z3legacy.EnumSort; 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.BvType; +import hu.bme.mit.theta.core.type.enumtype.EnumType; import hu.bme.mit.theta.core.type.fptype.FpType; import hu.bme.mit.theta.core.type.inttype.IntType; import hu.bme.mit.theta.core.type.rattype.RatType; -import java.util.Optional; -import java.util.Set; -import java.util.TreeSet; +import java.util.*; final class Z3TypeTransformer { @@ -40,6 +40,7 @@ final class Z3TypeTransformer { private final com.microsoft.z3legacy.RealSort realSort; private final Set bvSorts; private final Set fpSorts; + private final Map enumSorts; Z3TypeTransformer(final Z3TransformationManager transformer, final Context context) { this.context = context; @@ -50,6 +51,7 @@ final class Z3TypeTransformer { realSort = context.mkRealSort(); bvSorts = Sets.synchronizedNavigableSet(new TreeSet<>()); fpSorts = Sets.synchronizedNavigableSet(new TreeSet<>()); + enumSorts = new HashMap<>(); } public com.microsoft.z3legacy.Sort toSort(final Type type) { @@ -89,9 +91,11 @@ public com.microsoft.z3legacy.Sort toSort(final Type type) { final com.microsoft.z3legacy.Sort indexSort = toSort(arrayType.getIndexType()); final com.microsoft.z3legacy.Sort elemSort = toSort(arrayType.getElemType()); return context.mkArraySort(indexSort, elemSort); + } else if (type instanceof EnumType enumType) { + return enumSorts.computeIfAbsent(enumType.getName(), key -> createEnumSort(enumType)); } else { throw new UnsupportedOperationException( - "Unsupporte type: " + type.getClass().getSimpleName()); + "Unsupported type: " + type.getClass().getSimpleName()); } } @@ -99,4 +103,8 @@ public void reset() { bvSorts.clear(); } + private EnumSort createEnumSort(EnumType enumType) { + return context.mkEnumSort(enumType.getName(), enumType.getValues().stream().map(lit -> EnumType.makeLongName(enumType, lit)).toArray(String[]::new)); + } + } diff --git a/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java b/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java index 9893b19ff2..191e9ff030 100644 --- a/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java +++ b/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3ExprTransformer.java @@ -18,11 +18,7 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.ImmutableList; -import com.microsoft.z3.BitVecExpr; -import com.microsoft.z3.BoolExpr; -import com.microsoft.z3.Context; -import com.microsoft.z3.FPExpr; -import com.microsoft.z3.FPSort; +import com.microsoft.z3.*; import hu.bme.mit.theta.common.DispatchTable; import hu.bme.mit.theta.common.Tuple2; import hu.bme.mit.theta.common.dsl.Env; @@ -34,115 +30,18 @@ import hu.bme.mit.theta.core.type.Type; 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.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.arraytype.*; +import hu.bme.mit.theta.core.type.booltype.*; +import hu.bme.mit.theta.core.type.bvtype.*; +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.*; 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.type.inttype.*; +import hu.bme.mit.theta.core.type.rattype.*; import hu.bme.mit.theta.core.utils.BvUtils; import java.util.List; @@ -403,6 +302,14 @@ public Z3ExprTransformer(final Z3TransformationManager transformer, final Contex .addCase(ArrayInitExpr.class, this::transformArrayInit) + // Enums + + .addCase(EnumLitExpr.class, this::transformEnumLit) + + .addCase(EnumEqExpr.class, this::transformEnumEq) + + .addCase(EnumNeqExpr.class, this::transformEnumNeq) + .build(); } @@ -1248,6 +1155,23 @@ private com.microsoft.z3.Expr transformFuncApp(final FuncAppExpr expr) { } } + private com.microsoft.z3.Expr transformEnumLit(final EnumLitExpr expr) { + EnumType enumType = expr.getType(); + return ((EnumSort) transformer.toSort(enumType)).getConst(enumType.getIntValue(expr.getValue())); + } + + private com.microsoft.z3.Expr transformEnumEq(final EnumEqExpr expr) { + final com.microsoft.z3.Expr leftOpTerm = toTerm(expr.getLeftOp()); + final com.microsoft.z3.Expr rightOpTerm = toTerm(expr.getRightOp()); + return context.mkEq(leftOpTerm, rightOpTerm); + } + + private com.microsoft.z3.Expr transformEnumNeq(final EnumNeqExpr expr) { + final com.microsoft.z3.Expr leftOpTerm = toTerm(expr.getLeftOp()); + final com.microsoft.z3.Expr rightOpTerm = toTerm(expr.getRightOp()); + return context.mkNot(context.mkEq(leftOpTerm, rightOpTerm)); + } + public void reset() { exprToTerm.invalidateAll(); } diff --git a/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3Solver.java b/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3Solver.java index 945c771af7..390da9a8c3 100644 --- a/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3Solver.java +++ b/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3Solver.java @@ -29,20 +29,14 @@ 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.UnknownSolverStatusException; +import hu.bme.mit.theta.solver.*; import hu.bme.mit.theta.solver.impl.StackImpl; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedList; -import java.util.Map; -import java.util.Optional; +import java.util.*; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; @@ -287,6 +281,8 @@ private LitExpr extractLiteral(final ConstDecl extractBvConstLiteral(final FuncDecl funcDecl) { } } + private LitExpr extractEnumLiteral(final ConstDecl constDecl, final FuncDecl funcDecl) { + return EnumLitExpr.of((EnumType) constDecl.getType(), z3Model.getConstInterp(funcDecl).toString()); + } + private LitExpr extractConstLiteral(final FuncDecl funcDecl) { final com.microsoft.z3.Expr term = z3Model.getConstInterp(funcDecl); if (term == null) { diff --git a/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TermTransformer.java b/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TermTransformer.java index 71bd9ac6ed..d1999f5c94 100644 --- a/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TermTransformer.java +++ b/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TermTransformer.java @@ -16,12 +16,9 @@ package hu.bme.mit.theta.solver.z3; import com.google.common.collect.ImmutableList; -import com.microsoft.z3.ArrayExpr; -import com.microsoft.z3.ArraySort; -import com.microsoft.z3.FPNum; -import com.microsoft.z3.FuncDecl; -import com.microsoft.z3.Model; -import com.microsoft.z3.Z3Exception; +import com.microsoft.z3.*; +import com.microsoft.z3.enumerations.Z3_decl_kind; +import com.microsoft.z3.enumerations.Z3_sort_kind; import hu.bme.mit.theta.common.TernaryOperator; import hu.bme.mit.theta.common.TriFunction; import hu.bme.mit.theta.common.Tuple2; @@ -30,25 +27,14 @@ import hu.bme.mit.theta.core.decl.ParamDecl; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.Type; -import hu.bme.mit.theta.core.type.abstracttype.AddExpr; -import hu.bme.mit.theta.core.type.abstracttype.EqExpr; -import hu.bme.mit.theta.core.type.abstracttype.GeqExpr; -import hu.bme.mit.theta.core.type.abstracttype.GtExpr; -import hu.bme.mit.theta.core.type.abstracttype.LeqExpr; -import hu.bme.mit.theta.core.type.abstracttype.LtExpr; -import hu.bme.mit.theta.core.type.abstracttype.MulExpr; +import hu.bme.mit.theta.core.type.abstracttype.*; import hu.bme.mit.theta.core.type.anytype.IteExpr; import hu.bme.mit.theta.core.type.arraytype.ArrayReadExpr; import hu.bme.mit.theta.core.type.arraytype.ArrayType; 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.BoolType; -import hu.bme.mit.theta.core.type.booltype.FalseExpr; -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.*; +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.fptype.FpRoundingMode; import hu.bme.mit.theta.core.type.fptype.FpType; import hu.bme.mit.theta.core.type.functype.FuncType; @@ -74,18 +60,13 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Preconditions.*; import static com.google.common.collect.ImmutableList.toImmutableList; import static hu.bme.mit.theta.common.Utils.head; import static hu.bme.mit.theta.common.Utils.tail; import static hu.bme.mit.theta.core.decl.Decls.Param; import static hu.bme.mit.theta.core.type.arraytype.ArrayExprs.Array; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.And; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Exists; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Forall; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.*; import static hu.bme.mit.theta.core.type.bvtype.BvExprs.BvType; import static hu.bme.mit.theta.core.type.functype.FuncExprs.App; import static hu.bme.mit.theta.core.type.functype.FuncExprs.Func; @@ -271,6 +252,12 @@ private Expr transformFpLit(final com.microsoft.z3.Expr term) { return FpUtils.bigFloatToFpLitExpr(bigFloat, type); } + private Expr transformEnumLit(final com.microsoft.z3.Expr term, final EnumType enumType) { + String longName = term.getFuncDecl().getName().toString(); + String literal = EnumType.getShortName(longName); + return EnumLitExpr.of(enumType, literal); + } + private Expr transformApp(final com.microsoft.z3.Expr term, final Model model, final List> vars) { @@ -494,6 +481,22 @@ private TriFunction>, Expr> exprBi return (term, model, vars) -> { final com.microsoft.z3.Expr[] args = term.getArgs(); checkArgument(args.length == 2, "Number of arguments must be two"); + if (args[0].getSort().getSortKind().equals(Z3_sort_kind.Z3_DATATYPE_SORT)) { + // binary operator is on enum types + // if either arg is a literal, we need special handling to get its type + // (references' decl kind is Z3_OP_UNINTERPRETED, literals' decl kind is Z3_OP_DT_CONSTRUCTOR) + int litIndex = -1; + for (int i = 0; i < 2; i++) { + if (args[i].getFuncDecl().getDeclKind().equals(Z3_decl_kind.Z3_OP_DT_CONSTRUCTOR)) + litIndex = i; + } + if (litIndex > -1) { + int refIndex = Math.abs(litIndex - 1); + final Expr refOp = transform(args[refIndex], model, vars); + final Expr litExpr = transformEnumLit(args[litIndex], (EnumType) refOp.getType()); + return function.apply(refOp, litExpr); + } + } final Expr op1 = transform(args[0], model, vars); final Expr op2 = transform(args[1], model, vars); return function.apply(op1, op2); diff --git a/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TypeTransformer.java b/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TypeTransformer.java index 54e6583711..43f3133beb 100644 --- a/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TypeTransformer.java +++ b/subprojects/solver/solver-z3/src/main/java/hu/bme/mit/theta/solver/z3/Z3TypeTransformer.java @@ -17,17 +17,17 @@ import com.google.common.collect.Sets; import com.microsoft.z3.Context; +import com.microsoft.z3.EnumSort; 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.BvType; +import hu.bme.mit.theta.core.type.enumtype.EnumType; import hu.bme.mit.theta.core.type.fptype.FpType; import hu.bme.mit.theta.core.type.inttype.IntType; import hu.bme.mit.theta.core.type.rattype.RatType; -import java.util.Optional; -import java.util.Set; -import java.util.TreeSet; +import java.util.*; final class Z3TypeTransformer { @@ -40,6 +40,7 @@ final class Z3TypeTransformer { private final com.microsoft.z3.RealSort realSort; private final Set bvSorts; private final Set fpSorts; + private final Map enumSorts; Z3TypeTransformer(final Z3TransformationManager transformer, final Context context) { this.context = context; @@ -50,6 +51,7 @@ final class Z3TypeTransformer { realSort = context.mkRealSort(); bvSorts = Sets.synchronizedNavigableSet(new TreeSet<>()); fpSorts = Sets.synchronizedNavigableSet(new TreeSet<>()); + enumSorts = new HashMap<>(); } public com.microsoft.z3.Sort toSort(final Type type) { @@ -89,9 +91,11 @@ public com.microsoft.z3.Sort toSort(final Type type) { final com.microsoft.z3.Sort indexSort = toSort(arrayType.getIndexType()); final com.microsoft.z3.Sort elemSort = toSort(arrayType.getElemType()); return context.mkArraySort(indexSort, elemSort); + } else if (type instanceof EnumType enumType) { + return enumSorts.computeIfAbsent(enumType.getName(), key -> createEnumSort(enumType)); } else { throw new UnsupportedOperationException( - "Unsupporte type: " + type.getClass().getSimpleName()); + "Unsupported type: " + type.getClass().getSimpleName()); } } @@ -99,4 +103,8 @@ public void reset() { bvSorts.clear(); } + private EnumSort createEnumSort(EnumType enumType) { + return context.mkEnumSort(enumType.getName(), enumType.getValues().stream().map(lit -> EnumType.makeLongName(enumType, lit)).toArray(String[]::new)); + } + } diff --git a/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsEnumSemanticsTest.java b/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsEnumSemanticsTest.java new file mode 100644 index 0000000000..7a24971164 --- /dev/null +++ b/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsEnumSemanticsTest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023 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.xsts.analysis; + +import hu.bme.mit.theta.xsts.dsl.XstsDslManager; +import org.junit.Test; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.SequenceInputStream; + +public class XstsEnumSemanticsTest { + + @Test(expected = ClassCastException.class) + public void test() throws IOException { + + try (InputStream inputStream = new SequenceInputStream(new FileInputStream("src/test/resources/model/literals_bad.xsts"), + new FileInputStream("src/test/resources/property/literals.prop"))) { + XstsDslManager.createXsts(inputStream); + } + } + +} diff --git a/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsTest.java b/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsTest.java index c525e93876..049fb17dc3 100644 --- a/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsTest.java +++ b/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsTest.java @@ -132,13 +132,13 @@ public static Collection data() { false, XstsConfigBuilder.Domain.EXPL_PRED_COMBINED}, {"src/test/resources/model/literals.xsts", "src/test/resources/property/literals.prop", - true, XstsConfigBuilder.Domain.PRED_CART}, + false, XstsConfigBuilder.Domain.PRED_CART}, {"src/test/resources/model/literals.xsts", "src/test/resources/property/literals.prop", - true, XstsConfigBuilder.Domain.EXPL}, + false, XstsConfigBuilder.Domain.EXPL}, {"src/test/resources/model/literals.xsts", "src/test/resources/property/literals.prop", - true, XstsConfigBuilder.Domain.EXPL_PRED_COMBINED}, + false, XstsConfigBuilder.Domain.EXPL_PRED_COMBINED}, {"src/test/resources/model/cross3.xsts", "src/test/resources/property/cross.prop", false, XstsConfigBuilder.Domain.PRED_CART}, diff --git a/subprojects/xsts/xsts-analysis/src/test/resources/model/literals.xsts b/subprojects/xsts/xsts-analysis/src/test/resources/model/literals.xsts index d7346a37dd..2c90cae3ff 100644 --- a/subprojects/xsts/xsts-analysis/src/test/resources/model/literals.xsts +++ b/subprojects/xsts/xsts-analysis/src/test/resources/model/literals.xsts @@ -1,8 +1,7 @@ -type first : { A, B, C, D } -type second : { D, C, B, A } +type alphabet : { A, B, C, D } -var f : first = A -var s : second = A +var f : alphabet = A +var g : alphabet = B trans {} diff --git a/subprojects/xsts/xsts-analysis/src/test/resources/model/literals_bad.xsts b/subprojects/xsts/xsts-analysis/src/test/resources/model/literals_bad.xsts new file mode 100644 index 0000000000..f39e84ee5e --- /dev/null +++ b/subprojects/xsts/xsts-analysis/src/test/resources/model/literals_bad.xsts @@ -0,0 +1,11 @@ +type alphabet : { A, B, C, D } +type second_alphabet : { A, B, C, D } + +var f : alphabet = A +var g : second_alphabet = A + +trans {} + +init {} + +env {} \ No newline at end of file diff --git a/subprojects/xsts/xsts-analysis/src/test/resources/property/literals.prop b/subprojects/xsts/xsts-analysis/src/test/resources/property/literals.prop index 434d7eca1d..a775a9d572 100644 --- a/subprojects/xsts/xsts-analysis/src/test/resources/property/literals.prop +++ b/subprojects/xsts/xsts-analysis/src/test/resources/property/literals.prop @@ -1,3 +1,3 @@ prop { - f == s + f == g } \ No newline at end of file diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/CustomTypeDeclarationUtil.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/CustomTypeDeclarationUtil.java new file mode 100644 index 0000000000..57694872c4 --- /dev/null +++ b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/CustomTypeDeclarationUtil.java @@ -0,0 +1,46 @@ +/* + * 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.xsts.dsl; + +import hu.bme.mit.theta.common.dsl.DynamicScope; +import hu.bme.mit.theta.common.dsl.Env; +import hu.bme.mit.theta.common.dsl.Symbol; +import hu.bme.mit.theta.core.type.enumtype.EnumType; + +import java.util.Optional; + +public final class CustomTypeDeclarationUtil { + + private CustomTypeDeclarationUtil() { + } + + public static void declareTypeWithShortName(DynamicScope currentScope, EnumType enumType, String literal, Env env) { + Symbol fullNameSymbol = currentScope.resolve(EnumType.makeLongName(enumType, literal)).orElseThrow(); + if (fullNameSymbol instanceof XstsCustomLiteralSymbol fNameCustLitSymbol) { + var customSymbol = XstsCustomLiteralSymbol.copyWithName(fNameCustLitSymbol, literal); + Optional optionalSymbol = currentScope.resolve(literal); + if (optionalSymbol.isPresent()) { + env.define(optionalSymbol.get(), customSymbol.instantiate()); + } else { + currentScope.declare(customSymbol); + env.define(customSymbol, customSymbol.instantiate()); + } + } else { + throw new IllegalArgumentException(String.format("%s is not a literal of type %s", literal, enumType.getName())); + } + } + +} diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsCustomLiteralSymbol.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsCustomLiteralSymbol.java index 34f8d1f34b..22be26aa81 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsCustomLiteralSymbol.java +++ b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsCustomLiteralSymbol.java @@ -17,37 +17,40 @@ import hu.bme.mit.theta.common.dsl.Symbol; import hu.bme.mit.theta.core.type.Expr; -import hu.bme.mit.theta.xsts.type.XstsCustomType; - -import java.math.BigInteger; - -import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; +import hu.bme.mit.theta.core.type.enumtype.EnumLitExpr; +import hu.bme.mit.theta.core.type.enumtype.EnumType; public class XstsCustomLiteralSymbol implements Symbol { - private final XstsCustomType.XstsCustomLiteral literal; + private final EnumType type; - private static int counter = 0; + private final String literal; + + public XstsCustomLiteralSymbol(EnumType type, String literal) { + this.type = type; + this.literal = literal; + } - public XstsCustomLiteralSymbol(String name) { - this.literal = XstsCustomType.XstsCustomLiteral.of(name, BigInteger.valueOf(counter++)); + public static XstsCustomLiteralSymbol of(EnumType type, String literal) { + return new XstsCustomLiteralSymbol(type, literal); } @Override public String getName() { - return literal.getName(); + return literal; } @Override public String toString() { - return literal.toString(); + return literal; } public Expr instantiate() { - return Int(literal.getIntValue()); + return EnumLitExpr.of(type, EnumType.getShortName(literal)); } - public XstsCustomType.XstsCustomLiteral getLiteral() { - return literal; + public static XstsCustomLiteralSymbol copyWithName(XstsCustomLiteralSymbol symbol, String newName) { + return new XstsCustomLiteralSymbol(symbol.type, newName); } + } diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsCustomTypeSymbol.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsCustomTypeSymbol.java index e0dda61fb4..8fc41e1565 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsCustomTypeSymbol.java +++ b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsCustomTypeSymbol.java @@ -17,25 +17,25 @@ import hu.bme.mit.theta.common.dsl.Symbol; import hu.bme.mit.theta.core.type.Type; -import hu.bme.mit.theta.xsts.type.XstsCustomType; +import hu.bme.mit.theta.core.type.enumtype.EnumType; import java.util.Objects; public final class XstsCustomTypeSymbol implements Symbol { - private XstsCustomType xstsType; + private final EnumType enumType; - private XstsCustomTypeSymbol(final XstsCustomType xstsType) { - this.xstsType = xstsType; + private XstsCustomTypeSymbol(final EnumType enumType) { + this.enumType = enumType; } - public static XstsCustomTypeSymbol of(final XstsCustomType xstsType) { + public static XstsCustomTypeSymbol of(final EnumType xstsType) { return new XstsCustomTypeSymbol(xstsType); } @Override public int hashCode() { - return Objects.hash(xstsType); + return Objects.hash(enumType); } @Override @@ -44,7 +44,7 @@ public boolean equals(final Object obj) { return true; } else if (obj != null && this.getClass() == obj.getClass()) { final XstsCustomTypeSymbol that = (XstsCustomTypeSymbol) obj; - return this.xstsType.equals(that.xstsType); + return this.enumType.equals(that.enumType); } else { return false; } @@ -52,19 +52,15 @@ public boolean equals(final Object obj) { @Override public String toString() { - return xstsType.toString(); - } - - public XstsCustomType getXstsType() { - return xstsType; + return enumType.toString(); } @Override public String getName() { - return xstsType.getName(); + return enumType.getName(); } public Type instantiate() { - return xstsType.getType(); + return enumType; } } diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsExpression.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsExpression.java index e091e9c2a3..7b8ed8b139 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsExpression.java +++ b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsExpression.java @@ -25,16 +25,13 @@ import hu.bme.mit.theta.core.dsl.ParseException; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.Type; -import hu.bme.mit.theta.core.type.abstracttype.AddExpr; -import hu.bme.mit.theta.core.type.abstracttype.DivExpr; -import hu.bme.mit.theta.core.type.abstracttype.ModExpr; -import hu.bme.mit.theta.core.type.abstracttype.MulExpr; -import hu.bme.mit.theta.core.type.abstracttype.RemExpr; -import hu.bme.mit.theta.core.type.abstracttype.SubExpr; +import hu.bme.mit.theta.core.type.abstracttype.*; 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.booltype.FalseExpr; import hu.bme.mit.theta.core.type.booltype.TrueExpr; +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.inttype.IntLitExpr; import hu.bme.mit.theta.xsts.dsl.gen.XstsDslBaseVisitor; import org.antlr.v4.runtime.Token; @@ -51,69 +48,15 @@ import static com.google.common.base.Preconditions.checkNotNull; import static hu.bme.mit.theta.common.Utils.head; import static hu.bme.mit.theta.common.Utils.tail; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Add; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Div; import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Eq; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Geq; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Gt; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Ite; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Leq; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Lt; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Mod; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Mul; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Neg; import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Neq; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Pos; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Rem; -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Sub; +import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.*; import static hu.bme.mit.theta.core.type.arraytype.ArrayExprs.*; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.And; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.False; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Iff; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Imply; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Not; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Or; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.True; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Xor; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.*; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; import static hu.bme.mit.theta.core.utils.ExprUtils.simplify; import static hu.bme.mit.theta.core.utils.TypeUtils.cast; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.AccessContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.AccessorExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.AdditiveExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.AndExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.ArrLitExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.ArrayReadAccessContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.ArrayWriteAccessContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.DIV; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.EQ; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.EqualityExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.ExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.FalseExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.GEQ; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.GT; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.IdExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.IffExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.ImplyExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.IntLitExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.IteExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.LEQ; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.LT; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.MINUS; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.MOD; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.MUL; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.MultiplicativeExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.NEQ; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.NotExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.OrExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.PLUS; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.ParenExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.REM; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.RelationExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.TrueExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.UnaryExprContext; -import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.XorExprContext; +import static hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.*; import static java.util.stream.Collectors.toList; final class XstsExpression { @@ -234,17 +177,29 @@ public Expr visitNotExpr(final NotExprContext ctx) { @Override public Expr visitEqualityExpr(final EqualityExprContext ctx) { if (ctx.rightOp != null) { - final Expr leftOp = ctx.leftOp.accept(this); - final Expr rightOp = ctx.rightOp.accept(this); - - switch (ctx.oper.getType()) { - case EQ: - return Eq(leftOp, rightOp); - case NEQ: - return Neq(leftOp, rightOp); - default: - throw new ParseException(ctx, "Unknown operator"); + Expr leftOp; + boolean inverse = false; + final Expr rightOp; + try { + leftOp = ctx.leftOp.accept(this); + } catch (ParseException e) { + // It's possible that the left side is an enum literal + // So we have to parse enum type from the right side first + leftOp = ctx.rightOp.accept(this); + inverse = true; + } + if (leftOp.getType() instanceof EnumType enumType) { + env.push(); + enumType.getValues().forEach(literal -> CustomTypeDeclarationUtil.declareTypeWithShortName(currentScope, enumType, literal, env)); } + rightOp = (inverse ? ctx.leftOp : ctx.rightOp).accept(this); + if (leftOp.getType() instanceof EnumType) + env.pop(); + return switch (ctx.oper.getType()) { + case EQ -> Eq(leftOp, rightOp); + case NEQ -> Neq(leftOp, rightOp); + default -> throw new ParseException(ctx, "Unknown operator"); + }; } else { return visitChildren(ctx); @@ -550,10 +505,9 @@ public Expr visitIdExpr(final IdExprContext ctx) { } final Symbol symbol = optSymbol.get(); final Object val = env.eval(symbol); - if (val instanceof IntLitExpr) { - return (IntLitExpr) val; - } else if (val instanceof Decl) { - final Decl decl = (Decl) val; + if (val instanceof EnumLitExpr enumLiteral) { + return enumLiteral; + } else if (val instanceof Decl decl) { return decl.getRef(); } throw new ParseException(ctx, diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsSpecification.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsSpecification.java index 4193024142..6f754c056e 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsSpecification.java +++ b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsSpecification.java @@ -22,6 +22,7 @@ import hu.bme.mit.theta.core.stmt.NonDetStmt; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.booltype.BoolType; +import hu.bme.mit.theta.core.type.enumtype.EnumType; import hu.bme.mit.theta.core.utils.ExprUtils; import hu.bme.mit.theta.xsts.XSTS; import hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.XstsContext; @@ -30,12 +31,11 @@ import java.util.*; import java.util.regex.Pattern; -import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Eq; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.*; -import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.And; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; import static hu.bme.mit.theta.core.utils.TypeUtils.cast; public class XstsSpecification implements DynamicScope { @@ -43,6 +43,7 @@ public class XstsSpecification implements DynamicScope { private final SymbolTable symbolTable; private final SymbolTable typeTable; private final XstsContext context; + private final Set customTypeShortNames; private final Pattern tempVarPattern = Pattern.compile("temp([0-9])+"); @@ -50,6 +51,7 @@ public XstsSpecification(XstsContext context) { this.context = checkNotNull(context); this.symbolTable = new SymbolTable(); this.typeTable = new SymbolTable(); + customTypeShortNames = Containers.createSet(); } @Override @@ -70,33 +72,34 @@ public XSTS instantiate() { final List> initExprs = new ArrayList<>(); for (var typeDeclContext : context.typeDeclarations) { - final List literalSymbols = new ArrayList<>(); - for (var literalContext : typeDeclContext.literals) { - var optSymbol = resolve(literalContext.name.getText()); - if (optSymbol.isPresent()) { - literalSymbols.add((XstsCustomLiteralSymbol) optSymbol.get()); - } else { - var symbol = new XstsCustomLiteralSymbol(literalContext.name.getText()); - literalSymbols.add(symbol); - declare(symbol); - env.define(symbol, symbol.instantiate()); - } - } - final List literals = literalSymbols.stream() - .map(XstsCustomLiteralSymbol::getLiteral).collect(Collectors.toList()); - final XstsCustomType xstsCustomType = XstsCustomType.of(typeDeclContext.name.getText(), - literals); - - final XstsCustomTypeSymbol typeDeclSymbol = XstsCustomTypeSymbol.of(xstsCustomType); + final String typeName = typeDeclContext.name.getText(); + final List literalNames = new ArrayList<>(); + typeDeclContext.literals.forEach(litCtx -> literalNames.add(litCtx.name.getText())); + customTypeShortNames.addAll(literalNames); + final EnumType enumType = EnumType.of(typeName, literalNames); + literalNames + .stream() + .map(litName -> EnumType.makeLongName(enumType, litName)) + .map(fullLitName -> XstsCustomLiteralSymbol.of(enumType, fullLitName)) + .forEach(symbol -> { + declare(symbol); + env.define(symbol, symbol.instantiate()); + }); + + final XstsCustomTypeSymbol typeDeclSymbol = XstsCustomTypeSymbol.of(enumType); typeTable.add(typeDeclSymbol); - env.define(typeDeclSymbol, typeDeclSymbol.getXstsType()); + env.define(typeDeclSymbol, XstsCustomType.of(enumType)); } for (var varDeclContext : context.variableDeclarations) { - if (tempVarPattern.matcher(varDeclContext.name.getText()).matches()) { + final String varName = varDeclContext.name.getText(); + if (tempVarPattern.matcher(varName).matches()) { throw new ParseException(varDeclContext, - "Variable name '" + varDeclContext.name.getText() + "' is reserved!"); + "Variable name '" + varName + "' is reserved!"); } + if (customTypeShortNames.contains(varName)) + throw new ParseException(varDeclContext, + String.format("Variable name '%s' matches at least one declared enum literal", varName)); final XstsVariableSymbol symbol = new XstsVariableSymbol(typeTable, varToType, varDeclContext); @@ -107,9 +110,25 @@ public XSTS instantiate() { ctrlVars.add(var); } if (varDeclContext.initValue != null) { + var scope = new BasicDynamicScope(this); + if (var.getType() instanceof EnumType enumType) { + env.push(); + enumType.getValues().forEach(literal -> { + Symbol fullNameSymbol = resolve(String.format("%s%s%s", enumType.getName(), EnumType.FULLY_QUALIFIED_NAME_SEPARATOR, literal)).orElseThrow(); + if (fullNameSymbol instanceof XstsCustomLiteralSymbol fNameCustLitSymbol) { + var customSymbol = XstsCustomLiteralSymbol.copyWithName(fNameCustLitSymbol, literal); + scope.declare(customSymbol); + env.define(customSymbol, customSymbol.instantiate()); + } else { + throw new IllegalArgumentException(String.format("%s is not a literal of type %s", literal, enumType.getName())); + } + }); + } initExprs.add(Eq(var.getRef(), - new XstsExpression(this, typeTable, varDeclContext.initValue).instantiate( + new XstsExpression(scope, typeTable, varDeclContext.initValue).instantiate( env))); + if (var.getType() instanceof EnumType) + env.pop(); } env.define(symbol, var); } diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsStatement.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsStatement.java index 1666d3acc0..c6d50e75f3 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsStatement.java +++ b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsStatement.java @@ -15,17 +15,19 @@ */ package hu.bme.mit.theta.xsts.dsl; -import com.google.common.collect.ImmutableList; import hu.bme.mit.theta.common.dsl.*; import hu.bme.mit.theta.core.decl.Decls; import hu.bme.mit.theta.core.decl.VarDecl; import hu.bme.mit.theta.core.dsl.DeclSymbol; import hu.bme.mit.theta.core.dsl.ParseException; +import hu.bme.mit.theta.core.stmt.NonDetStmt; +import hu.bme.mit.theta.core.stmt.SequenceStmt; import hu.bme.mit.theta.core.stmt.*; import hu.bme.mit.theta.core.type.Expr; 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.enumtype.EnumType; import hu.bme.mit.theta.core.type.inttype.IntType; import hu.bme.mit.theta.xsts.dsl.gen.XstsDslBaseVisitor; import hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.*; @@ -39,7 +41,6 @@ import static hu.bme.mit.theta.core.stmt.Stmts.*; import static hu.bme.mit.theta.core.type.arraytype.ArrayExprs.Write; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Or; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; import static hu.bme.mit.theta.core.utils.TypeUtils.cast; @@ -128,10 +129,15 @@ public Stmt visitAssignStmt(final AssignStmtContext ctx) { final Symbol lhsSymbol = currentScope.resolve(lhsId).get(); final VarDecl var = (VarDecl) env.eval(lhsSymbol); + if (var.getType() instanceof EnumType enumType) { + env.push(); + enumType.getValues().forEach(literal -> CustomTypeDeclarationUtil.declareTypeWithShortName(currentScope, enumType, literal, env)); + } final XstsExpression expression = new XstsExpression(currentScope, typeTable, ctx.value); final Expr expr = expression.instantiate(env); - + if (var.getType() instanceof EnumType) + env.pop(); if (expr.getType().equals(var.getType())) { @SuppressWarnings("unchecked") final VarDecl tVar = (VarDecl) var; @SuppressWarnings("unchecked") final Expr tExpr = (Expr) expr; diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsCustomType.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsCustomType.java index 43093d0618..8945780e54 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsCustomType.java +++ b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsCustomType.java @@ -15,85 +15,46 @@ */ package hu.bme.mit.theta.xsts.type; -import com.google.common.base.Preconditions; import hu.bme.mit.theta.core.decl.VarDecl; import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.LitExpr; import hu.bme.mit.theta.core.type.booltype.BoolType; -import hu.bme.mit.theta.core.type.inttype.IntLitExpr; -import hu.bme.mit.theta.core.type.inttype.IntType; - -import java.math.BigInteger; -import java.util.List; -import java.util.stream.Collectors; +import hu.bme.mit.theta.core.type.enumtype.EnumLitExpr; +import hu.bme.mit.theta.core.type.enumtype.EnumType; import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Eq; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Or; -import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; -public final class XstsCustomType implements XstsType { +public final class XstsCustomType implements XstsType { - private final String name; - private final List literals; + private final EnumType type; - private XstsCustomType(final String name, final List literals) { - this.name = name; - this.literals = literals; + private XstsCustomType(EnumType type) { + this.type = type; } - public static XstsCustomType of(final String name, final List literals) { - return new XstsCustomType(name, literals); + public static XstsCustomType of(EnumType type) { + return new XstsCustomType(type); } public String getName() { - return name; - } - - public List getLiterals() { - return literals; + return type.getName(); } - public static final class XstsCustomLiteral { - - private final BigInteger intValue; - private final String name; - - private XstsCustomLiteral(String name, BigInteger intValue) { - this.name = name; - this.intValue = intValue; - } - - public static XstsCustomLiteral of(String name, BigInteger intValue) { - return new XstsCustomLiteral(name, intValue); - } - - public BigInteger getIntValue() { - return intValue; - } - - public String getName() { - return name; - } - } - - public IntType getType() { - return Int(); + @Override + public EnumType getType() { + return type; } @Override - public Expr createBoundExpr(VarDecl decl) { - return Or(literals.stream() - .map(lit -> Eq(decl.getRef(), Int(lit.getIntValue()))) - .collect(Collectors.toList())); + public Expr createBoundExpr(VarDecl decl) { + return Or(type.getValues().stream() + .map(lit -> Eq(decl.getRef(), EnumLitExpr.of(type, lit))) + .toList()); } @Override - public String serializeLiteral(LitExpr literal) { - final IntLitExpr intLitExpr = (IntLitExpr) literal; - final var customLiteral = literals.stream() - .filter(lit -> lit.getIntValue().equals(intLitExpr.getValue())).findFirst(); - Preconditions.checkArgument(customLiteral.isPresent(), "Literal %s not found", - intLitExpr.getValue()); - return customLiteral.get().getName(); + public String serializeLiteral(LitExpr literal) { + return literal.toString(); } } From 37ba2782029790130963f357bf2c7290384c7d55 Mon Sep 17 00:00:00 2001 From: RipplB Date: Mon, 2 Oct 2023 16:42:42 +0200 Subject: [PATCH 3/8] Remove xsts type layer from above native types --- .../concretizer/XstsStateSequence.java | 17 +---- .../xsts/analysis/XstsEnumSemanticsTest.java | 2 +- .../main/java/hu/bme/mit/theta/xsts/XSTS.java | 14 ++-- .../mit/theta/xsts/dsl/XstsExpression.java | 2 +- .../mit/theta/xsts/dsl/XstsSpecification.java | 21 ++---- .../bme/mit/theta/xsts/dsl/XstsStatement.java | 33 ++------- .../mit/theta/xsts/dsl/XstsTransitionSet.java | 14 ++-- .../hu/bme/mit/theta/xsts/dsl/XstsType.java | 31 ++++---- .../theta/xsts/dsl/XstsVariableSymbol.java | 10 +-- .../bme/mit/theta/xsts/pnml/PnmlToXSTS.java | 6 +- .../mit/theta/xsts/type/XstsArrayType.java | 70 ------------------- .../mit/theta/xsts/type/XstsCustomType.java | 60 ---------------- .../theta/xsts/type/XstsPrimitiveType.java | 54 -------------- .../hu/bme/mit/theta/xsts/type/XstsType.java | 32 --------- .../mit/theta/xsts/utils/XSTSVarChanger.kt | 4 +- 15 files changed, 40 insertions(+), 330 deletions(-) delete mode 100644 subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsArrayType.java delete mode 100644 subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsCustomType.java delete mode 100644 subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsPrimitiveType.java delete mode 100644 subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsType.java diff --git a/subprojects/xsts/xsts-analysis/src/main/java/hu/bme/mit/theta/xsts/analysis/concretizer/XstsStateSequence.java b/subprojects/xsts/xsts-analysis/src/main/java/hu/bme/mit/theta/xsts/analysis/concretizer/XstsStateSequence.java index 24d2c1782b..a0923508d7 100644 --- a/subprojects/xsts/xsts-analysis/src/main/java/hu/bme/mit/theta/xsts/analysis/concretizer/XstsStateSequence.java +++ b/subprojects/xsts/xsts-analysis/src/main/java/hu/bme/mit/theta/xsts/analysis/concretizer/XstsStateSequence.java @@ -19,13 +19,10 @@ import hu.bme.mit.theta.analysis.expl.ExplState; import hu.bme.mit.theta.common.LispStringBuilder; import hu.bme.mit.theta.common.Utils; -import hu.bme.mit.theta.core.decl.VarDecl; -import hu.bme.mit.theta.core.type.LitExpr; import hu.bme.mit.theta.xsts.XSTS; import hu.bme.mit.theta.xsts.analysis.XstsState; import java.util.List; -import java.util.Optional; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkElementIndex; @@ -86,21 +83,9 @@ public String toString() { sb.add(Utils.lispStringBuilder(XstsState.class.getSimpleName()) .add(state.isInitialized() ? "post_init" : "pre_init") .add(state.lastActionWasEnv() ? "last_env" : "last_internal").body() - .add(stateToString(state.getState())).toString()); + .add(state.getState().toString())); } return sb.toString(); } - public String stateToString(ExplState state) { - final LispStringBuilder sb = Utils.lispStringBuilder(ExplState.class.getSimpleName()) - .body(); - for (VarDecl decl : xsts.getVars()) { - Optional val = state.eval(decl); - if (val.isPresent() && xsts.getVarToType().containsKey(decl)) { - sb.add(String.format("(%s %s)", decl.getName(), - xsts.getVarToType().get(decl).serializeLiteral(val.get()))); - } - } - return sb.toString(); - } } diff --git a/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsEnumSemanticsTest.java b/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsEnumSemanticsTest.java index 7a24971164..bccabf00bf 100644 --- a/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsEnumSemanticsTest.java +++ b/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsEnumSemanticsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Budapest University of Technology and Economics + * 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. diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/XSTS.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/XSTS.java index 4eded64ac7..97d6bad079 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/XSTS.java +++ b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/XSTS.java @@ -22,16 +22,16 @@ import hu.bme.mit.theta.core.type.booltype.BoolType; import hu.bme.mit.theta.core.utils.ExprUtils; import hu.bme.mit.theta.core.utils.StmtUtils; -import hu.bme.mit.theta.xsts.type.XstsType; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; import static com.google.common.base.Preconditions.checkNotNull; public final class XSTS { private final Collection> vars; - private final Map, XstsType> varToType; private final Set> ctrlVars; private final NonDetStmt tran; @@ -49,10 +49,6 @@ public Collection> getVars() { return vars; } - public Map, XstsType> getVarToType() { - return varToType; - } - public Expr getProp() { return prop; } @@ -73,7 +69,7 @@ public Set> getCtrlVars() { return ctrlVars; } - public XSTS(final Map, XstsType> varToType, final Set> ctrlVars, + public XSTS(final Set> ctrlVars, final NonDetStmt init, final NonDetStmt tran, final NonDetStmt env, final Expr initFormula, final Expr prop) { this.tran = checkNotNull(tran); @@ -81,11 +77,9 @@ public XSTS(final Map, XstsType> varToType, final Set> this.env = checkNotNull(env); this.initFormula = checkNotNull(initFormula); this.prop = checkNotNull(prop); - this.varToType = varToType; this.ctrlVars = ctrlVars; final Set> tmpVars = Containers.createSet(); - tmpVars.addAll(varToType.keySet()); tmpVars.addAll(StmtUtils.getVars(tran)); tmpVars.addAll(StmtUtils.getVars(env)); tmpVars.addAll(StmtUtils.getVars(init)); diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsExpression.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsExpression.java index 7b8ed8b139..a0fd5b35ff 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsExpression.java +++ b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsExpression.java @@ -478,7 +478,7 @@ private Expr createArrayLitExpr( final T2 valueType; if (ctx.indexType != null) { - indexType = (T1) new XstsType(typeTable, ctx.indexType).instantiate(env).getType(); + indexType = (T1) new XstsType(typeTable, ctx.indexType).instantiate(env); } else { indexType = (T1) ctx.indexExpr.get(0).accept(this).getType(); } diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsSpecification.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsSpecification.java index 6f754c056e..fc3c91d6c8 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsSpecification.java +++ b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsSpecification.java @@ -26,8 +26,6 @@ import hu.bme.mit.theta.core.utils.ExprUtils; import hu.bme.mit.theta.xsts.XSTS; import hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.XstsContext; -import hu.bme.mit.theta.xsts.type.XstsCustomType; -import hu.bme.mit.theta.xsts.type.XstsType; import java.util.*; import java.util.regex.Pattern; @@ -67,7 +65,6 @@ public Optional resolve(String name) { public XSTS instantiate() { final Env env = new Env(); - final Map, XstsType> varToType = Containers.createMap(); final Set> ctrlVars = Containers.createSet(); final List> initExprs = new ArrayList<>(); @@ -88,7 +85,7 @@ public XSTS instantiate() { final XstsCustomTypeSymbol typeDeclSymbol = XstsCustomTypeSymbol.of(enumType); typeTable.add(typeDeclSymbol); - env.define(typeDeclSymbol, XstsCustomType.of(enumType)); + env.define(typeDeclSymbol, enumType); } for (var varDeclContext : context.variableDeclarations) { @@ -101,8 +98,7 @@ public XSTS instantiate() { throw new ParseException(varDeclContext, String.format("Variable name '%s' matches at least one declared enum literal", varName)); - final XstsVariableSymbol symbol = new XstsVariableSymbol(typeTable, varToType, - varDeclContext); + final XstsVariableSymbol symbol = new XstsVariableSymbol(typeTable, varDeclContext); declare(symbol); final VarDecl var = symbol.instantiate(env); @@ -114,7 +110,7 @@ public XSTS instantiate() { if (var.getType() instanceof EnumType enumType) { env.push(); enumType.getValues().forEach(literal -> { - Symbol fullNameSymbol = resolve(String.format("%s%s%s", enumType.getName(), EnumType.FULLY_QUALIFIED_NAME_SEPARATOR, literal)).orElseThrow(); + Symbol fullNameSymbol = resolve(EnumType.makeLongName(enumType, literal)).orElseThrow(); if (fullNameSymbol instanceof XstsCustomLiteralSymbol fNameCustLitSymbol) { var customSymbol = XstsCustomLiteralSymbol.copyWithName(fNameCustLitSymbol, literal); scope.declare(customSymbol); @@ -134,21 +130,18 @@ public XSTS instantiate() { } final NonDetStmt tranSet = new XstsTransitionSet(this, typeTable, - context.tran.transitionSet(), varToType).instantiate(env); + context.tran.transitionSet()).instantiate(env); final NonDetStmt initSet = new XstsTransitionSet(this, typeTable, - context.init.transitionSet(), varToType).instantiate(env); + context.init.transitionSet()).instantiate(env); final NonDetStmt envSet = new XstsTransitionSet(this, typeTable, - context.env.transitionSet(), varToType).instantiate(env); + context.env.transitionSet()).instantiate(env); - for (VarDecl varDecl : varToType.keySet()) { - initExprs.add(varToType.get(varDecl).createBoundExpr(varDecl)); - } final Expr initFormula = ExprUtils.simplify(And(initExprs)); final Expr prop = cast( new XstsExpression(this, typeTable, context.prop).instantiate(env), Bool()); - return new XSTS(varToType, ctrlVars, initSet, tranSet, envSet, initFormula, prop); + return new XSTS(ctrlVars, initSet, tranSet, envSet, initFormula, prop); } @Override diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsStatement.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsStatement.java index c6d50e75f3..ef74b56a46 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsStatement.java +++ b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsStatement.java @@ -31,11 +31,9 @@ import hu.bme.mit.theta.core.type.inttype.IntType; import hu.bme.mit.theta.xsts.dsl.gen.XstsDslBaseVisitor; import hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.*; -import hu.bme.mit.theta.xsts.type.XstsCustomType; import java.util.ArrayList; import java.util.List; -import java.util.Map; import static com.google.common.base.Preconditions.*; import static hu.bme.mit.theta.core.stmt.Stmts.*; @@ -49,19 +47,16 @@ public class XstsStatement { private final DynamicScope scope; private final SymbolTable typeTable; private final StmtContext context; - private final Map, hu.bme.mit.theta.xsts.type.XstsType> varToType; public XstsStatement(final DynamicScope scope, final SymbolTable typeTable, - final StmtContext context, - final Map, hu.bme.mit.theta.xsts.type.XstsType> varToType) { + final StmtContext context) { this.scope = checkNotNull(scope); this.typeTable = checkNotNull(typeTable); this.context = checkNotNull(context); - this.varToType = checkNotNull(varToType); } public Stmt instantiate(final Env env) { - final StmtCreatorVisitor visitor = new StmtCreatorVisitor(scope, typeTable, env, varToType); + final StmtCreatorVisitor visitor = new StmtCreatorVisitor(scope, typeTable, env); final Stmt stmt = context.accept(visitor); if (stmt == null) { throw new AssertionError(); @@ -74,16 +69,13 @@ private static final class StmtCreatorVisitor extends XstsDslBaseVisitor { private DynamicScope currentScope; private final SymbolTable typeTable; - final Map, hu.bme.mit.theta.xsts.type.XstsType> varToType; private final Env env; public StmtCreatorVisitor(final DynamicScope scope, final SymbolTable typeTable, - final Env env, - final Map, hu.bme.mit.theta.xsts.type.XstsType> varToType) { + final Env env) { this.currentScope = checkNotNull(scope); this.typeTable = checkNotNull(typeTable); this.env = checkNotNull(env); - this.varToType = checkNotNull(varToType); } private void push() { @@ -105,13 +97,6 @@ public Stmt visitHavocStmt(final HavocStmtContext ctx) { final Symbol lhsSymbol = currentScope.resolve(lhsId).get(); final VarDecl var = (VarDecl) env.eval(lhsSymbol); - final hu.bme.mit.theta.xsts.type.XstsType type = varToType.get(var); - if (type instanceof XstsCustomType) { - final Expr expr = type.createBoundExpr(var); - final AssumeStmt assume = Assume(expr); - return SequenceStmt.of(List.of(Havoc(var), assume)); - } - return Havoc(var); } @@ -228,21 +213,14 @@ public Stmt visitLoopStmt(LoopStmtContext ctx) { @SuppressWarnings("unchecked") public Stmt visitLocalVarDeclStmt(LocalVarDeclStmtContext ctx) { final String name = ctx.name.getText(); - final hu.bme.mit.theta.xsts.type.XstsType xstsType = new XstsType(typeTable, + final Type type = new XstsType(typeTable, ctx.ttype).instantiate(env); - final Type type = xstsType.getType(); final var decl = Decls.Var(name, type); final Symbol symbol = DeclSymbol.of(decl); final Stmt result; if (ctx.initValue == null) { - if (xstsType instanceof XstsCustomType) { - final Expr expr = xstsType.createBoundExpr(decl); - final AssumeStmt assume = Assume(expr); - result = assume; - } else { - result = SkipStmt.getInstance(); - } + result = SkipStmt.getInstance(); } else { var expr = new XstsExpression(currentScope, typeTable, ctx.initValue).instantiate( env); @@ -258,7 +236,6 @@ public Stmt visitLocalVarDeclStmt(LocalVarDeclStmtContext ctx) { currentScope.declare(symbol); env.define(symbol, decl); - varToType.put(decl, xstsType); return result; } diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsTransitionSet.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsTransitionSet.java index f85b429c43..0347f5c9a7 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsTransitionSet.java +++ b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsTransitionSet.java @@ -17,18 +17,13 @@ import hu.bme.mit.theta.common.dsl.DynamicScope; import hu.bme.mit.theta.common.dsl.Env; -import hu.bme.mit.theta.common.dsl.Scope; import hu.bme.mit.theta.common.dsl.SymbolTable; -import hu.bme.mit.theta.core.decl.VarDecl; import hu.bme.mit.theta.core.stmt.NonDetStmt; import hu.bme.mit.theta.core.stmt.Stmt; import hu.bme.mit.theta.xsts.dsl.gen.XstsDslBaseVisitor; import hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.TransitionSetContext; -import hu.bme.mit.theta.xsts.type.XstsType; import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; @@ -37,14 +32,12 @@ public class XstsTransitionSet { private final DynamicScope scope; private final SymbolTable typeTable; private final TransitionSetContext context; - private final Map, XstsType> varToType; public XstsTransitionSet(final DynamicScope scope, final SymbolTable typeTable, - final TransitionSetContext context, final Map, XstsType> varToType) { + final TransitionSetContext context) { this.scope = checkNotNull(scope); this.typeTable = checkNotNull(typeTable); this.context = checkNotNull(context); - this.varToType = checkNotNull(varToType); } public NonDetStmt instantiate(final Env env) { @@ -68,8 +61,9 @@ public TransitionSetCreatorVisitor(final Env env) { @Override public NonDetStmt visitTransitionSet(TransitionSetContext ctx) { final List stmts = ctx.stmts.stream() - .map((stmtContext -> new XstsStatement(scope, typeTable, stmtContext, - varToType).instantiate(env))).collect(Collectors.toList()); + .map((stmtContext -> + new XstsStatement(scope, typeTable, stmtContext) + .instantiate(env))).toList(); return NonDetStmt.of(stmts); } } diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsType.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsType.java index 39daae2570..1914625170 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsType.java +++ b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsType.java @@ -19,10 +19,9 @@ import hu.bme.mit.theta.common.dsl.Symbol; import hu.bme.mit.theta.common.dsl.SymbolTable; import hu.bme.mit.theta.core.dsl.ParseException; +import hu.bme.mit.theta.core.type.Type; import hu.bme.mit.theta.xsts.dsl.gen.XstsDslBaseVisitor; import hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.*; -import hu.bme.mit.theta.xsts.type.XstsArrayType; -import hu.bme.mit.theta.xsts.type.XstsPrimitiveType; import java.util.Optional; @@ -41,9 +40,9 @@ public XstsType(final SymbolTable typeTable, final TypeContext context) { this.context = checkNotNull(context); } - public hu.bme.mit.theta.xsts.type.XstsType instantiate(final Env env) { + public Type instantiate(final Env env) { final TypeCreatorVisitor typeCreatorVisitor = new TypeCreatorVisitor(typeTable, env); - final hu.bme.mit.theta.xsts.type.XstsType result = context.accept(typeCreatorVisitor); + final Type result = context.accept(typeCreatorVisitor); if (result == null) { throw new AssertionError(); } else { @@ -52,7 +51,7 @@ public hu.bme.mit.theta.xsts.type.XstsType instantiate(final Env env) { } private static class TypeCreatorVisitor extends - XstsDslBaseVisitor { + XstsDslBaseVisitor { private final SymbolTable typeTable; private final Env env; @@ -63,33 +62,31 @@ public TypeCreatorVisitor(final SymbolTable typeTable, final Env env) { } @Override - public hu.bme.mit.theta.xsts.type.XstsType visitCustomType(final CustomTypeContext ctx) { + public Type visitCustomType(final CustomTypeContext ctx) { Optional optSymbol = typeTable.get(ctx.name.getText()); if (optSymbol.isEmpty()) { throw new ParseException(ctx, "Type '" + ctx.name.getText() + "' cannot be resolved"); } final Symbol symbol = optSymbol.get(); - final hu.bme.mit.theta.xsts.type.XstsType xstsType = (hu.bme.mit.theta.xsts.type.XstsType) env.eval( - symbol); - return xstsType; + return (Type) env.eval(symbol); } @Override - public hu.bme.mit.theta.xsts.type.XstsType visitBoolType(final BoolTypeContext ctx) { - return XstsPrimitiveType.of(Bool()); + public Type visitBoolType(final BoolTypeContext ctx) { + return Bool(); } @Override - public hu.bme.mit.theta.xsts.type.XstsType visitIntType(final IntTypeContext ctx) { - return XstsPrimitiveType.of(Int()); + public Type visitIntType(final IntTypeContext ctx) { + return Int(); } @Override - public hu.bme.mit.theta.xsts.type.XstsType visitArrayType(final ArrayTypeContext ctx) { - final hu.bme.mit.theta.xsts.type.XstsType indexType = ctx.indexType.accept(this); - final hu.bme.mit.theta.xsts.type.XstsType elemType = ctx.elemType.accept(this); - return XstsArrayType.of(indexType, elemType); + public Type visitArrayType(final ArrayTypeContext ctx) { + final Type indexType = ctx.indexType.accept(this); + final Type elemType = ctx.elemType.accept(this); + return Array(indexType, elemType); } } diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsVariableSymbol.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsVariableSymbol.java index 002fa60e4c..a1c97f9fbc 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsVariableSymbol.java +++ b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/dsl/XstsVariableSymbol.java @@ -21,8 +21,6 @@ import hu.bme.mit.theta.core.decl.VarDecl; import hu.bme.mit.theta.xsts.dsl.gen.XstsDslParser.VariableDeclarationContext; -import java.util.Map; - import static com.google.common.base.Preconditions.checkNotNull; import static hu.bme.mit.theta.core.decl.Decls.Var; @@ -30,14 +28,11 @@ public class XstsVariableSymbol implements Symbol { private final String name; private final XstsType type; - final Map, hu.bme.mit.theta.xsts.type.XstsType> varToType; public XstsVariableSymbol(final SymbolTable typeTable, - final Map, hu.bme.mit.theta.xsts.type.XstsType> varToType, final VariableDeclarationContext context) { checkNotNull(context); name = context.name.getText(); - this.varToType = varToType; type = new XstsType(typeTable, context.ttype); } @@ -47,9 +42,6 @@ public String getName() { } public VarDecl instantiate(Env env) { - final hu.bme.mit.theta.xsts.type.XstsType xstsType = type.instantiate(env); - final VarDecl var = Var(name, xstsType.getType()); - varToType.put(var, xstsType); - return var; + return Var(name, type.instantiate(env)); } } diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/PnmlToXSTS.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/PnmlToXSTS.java index e4db4cc760..51a343ad5c 100644 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/PnmlToXSTS.java +++ b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/pnml/PnmlToXSTS.java @@ -16,7 +16,6 @@ package hu.bme.mit.theta.xsts.pnml; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import hu.bme.mit.theta.common.container.Containers; import hu.bme.mit.theta.core.decl.Decls; @@ -29,7 +28,6 @@ import hu.bme.mit.theta.core.type.inttype.IntType; import hu.bme.mit.theta.xsts.XSTS; import hu.bme.mit.theta.xsts.pnml.elements.*; -import hu.bme.mit.theta.xsts.type.XstsType; import java.io.InputStream; import java.util.*; @@ -104,8 +102,6 @@ public static XSTS createXSTS(final PnmlNet net, final InputStream propStream) { final NonDetStmt tran = NonDetStmt.of(tranStmts); final NonDetStmt init = NonDetStmt.of(ImmutableList.of()); final NonDetStmt env = NonDetStmt.of(ImmutableList.of()); - - final Map, XstsType> varToType = ImmutableMap.of(); final Set> ctrlVars = ImmutableSet.of(); final Scanner propScanner = new Scanner(propStream).useDelimiter("\\A"); @@ -136,7 +132,7 @@ public static XSTS createXSTS(final PnmlNet net, final InputStream propStream) { propExpr = cast(dslManager.parseExpr(property), Bool()); } - return new XSTS(varToType, ctrlVars, init, tran, env, initExpr, propExpr); + return new XSTS(ctrlVars, init, tran, env, initExpr, propExpr); } private static String stripPropFromPropFile(final String propertyFile) { diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsArrayType.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsArrayType.java deleted file mode 100644 index 0c8d7a80e4..0000000000 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsArrayType.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.xsts.type; - -import com.google.common.base.Preconditions; -import hu.bme.mit.theta.common.Utils; -import hu.bme.mit.theta.core.decl.VarDecl; -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.ArrayLitExpr; -import hu.bme.mit.theta.core.type.arraytype.ArrayType; -import hu.bme.mit.theta.core.type.booltype.BoolType; - -import static hu.bme.mit.theta.core.type.arraytype.ArrayExprs.Array; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.True; - -public final class XstsArrayType implements - XstsType> { - - private final XstsType indexType; - private final XstsType elemType; - private ArrayType type; - - private XstsArrayType(XstsType indexType, XstsType elemType) { - this.indexType = indexType; - this.elemType = elemType; - this.type = Array(indexType.getType(), elemType.getType()); - } - - public static XstsArrayType of( - XstsType indexType, XstsType elemType) { - return new XstsArrayType<>(indexType, elemType); - } - - public ArrayType getType() { - return type; - } - - @Override - public Expr createBoundExpr(VarDecl> decl) { - return True(); - } - - @Override - public String serializeLiteral(LitExpr> literal) { - Preconditions.checkArgument(literal.getType().equals(type)); - final ArrayLitExpr arrayLitExpr = (ArrayLitExpr) literal; - return Utils.lispStringBuilder("array") - .addAll(arrayLitExpr.getElements().stream().map( - elem -> String.format("(%s %s)", indexType.serializeLiteral(elem.get1()), - elemType.serializeLiteral(elem.get2())))) - .add((String.format("(default %s)", - elemType.serializeLiteral(arrayLitExpr.getElseElem())))) - .toString(); - } -} diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsCustomType.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsCustomType.java deleted file mode 100644 index 8945780e54..0000000000 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsCustomType.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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.xsts.type; - -import hu.bme.mit.theta.core.decl.VarDecl; -import hu.bme.mit.theta.core.type.Expr; -import hu.bme.mit.theta.core.type.LitExpr; -import hu.bme.mit.theta.core.type.booltype.BoolType; -import hu.bme.mit.theta.core.type.enumtype.EnumLitExpr; -import hu.bme.mit.theta.core.type.enumtype.EnumType; - -import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Eq; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Or; - -public final class XstsCustomType implements XstsType { - - private final EnumType type; - - private XstsCustomType(EnumType type) { - this.type = type; - } - - public static XstsCustomType of(EnumType type) { - return new XstsCustomType(type); - } - - public String getName() { - return type.getName(); - } - - @Override - public EnumType getType() { - return type; - } - - @Override - public Expr createBoundExpr(VarDecl decl) { - return Or(type.getValues().stream() - .map(lit -> Eq(decl.getRef(), EnumLitExpr.of(type, lit))) - .toList()); - } - - @Override - public String serializeLiteral(LitExpr literal) { - return literal.toString(); - } -} diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsPrimitiveType.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsPrimitiveType.java deleted file mode 100644 index 00768085ca..0000000000 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsPrimitiveType.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.xsts.type; - -import com.google.common.base.Preconditions; -import hu.bme.mit.theta.core.decl.VarDecl; -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.booltype.BoolType; - -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.True; - -public final class XstsPrimitiveType implements XstsType { - - private final T type; - - private XstsPrimitiveType(T type) { - this.type = type; - } - - public static XstsPrimitiveType of(T type) { - return new XstsPrimitiveType<>(type); - } - - @Override - public T getType() { - return type; - } - - @Override - public Expr createBoundExpr(VarDecl decl) { - return True(); - } - - @Override - public String serializeLiteral(LitExpr literal) { - Preconditions.checkArgument(literal.getType().equals(type)); - return literal.toString(); - } -} diff --git a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsType.java b/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsType.java deleted file mode 100644 index 7eb8893870..0000000000 --- a/subprojects/xsts/xsts/src/main/java/hu/bme/mit/theta/xsts/type/XstsType.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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.xsts.type; - -import hu.bme.mit.theta.core.decl.VarDecl; -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.booltype.BoolType; - -public interface XstsType { - - T getType(); - - Expr createBoundExpr(final VarDecl decl); - - String serializeLiteral(final LitExpr literal); - -} diff --git a/subprojects/xsts/xsts/src/main/kotlin/hu/bme/mit/theta/xsts/utils/XSTSVarChanger.kt b/subprojects/xsts/xsts/src/main/kotlin/hu/bme/mit/theta/xsts/utils/XSTSVarChanger.kt index 6a80ea1d76..c38b044ec5 100644 --- a/subprojects/xsts/xsts/src/main/kotlin/hu/bme/mit/theta/xsts/utils/XSTSVarChanger.kt +++ b/subprojects/xsts/xsts/src/main/kotlin/hu/bme/mit/theta/xsts/utils/XSTSVarChanger.kt @@ -22,12 +22,10 @@ import hu.bme.mit.theta.core.utils.changeVars import hu.bme.mit.theta.xsts.XSTS fun XSTS.copyWithReplacingVars(variableMapping: Map>): XSTS { - val newVarToType = varToType.toMutableMap() - variableMapping.forEach { (name, varDecl) -> newVarToType[varDecl] = varToType[vars.find { it.name == name }] } val matchingCtrlVarNames = ctrlVars.filter { variableMapping.containsKey(it.name) }.map { it.name } val newCtrlVars = ctrlVars.filter { it.name !in variableMapping } .toSet() + variableMapping.filter { it.key in matchingCtrlVarNames }.values.toSet() - return XSTS(newVarToType, newCtrlVars, init.changeVars(variableMapping) as NonDetStmt, + return XSTS(newCtrlVars, init.changeVars(variableMapping) as NonDetStmt, tran.changeVars(variableMapping) as NonDetStmt, env.changeVars(variableMapping) as NonDetStmt, initFormula.changeVars(variableMapping), prop.changeVars(variableMapping)) } \ No newline at end of file From 86fb3845853f4477dcf53b59e8bf190d4f76a98a Mon Sep 17 00:00:00 2001 From: RipplB Date: Tue, 18 Jun 2024 10:28:08 +0200 Subject: [PATCH 4/8] XstsTest: Improve test experience Now the test uses solvermanagers and a constant string can be set to easily define which solver to run the tests with. If it is set to an SMTLib solver, a helper BeforeClass method checks if specified version is installed, and if not, installs it. --- .../xsts/xsts-analysis/build.gradle.kts | 2 + .../bme/mit/theta/xsts/analysis/XstsTest.java | 68 +++++++++++++++---- 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/subprojects/xsts/xsts-analysis/build.gradle.kts b/subprojects/xsts/xsts-analysis/build.gradle.kts index 05081d8c86..4b2513efbf 100644 --- a/subprojects/xsts/xsts-analysis/build.gradle.kts +++ b/subprojects/xsts/xsts-analysis/build.gradle.kts @@ -24,5 +24,7 @@ dependencies { implementation(project(":theta-core")) implementation(project(":theta-solver")) implementation(project(":theta-xsts")) + testImplementation(project(":theta-solver-z3")) testImplementation(project(":theta-solver-z3-legacy")) + testImplementation(project(":theta-solver-smtlib")) } diff --git a/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsTest.java b/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsTest.java index 049fb17dc3..b527738861 100644 --- a/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsTest.java +++ b/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsTest.java @@ -19,19 +19,23 @@ import hu.bme.mit.theta.common.logging.ConsoleLogger; import hu.bme.mit.theta.common.logging.Logger; import hu.bme.mit.theta.common.logging.Logger.Level; -import hu.bme.mit.theta.solver.z3legacy.Z3LegacySolverFactory; +import hu.bme.mit.theta.solver.SolverFactory; +import hu.bme.mit.theta.solver.SolverManager; +import hu.bme.mit.theta.solver.smtlib.SmtLibSolverManager; import hu.bme.mit.theta.xsts.XSTS; import hu.bme.mit.theta.xsts.analysis.config.XstsConfig; import hu.bme.mit.theta.xsts.analysis.config.XstsConfigBuilder; import hu.bme.mit.theta.xsts.dsl.XstsDslManager; +import org.junit.Assume; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.io.FileInputStream; -import java.io.IOException; import java.io.InputStream; import java.io.SequenceInputStream; +import java.nio.file.Path; import java.util.Arrays; import java.util.Collection; @@ -40,6 +44,9 @@ @RunWith(value = Parameterized.class) public class XstsTest { + private static final String SOLVER_STRING = "Z3"; + private static final Path SMTLIB_HOME = SmtLibSolverManager.HOME; + @Parameterized.Parameter(value = 0) public String filePath; @@ -344,10 +351,36 @@ public static Collection data() { }); } - @Test - public void test() throws IOException { + @BeforeClass + public static void installSolver() { + if (SOLVER_STRING.contains("Z3")) { + return; + } + try (final var solverManager = SmtLibSolverManager.create(SMTLIB_HOME, new ConsoleLogger(Level.DETAIL))) { + String solverVersion = SmtLibSolverManager.getSolverVersion(SOLVER_STRING); + String solverName = SmtLibSolverManager.getSolverName(SOLVER_STRING); + if (solverManager.managesSolver(SOLVER_STRING) && !solverManager.getInstalledVersions(solverName).contains(solverManager.getVersionString(solverName, solverVersion, false))) { + solverManager.install(solverName, solverVersion, solverVersion, null, false); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @Test + public void test() throws Exception { final Logger logger = new ConsoleLogger(Level.SUBSTEP); + SolverManager.registerSolverManager(hu.bme.mit.theta.solver.z3legacy.Z3SolverManager.create()); + SolverManager.registerSolverManager(hu.bme.mit.theta.solver.z3.Z3SolverManager.create()); + SolverManager.registerSolverManager(SmtLibSolverManager.create(SMTLIB_HOME, logger)); + + final SolverFactory solverFactory; + try { + solverFactory = SolverManager.resolveSolverFactory(SOLVER_STRING); + } catch (Exception e) { + Assume.assumeNoException(e); + return; + } XSTS xsts; try (InputStream inputStream = new SequenceInputStream(new FileInputStream(filePath), @@ -355,17 +388,22 @@ public void test() throws IOException { xsts = XstsDslManager.createXsts(inputStream); } - final XstsConfig configuration = new XstsConfigBuilder(domain, - XstsConfigBuilder.Refinement.SEQ_ITP, Z3LegacySolverFactory.getInstance(), - Z3LegacySolverFactory.getInstance()).initPrec(XstsConfigBuilder.InitPrec.CTRL) - .optimizeStmts(XstsConfigBuilder.OptimizeStmts.ON) - .predSplit(XstsConfigBuilder.PredSplit.CONJUNCTS).maxEnum(250) - .autoExpl(XstsConfigBuilder.AutoExpl.NEWOPERANDS).logger(logger).build(xsts); - final SafetyResult status = configuration.check(); - if (safe) { - assertTrue(status.isSafe()); - } else { - assertTrue(status.isUnsafe()); + try { + final XstsConfig configuration = new XstsConfigBuilder(domain, + XstsConfigBuilder.Refinement.SEQ_ITP, solverFactory, + solverFactory).initPrec(XstsConfigBuilder.InitPrec.CTRL) + .optimizeStmts(XstsConfigBuilder.OptimizeStmts.ON) + .predSplit(XstsConfigBuilder.PredSplit.CONJUNCTS).maxEnum(250) + .autoExpl(XstsConfigBuilder.AutoExpl.NEWOPERANDS).logger(logger).build(xsts); + final SafetyResult status = configuration.check(); + + if (safe) { + assertTrue(status.isSafe()); + } else { + assertTrue(status.isUnsafe()); + } + } finally { + SolverManager.closeAll(); } } From ddcb486ecdc118f651fa3648c4f73b7c8ca82d9e Mon Sep 17 00:00:00 2001 From: RipplB Date: Wed, 12 Jun 2024 11:45:58 +0200 Subject: [PATCH 5/8] SmtLib binary: timeout before status check The generic smtlib solver binary checks process health after starting it. If the process didn't fail fast enough, this check reported a running status, but later calls failed. Now introduced a 50ms thread sleep after starting the process, to make sure it catches all startup fails. --- .../smtlib/impl/generic/GenericSmtLibSolverBinary.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibSolverBinary.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibSolverBinary.java index 3dc4801096..f9c36afa9a 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibSolverBinary.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibSolverBinary.java @@ -51,6 +51,11 @@ public GenericSmtLibSolverBinary(final Path solverPath, final String[] args, solverProcessBuilder.setProcessListener(processHandler); solverProcess = solverProcessBuilder.start(); + try { + Thread.sleep(50); + } catch (InterruptedException ignored) { + + } checkState(solverProcess.isRunning()); } From 44dbed2c5c5009df1c49005f9635e9c5ace50508 Mon Sep 17 00:00:00 2001 From: RipplB Date: Tue, 18 Jun 2024 10:28:19 +0200 Subject: [PATCH 6/8] Introduce datatypes for smtlib --- .../solver/smtlib/SmtLibSolverManager.java | 104 +++++++------- .../smtlib/impl/cvc5/CVC5SmtLibItpSolver.java | 11 +- .../impl/cvc5/CVC5SmtLibSolverFactory.java | 14 +- .../impl/cvc5/CVC5SmtLibSolverInstaller.java | 6 +- .../generic/GenericSmtLibExprTransformer.java | 36 ++++- .../generic/GenericSmtLibSolverBinary.java | 2 + .../generic/GenericSmtLibSolverFactory.java | 25 +++- .../generic/GenericSmtLibSymbolTable.java | 23 ++++ .../generic/GenericSmtLibTermTransformer.java | 130 +++++------------- .../GenericSmtLibTransformationManager.java | 7 +- .../generic/GenericSmtLibTypeTransformer.java | 6 + .../mathsat/MathSATSmtLibExprTransformer.java | 5 +- .../mathsat/MathSATSmtLibSolverFactory.java | 6 +- .../MathSATSmtLibTransformationManager.java | 5 +- .../princess/PrincessSmtLibItpSolver.java | 16 +-- .../princess/PrincessSmtLibSolverFactory.java | 21 ++- .../PrincessSmtLibSolverInstaller.java | 5 +- .../SMTInterpolSmtLibItpSolver.java | 27 ++-- .../SMTInterpolSmtLibSolverFactory.java | 26 ++-- .../SMTInterpolSmtLibSolverInstaller.java | 48 ++++--- .../smtlib/impl/z3/Z3SmtLibSolverFactory.java | 2 +- .../smtlib/solver/SmtLibEnumStrategy.java | 125 +++++++++++++++++ .../solver/smtlib/solver/SmtLibItpSolver.java | 42 +++--- .../solver/smtlib/solver/SmtLibSolver.java | 91 ++++++------ .../smtlib/solver/model/SmtLibValuation.java | 6 +- .../solver/transformer/SmtLibSymbolTable.java | 7 + 26 files changed, 473 insertions(+), 323 deletions(-) create mode 100644 subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/SmtLibEnumStrategy.java diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/SmtLibSolverManager.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/SmtLibSolverManager.java index 8e8c89de2c..2c3dd8f167 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/SmtLibSolverManager.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/SmtLibSolverManager.java @@ -48,17 +48,6 @@ public final class SmtLibSolverManager extends SolverManager { private static final Map> installerDeclarations = new HashMap<>(); private static Tuple2> genericInstallerDeclaration; - public static void registerInstaller(final String name, - final Class decl) { - installerDeclarations.put(name, decl); - } - - public static void registerGenericInstaller( - final String name, final Class decl) { - checkState(genericInstallerDeclaration == null); - genericInstallerDeclaration = Tuple2.of(name, decl); - } - static { registerInstaller("z3", Z3SmtLibSolverInstaller.class); registerInstaller("cvc4", CVC4SmtLibSolverInstaller.class); @@ -71,42 +60,12 @@ public static void registerGenericInsta registerGenericInstaller("generic", GenericSmtLibSolverInstaller.class); } - public static String getSolverName(final String name) { - final var solverName = decodeSolverName(name, 0); - if (solverName != null) { - return solverName; - } else { - throw new IllegalArgumentException("Invalid version string: " + name); - } - } - - public static String getSolverVersion(final String name) { - final var solverVersion = decodeSolverName(name, 1); - if (solverVersion != null) { - return solverVersion; - } else { - throw new IllegalArgumentException("Invalid version string: " + name); - } - } - - private static String decodeSolverName(final String name, final int part) { - final var versionArr = name.split(":"); - - if (versionArr.length != 2) { - return null; - } - - return versionArr[part]; - } - private final Path home; private final Logger logger; - private final Map installers; private final Tuple2 genericInstaller; - - private boolean closed = false; private final Set instantiatedSolvers; + private boolean closed = false; private SmtLibSolverManager(final Path home, final Logger logger) { this.logger = logger; @@ -144,12 +103,58 @@ private SmtLibSolverManager(final Path home, final Logger logger) { this.instantiatedSolvers = new HashSet<>(); } + public static void registerInstaller(final String name, + final Class decl) { + installerDeclarations.put(name, decl); + } + + public static void registerGenericInstaller( + final String name, final Class decl) { + checkState(genericInstallerDeclaration == null); + genericInstallerDeclaration = Tuple2.of(name, decl); + } + + public static String getSolverName(final String name) { + final var solverName = decodeSolverName(name, 0); + if (solverName != null) { + return solverName; + } else { + throw new IllegalArgumentException("Invalid version string: " + name); + } + } + + public static String getSolverVersion(final String name) { + final var solverVersion = decodeSolverName(name, 1); + if (solverVersion != null) { + return solverVersion; + } else { + throw new IllegalArgumentException("Invalid version string: " + name); + } + } + + private static String decodeSolverName(final String name, final int part) { + final var versionArr = name.split(":"); + + if (versionArr.length != 2) { + return null; + } + + return versionArr[part]; + } + public static SmtLibSolverManager create(final Path home, final Logger logger) throws IOException { createIfNotExists(home); return new SmtLibSolverManager(home, logger); } + private static Path createIfNotExists(final Path path) throws IOException { + if (!Files.exists(path)) { + Files.createDirectory(path); + } + return path; + } + public String getGenericInstallerName() { return genericInstaller.get1(); } @@ -304,16 +309,16 @@ public List getInstalledVersions(final String solver) return installers.get(solver).getInstalledVersions(home.resolve(solver)); } - private String getVersionString(final String solver, final String version, - final boolean installed) throws SmtLibSolverInstallerException { + public String getVersionString(final String solver, final String version, + final boolean installed) throws SmtLibSolverInstallerException { if (!version.equals("latest")) { return version; } else { final var supportedVersions = getSupportedVersions(solver); final var versions = installed ? getInstalledVersions(solver).stream() - .filter(supportedVersions::contains).collect(Collectors.toList()) + .filter(supportedVersions::contains).toList() : supportedVersions; - if (versions.size() > 0) { + if (!versions.isEmpty()) { return versions.get(0); } else { throw new SmtLibSolverInstallerException( @@ -323,13 +328,6 @@ private String getVersionString(final String solver, final String version, } } - private static Path createIfNotExists(final Path path) throws IOException { - if (!Files.exists(path)) { - Files.createDirectory(path); - } - return path; - } - @Override public void close() throws Exception { for (final var solver : instantiatedSolvers) { diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/cvc5/CVC5SmtLibItpSolver.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/cvc5/CVC5SmtLibItpSolver.java index 707a80735c..039ba105c4 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/cvc5/CVC5SmtLibItpSolver.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/cvc5/CVC5SmtLibItpSolver.java @@ -21,8 +21,10 @@ import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.booltype.BoolType; import hu.bme.mit.theta.solver.*; +import hu.bme.mit.theta.solver.impl.StackImpl; import hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Lexer; import hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser; +import hu.bme.mit.theta.solver.smtlib.solver.SmtLibEnumStrategy; import hu.bme.mit.theta.solver.smtlib.solver.SmtLibItpSolver; import hu.bme.mit.theta.solver.smtlib.solver.SmtLibSolverException; import hu.bme.mit.theta.solver.smtlib.solver.binary.SmtLibSolverBinary; @@ -54,8 +56,9 @@ public class CVC5SmtLibItpSolver extends SmtLibItpSolver { public CVC5SmtLibItpSolver(final SmtLibSymbolTable symbolTable, final SmtLibTransformationManager transformationManager, final SmtLibTermTransformer termTransformer, final SmtLibSolverBinary solverBinary, - final Supplier itpSolverBinaryFactory) { - super(symbolTable, transformationManager, termTransformer, solverBinary); + final Supplier itpSolverBinaryFactory, + final SmtLibEnumStrategy enumStrategy) { + super(symbolTable, transformationManager, termTransformer, solverBinary, enumStrategy); this.itpSolverBinaryFactory = itpSolverBinaryFactory; final var tmp = Decls.Const("shevgcrjhsdfzgrjbms2dhrbcshdmrgcsh", Int()); // symbolTable.put(tmp, "shevgcrjhsdfzgrjbms2dhrbcshdmrgcsh", "(declare-fun shevgcrjhsdfzgrjbms2dhrbcshdmrgcsh () Int)"); @@ -90,6 +93,7 @@ public Interpolant getInterpolant(ItpPattern pattern) { try (final var itpSolverBinary = itpSolverBinaryFactory.get()) { itpSolverBinary.issueCommand("(set-option :produce-interpolants true)"); itpSolverBinary.issueCommand("(set-logic ALL)"); + enumStrategy.declareDatatypes(typeStack.toCollection(), new StackImpl<>(), itpSolverBinary::issueCommand); declarationStack.forEach( constDecl -> itpSolverBinary.issueCommand(symbolTable.getDeclaration(constDecl))); @@ -120,8 +124,9 @@ public Interpolant getInterpolant(ItpPattern pattern) { interpolantCount++, bTerm.collect(Collectors.joining(" ")))); itpSolverBinary.issueCommand("(pop)"); + final String solverResponse = itpSolverBinary.readResponse(); itpMap.put(marker, - termTransformer.toExpr(parseItpResponse(itpSolverBinary.readResponse()), + termTransformer.toExpr(parseItpResponse(solverResponse), Bool(), new SmtLibModel(Collections.emptyMap()))); } else { itpMap.put(marker, False()); diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/cvc5/CVC5SmtLibSolverFactory.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/cvc5/CVC5SmtLibSolverFactory.java index 8e0c876ccd..2e6420481c 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/cvc5/CVC5SmtLibSolverFactory.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/cvc5/CVC5SmtLibSolverFactory.java @@ -18,33 +18,33 @@ import hu.bme.mit.theta.solver.ItpSolver; import hu.bme.mit.theta.solver.smtlib.impl.generic.*; -import hu.bme.mit.theta.solver.smtlib.solver.SmtLibSolver; +import hu.bme.mit.theta.solver.smtlib.solver.SmtLibEnumStrategy; import java.nio.file.Path; import java.util.EnumSet; public class CVC5SmtLibSolverFactory extends GenericSmtLibSolverFactory { - private CVC5SmtLibSolverFactory(Path solverPath, String[] args) { - super(solverPath, args); + private CVC5SmtLibSolverFactory(Path solverPath, String[] args, SmtLibEnumStrategy enumStrategy) { + super(solverPath, args, enumStrategy); } - public static CVC5SmtLibSolverFactory create(Path solverPath, String[] args) { - return new CVC5SmtLibSolverFactory(solverPath, args); + public static CVC5SmtLibSolverFactory create(Path solverPath, String[] args, SmtLibEnumStrategy enumStrategy) { + return new CVC5SmtLibSolverFactory(solverPath, args, enumStrategy); } @Override public ItpSolver createItpSolver() { final var symbolTable = new GenericSmtLibSymbolTable(); final var transformationManager = new GenericSmtLibTransformationManager(symbolTable); - final var termTransformer = new GenericSmtLibTermTransformer(symbolTable); + final var termTransformer = new GenericSmtLibTermTransformer(symbolTable, enumStrategy); final var solverBinary = new GenericSmtLibSolverBinary(solverPath, args, EnumSet.noneOf(GenericSmtLibSolverBinary.Solver.class)); return new CVC5SmtLibItpSolver( symbolTable, transformationManager, termTransformer, solverBinary, () -> new GenericSmtLibSolverBinary(solverPath, args, - EnumSet.noneOf(GenericSmtLibSolverBinary.Solver.class)) + EnumSet.noneOf(GenericSmtLibSolverBinary.Solver.class)), enumStrategy ); } } diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/cvc5/CVC5SmtLibSolverInstaller.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/cvc5/CVC5SmtLibSolverInstaller.java index a338f437cf..6d13d05cd7 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/cvc5/CVC5SmtLibSolverInstaller.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/cvc5/CVC5SmtLibSolverInstaller.java @@ -18,6 +18,7 @@ import hu.bme.mit.theta.common.OsHelper; import hu.bme.mit.theta.common.logging.Logger; import hu.bme.mit.theta.solver.SolverFactory; +import hu.bme.mit.theta.solver.smtlib.solver.SmtLibEnumStrategy; import hu.bme.mit.theta.solver.smtlib.solver.installer.SmtLibSolverInstaller; import hu.bme.mit.theta.solver.smtlib.solver.installer.SmtLibSolverInstallerException; import hu.bme.mit.theta.solver.smtlib.utils.Compress; @@ -40,6 +41,9 @@ import static hu.bme.mit.theta.common.OsHelper.OperatingSystem.WINDOWS; public class CVC5SmtLibSolverInstaller extends SmtLibSolverInstaller.Default { + + private static final SmtLibEnumStrategy ENUM_STRATEGY = SmtLibEnumStrategy.DATATYPES; + private final List versions; public CVC5SmtLibSolverInstaller(final Logger logger) { @@ -122,7 +126,7 @@ public SolverFactory getSolverFactory(final Path installDir, final String versio } else { solverFilePath = solverPath != null ? solverPath : installDir.resolve("bin").resolve(getSolverBinaryName(version)); } - return CVC5SmtLibSolverFactory.create(solverFilePath, solverArgs); + return CVC5SmtLibSolverFactory.create(solverFilePath, solverArgs, ENUM_STRATEGY); } @Override diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibExprTransformer.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibExprTransformer.java index 1233550ba0..bed493ea87 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibExprTransformer.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibExprTransformer.java @@ -82,6 +82,10 @@ 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; @@ -142,6 +146,7 @@ import hu.bme.mit.theta.core.type.rattype.RatToIntExpr; import hu.bme.mit.theta.core.utils.BvUtils; import hu.bme.mit.theta.solver.smtlib.solver.transformer.SmtLibExprTransformer; +import hu.bme.mit.theta.solver.smtlib.solver.transformer.SmtLibSymbolTable; import hu.bme.mit.theta.solver.smtlib.solver.transformer.SmtLibTransformationManager; import java.math.BigInteger; @@ -155,13 +160,15 @@ public class GenericSmtLibExprTransformer implements SmtLibExprTransformer { private static final int CACHE_SIZE = 1000; private final SmtLibTransformationManager transformer; + private final SmtLibSymbolTable symbolTable; private final Cache, String> exprToTerm; private final DispatchTable table; private final Env env; - public GenericSmtLibExprTransformer(final SmtLibTransformationManager transformer) { + public GenericSmtLibExprTransformer(final SmtLibTransformationManager transformer, final SmtLibSymbolTable symbolTable) { this.transformer = transformer; + this.symbolTable = symbolTable; this.env = new Env(); this.exprToTerm = CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).build(); @@ -262,6 +269,14 @@ protected DispatchTable.Builder buildDispatchTable(DispatchTable.Builder .addCase(IntToRatExpr.class, this::transformIntToRat) + // Enums + + .addCase(EnumLitExpr.class, this::transformEnumLit) + + .addCase(EnumNeqExpr.class, this::transformEnumNeq) + + .addCase(EnumEqExpr.class, this::transformEnumEq) + // Bitvectors .addCase(BvLitExpr.class, this::transformBvLit) @@ -722,6 +737,25 @@ protected String transformIntToRat(final IntToRatExpr expr) { return String.format("(to_real %s)", toTerm(expr.getOp())); } + /* + * Enums + */ + + protected String transformEnumEq(final EnumEqExpr expr) { + return String.format("(= %s %s)", toTerm(expr.getLeftOp()), toTerm(expr.getRightOp())); + } + + protected String transformEnumNeq(final EnumNeqExpr expr) { + return String.format("(not (= %s %s))", toTerm(expr.getLeftOp()), + toTerm(expr.getRightOp())); + } + + protected String transformEnumLit(final EnumLitExpr expr) { + String longName = EnumType.makeLongName(expr.getType(), expr.getValue()); + symbolTable.putEnumLiteral(longName, expr); + return longName; + } + /* * Bitvectors */ diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibSolverBinary.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibSolverBinary.java index f9c36afa9a..3acef6cb5e 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibSolverBinary.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibSolverBinary.java @@ -34,6 +34,7 @@ public final class GenericSmtLibSolverBinary implements SmtLibSolverBinary { private final NuProcess solverProcess; private final ProcessHandler processHandler; + private final List issuedCommands = new ArrayList<>(); public GenericSmtLibSolverBinary(final Path solverPath, final String[] args) { this(solverPath, args, EnumSet.noneOf(Solver.class)); @@ -61,6 +62,7 @@ public GenericSmtLibSolverBinary(final Path solverPath, final String[] args, @Override public void issueCommand(final String command) { + issuedCommands.add(command); checkState(solverProcess.isRunning()); processHandler.write(command); solverProcess.wantWrite(); diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibSolverFactory.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibSolverFactory.java index a544b9eb7c..17f00eb5be 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibSolverFactory.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibSolverFactory.java @@ -20,6 +20,7 @@ import hu.bme.mit.theta.solver.Solver; import hu.bme.mit.theta.solver.SolverFactory; import hu.bme.mit.theta.solver.UCSolver; +import hu.bme.mit.theta.solver.smtlib.solver.SmtLibEnumStrategy; import hu.bme.mit.theta.solver.smtlib.solver.SmtLibSolver; import java.nio.file.Path; @@ -27,6 +28,8 @@ public class GenericSmtLibSolverFactory implements SolverFactory { + protected final SmtLibEnumStrategy enumStrategy; + protected final Path solverPath; protected final String[] args; private final EnumSet solverOverride; @@ -37,31 +40,47 @@ protected GenericSmtLibSolverFactory(Path solverPath, String[] args) { protected GenericSmtLibSolverFactory(Path solverPath, String[] args, EnumSet solverOverride) { + this(solverPath, args, solverOverride, SmtLibEnumStrategy.SORTS); + } + + protected GenericSmtLibSolverFactory(Path solverPath, String[] args, + SmtLibEnumStrategy enumStrategy) { + this(solverPath, args, EnumSet.noneOf(GenericSmtLibSolverBinary.Solver.class), enumStrategy); + } + + protected GenericSmtLibSolverFactory(Path solverPath, String[] args, + EnumSet solverOverride, + SmtLibEnumStrategy enumStrategy) { this.solverPath = solverPath; this.args = args; this.solverOverride = solverOverride; + this.enumStrategy = enumStrategy; } public static GenericSmtLibSolverFactory create(Path solverPath, String[] args) { return new GenericSmtLibSolverFactory(solverPath, args); } + public static GenericSmtLibSolverFactory create(Path solverPath, String[] args, SmtLibEnumStrategy enumStrategy) { + return new GenericSmtLibSolverFactory(solverPath, args, enumStrategy); + } + @Override public Solver createSolver() { final var symbolTable = new GenericSmtLibSymbolTable(); final var transformationManager = new GenericSmtLibTransformationManager(symbolTable); - final var termTransformer = new GenericSmtLibTermTransformer(symbolTable); + final var termTransformer = new GenericSmtLibTermTransformer(symbolTable, enumStrategy); final var solverBinary = new GenericSmtLibSolverBinary(solverPath, args, solverOverride); return new SmtLibSolver(symbolTable, transformationManager, termTransformer, solverBinary, - false); + false, enumStrategy); } @Override public UCSolver createUCSolver() { final var symbolTable = new GenericSmtLibSymbolTable(); final var transformationManager = new GenericSmtLibTransformationManager(symbolTable); - final var termTransformer = new GenericSmtLibTermTransformer(symbolTable); + final var termTransformer = new GenericSmtLibTermTransformer(symbolTable, enumStrategy); final var solverBinary = new GenericSmtLibSolverBinary(solverPath, args, solverOverride); return new SmtLibSolver(symbolTable, transformationManager, termTransformer, solverBinary, diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibSymbolTable.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibSymbolTable.java index f003780f0f..d4a9665ef9 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibSymbolTable.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibSymbolTable.java @@ -19,8 +19,12 @@ import com.google.common.collect.HashBiMap; import com.google.common.collect.Maps; import hu.bme.mit.theta.core.decl.ConstDecl; +import hu.bme.mit.theta.core.type.enumtype.EnumLitExpr; import hu.bme.mit.theta.solver.smtlib.solver.transformer.SmtLibSymbolTable; +import java.util.HashMap; +import java.util.Map; + import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; @@ -32,10 +36,12 @@ public class GenericSmtLibSymbolTable implements SmtLibSymbolTable { private final BiMap, String> constToSymbol; private final BiMap, String> constToDeclaration; + private final Map symbolToEnumLiteral; public GenericSmtLibSymbolTable() { constToSymbol = Maps.synchronizedBiMap(HashBiMap.create()); constToDeclaration = Maps.synchronizedBiMap(HashBiMap.create()); + symbolToEnumLiteral = new HashMap<>(); } public GenericSmtLibSymbolTable(GenericSmtLibSymbolTable table) { @@ -43,6 +49,8 @@ public GenericSmtLibSymbolTable(GenericSmtLibSymbolTable table) { constToSymbol.putAll(table.constToSymbol); constToDeclaration = Maps.synchronizedBiMap(HashBiMap.create()); constToDeclaration.putAll(table.constToDeclaration); + symbolToEnumLiteral = new HashMap<>(); + symbolToEnumLiteral.putAll(table.symbolToEnumLiteral); } @Override @@ -56,6 +64,11 @@ public boolean definesSymbol(final String symbol) { symbol.replaceAll(problematicCharactersRegex, problematicCharactersReplacement)); } + @Override + public boolean definesEnumLiteral(String literal) { + return symbolToEnumLiteral.containsKey(literal); + } + @Override public String getSymbol(final ConstDecl constDecl) { checkArgument(definesConst(constDecl)); @@ -74,6 +87,11 @@ public ConstDecl getConst(final String symbol) { return constToSymbol.inverse().get(symbol); } + @Override + public EnumLitExpr getEnumLiteral(String literal) { + return symbolToEnumLiteral.get(literal); + } + @Override public void put(final ConstDecl constDecl, final String symbol, final String declaration) { checkNotNull(constDecl); @@ -85,4 +103,9 @@ public void put(final ConstDecl constDecl, final String symbol, final String constToDeclaration.put(constDecl, declaration.replaceAll(problematicCharactersRegex, problematicCharactersReplacement)); } + + @Override + public void putEnumLiteral(String symbol, EnumLitExpr litExpr) { + symbolToEnumLiteral.put(symbol, litExpr); + } } diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibTermTransformer.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibTermTransformer.java index b7192786ef..2f2e33d8be 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibTermTransformer.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibTermTransformer.java @@ -28,77 +28,16 @@ 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.abstracttype.AddExpr; -import hu.bme.mit.theta.core.type.abstracttype.EqExpr; -import hu.bme.mit.theta.core.type.abstracttype.GeqExpr; -import hu.bme.mit.theta.core.type.abstracttype.GtExpr; -import hu.bme.mit.theta.core.type.abstracttype.LeqExpr; -import hu.bme.mit.theta.core.type.abstracttype.LtExpr; -import hu.bme.mit.theta.core.type.abstracttype.ModExpr; -import hu.bme.mit.theta.core.type.abstracttype.MulExpr; -import hu.bme.mit.theta.core.type.abstracttype.NegExpr; -import hu.bme.mit.theta.core.type.abstracttype.RemExpr; -import hu.bme.mit.theta.core.type.abstracttype.SubExpr; +import hu.bme.mit.theta.core.type.abstracttype.*; import hu.bme.mit.theta.core.type.anytype.IteExpr; import hu.bme.mit.theta.core.type.arraytype.ArrayReadExpr; import hu.bme.mit.theta.core.type.arraytype.ArrayType; 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.BoolExprs; -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.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.BvExprs; -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.BvNegExpr; -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.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.BvSubExpr; -import hu.bme.mit.theta.core.type.bvtype.BvType; -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.fptype.FpAbsExpr; -import hu.bme.mit.theta.core.type.fptype.FpAddExpr; -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.FpExprs; -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.FpIsNanExpr; -import hu.bme.mit.theta.core.type.fptype.FpLeqExpr; -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.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.booltype.*; +import hu.bme.mit.theta.core.type.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.fptype.*; import hu.bme.mit.theta.core.type.functype.FuncExprs; import hu.bme.mit.theta.core.type.functype.FuncLitExpr; import hu.bme.mit.theta.core.type.functype.FuncType; @@ -110,7 +49,7 @@ import hu.bme.mit.theta.core.utils.ExprUtils; import hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Lexer; import hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser; -import hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser.Let_termContext; +import hu.bme.mit.theta.solver.smtlib.solver.SmtLibEnumStrategy; import hu.bme.mit.theta.solver.smtlib.solver.SmtLibSolverException; import hu.bme.mit.theta.solver.smtlib.solver.model.SmtLibModel; import hu.bme.mit.theta.solver.smtlib.solver.parser.ThrowExceptionErrorListener; @@ -121,53 +60,36 @@ import java.math.BigDecimal; import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.BiFunction; -import java.util.function.BinaryOperator; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.function.UnaryOperator; +import java.util.*; +import java.util.function.*; import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static hu.bme.mit.theta.core.decl.Decls.Param; import static hu.bme.mit.theta.core.type.arraytype.ArrayExprs.Array; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Exists; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Forall; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.*; import static hu.bme.mit.theta.core.type.functype.FuncExprs.Func; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; import static hu.bme.mit.theta.core.type.rattype.RatExprs.Rat; import static hu.bme.mit.theta.core.utils.TypeUtils.cast; import static hu.bme.mit.theta.core.utils.TypeUtils.castBv; -import static hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser.BinaryContext; -import static hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser.DecimalContext; -import static hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser.Exists_termContext; -import static hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser.Forall_termContext; -import static hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser.Generic_termContext; -import static hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser.HexadecimalContext; -import static hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser.IdentifierContext; -import static hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser.IndexContext; -import static hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser.NumeralContext; -import static hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser.Qual_identifierContext; -import static hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser.SortContext; -import static hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser.Spec_constantContext; -import static hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser.SymbolContext; -import static hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser.TermContext; +import static hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser.*; import static java.util.stream.Collectors.toList; public class GenericSmtLibTermTransformer implements SmtLibTermTransformer { protected final SmtLibSymbolTable symbolTable; protected final Map funAppTransformer; + protected final SmtLibEnumStrategy enumStrategy; public GenericSmtLibTermTransformer(final SmtLibSymbolTable symbolTable) { + this(symbolTable, SmtLibEnumStrategy.getDefaultStrategy()); + } + + public GenericSmtLibTermTransformer(final SmtLibSymbolTable symbolTable, final SmtLibEnumStrategy enumStrategy) { this.symbolTable = symbolTable; + this.enumStrategy = enumStrategy; this.funAppTransformer = new HashMap<>() {{ // Generic put("ite", exprIteOperator()); @@ -304,6 +226,8 @@ private Expr toExpr(final String term, final SmtLibModel model) { @Override public LitExpr toLitExpr(final String litImpl, final T type, final SmtLibModel model) { + if (type instanceof EnumType enumType) + return (LitExpr) cast(toEnumLitExpr(litImpl, enumType, model), type); final var litExpr = toLitExpr(litImpl, model); if (litExpr == null) { @@ -336,6 +260,18 @@ private Expr toLitExpr(final String litImpl, final SmtLibModel model) { return expr; } + private EnumLitExpr toEnumLitExpr(final String litImpl, final EnumType type, final SmtLibModel model) { + final var lexer = new SMTLIBv2Lexer(CharStreams.fromString(litImpl)); + final var parser = new SMTLIBv2Parser(new CommonTokenStream(lexer)); + lexer.removeErrorListeners(); + lexer.addErrorListener(new ThrowExceptionErrorListener()); + parser.removeErrorListeners(); + parser.addErrorListener(new ThrowExceptionErrorListener()); + + final var funcDef = parser.function_def(); + return enumStrategy.transformEnumTerm(funcDef, type, model); + } + @Override @SuppressWarnings("unchecked") public LitExpr> toArrayLitExpr( @@ -621,8 +557,10 @@ protected Expr transformSymbol(final SymbolContext ctx, final SmtLibModel mod return decl.getRef(); } else if (symbolTable.definesSymbol(value)) { return symbolTable.getConst(value).getRef(); + } else if (symbolTable.definesEnumLiteral(value)) { + return symbolTable.getEnumLiteral(value); } else { - throw new SmtLibSolverException("Transforation of symbol not supported: " + value); + throw new SmtLibSolverException("Transformation of symbol not supported: " + value); } } } diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibTransformationManager.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibTransformationManager.java index 8d6bc2f811..24fefdfcae 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibTransformationManager.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibTransformationManager.java @@ -33,7 +33,7 @@ public class GenericSmtLibTransformationManager implements SmtLibTransformationM public GenericSmtLibTransformationManager(final SmtLibSymbolTable symbolTable) { this.typeTransformer = instantiateTypeTransformer(this); this.declTransformer = instantiateDeclTransformer(this, symbolTable); - this.exprTransformer = instantiateExprTransformer(this); + this.exprTransformer = instantiateExprTransformer(this, symbolTable); } @Override @@ -63,7 +63,8 @@ protected SmtLibDeclTransformer instantiateDeclTransformer( } protected SmtLibExprTransformer instantiateExprTransformer( - final SmtLibTransformationManager transformer) { - return new GenericSmtLibExprTransformer(transformer); + final SmtLibTransformationManager transformer, final SmtLibSymbolTable symbolTable + ) { + return new GenericSmtLibExprTransformer(transformer, symbolTable); } } diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibTypeTransformer.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibTypeTransformer.java index ff6c8061d6..c0442f7ab7 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibTypeTransformer.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/generic/GenericSmtLibTypeTransformer.java @@ -22,6 +22,7 @@ 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.BvType; +import hu.bme.mit.theta.core.type.enumtype.EnumType; import hu.bme.mit.theta.core.type.fptype.FpType; import hu.bme.mit.theta.core.type.inttype.IntType; import hu.bme.mit.theta.core.type.rattype.RatType; @@ -55,6 +56,7 @@ protected DispatchTable.Builder buildDispatchTable(DispatchTable.Builder .addCase(RatType.class, this::ratType) .addCase(BvType.class, this::bvType) .addCase(FpType.class, this::fpType) + .addCase(EnumType.class, this::enumType) .addCase(ArrayType.class, this::arrayType); return builder; } @@ -92,4 +94,8 @@ protected String arrayType(final ArrayType type) { return String.format("(Array %s %s)", toSort(type.getIndexType()), toSort(type.getElemType())); } + + protected String enumType(final EnumType type) { + return type.getName(); + } } diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/mathsat/MathSATSmtLibExprTransformer.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/mathsat/MathSATSmtLibExprTransformer.java index 4ec99b63d2..5a7dbd33b4 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/mathsat/MathSATSmtLibExprTransformer.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/mathsat/MathSATSmtLibExprTransformer.java @@ -17,12 +17,13 @@ import hu.bme.mit.theta.core.type.inttype.IntRemExpr; import hu.bme.mit.theta.solver.smtlib.impl.generic.GenericSmtLibExprTransformer; +import hu.bme.mit.theta.solver.smtlib.solver.transformer.SmtLibSymbolTable; import hu.bme.mit.theta.solver.smtlib.solver.transformer.SmtLibTransformationManager; public class MathSATSmtLibExprTransformer extends GenericSmtLibExprTransformer { - public MathSATSmtLibExprTransformer(final SmtLibTransformationManager transformer) { - super(transformer); + public MathSATSmtLibExprTransformer(final SmtLibTransformationManager transformer, final SmtLibSymbolTable symbolTable) { + super(transformer, symbolTable); } @Override diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/mathsat/MathSATSmtLibSolverFactory.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/mathsat/MathSATSmtLibSolverFactory.java index 4738147047..827bddc5d3 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/mathsat/MathSATSmtLibSolverFactory.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/mathsat/MathSATSmtLibSolverFactory.java @@ -44,7 +44,7 @@ public static MathSATSmtLibSolverFactory create(Path solverPath, String[] args, public Solver createSolver() { final var symbolTable = new GenericSmtLibSymbolTable(); final var transformationManager = new MathSATSmtLibTransformationManager(symbolTable); - final var termTransformer = new GenericSmtLibTermTransformer(symbolTable); + final var termTransformer = new GenericSmtLibTermTransformer(symbolTable, enumStrategy); final var solverBinary = new GenericSmtLibSolverBinary(solverPath, args); return new SmtLibSolver(symbolTable, transformationManager, termTransformer, solverBinary, @@ -55,7 +55,7 @@ public Solver createSolver() { public UCSolver createUCSolver() { final var symbolTable = new GenericSmtLibSymbolTable(); final var transformationManager = new MathSATSmtLibTransformationManager(symbolTable); - final var termTransformer = new GenericSmtLibTermTransformer(symbolTable); + final var termTransformer = new GenericSmtLibTermTransformer(symbolTable, enumStrategy); final var solverBinary = new GenericSmtLibSolverBinary(solverPath, args); return new SmtLibSolver(symbolTable, transformationManager, termTransformer, solverBinary, @@ -67,7 +67,7 @@ public ItpSolver createItpSolver() { if (itpSupported) { final var symbolTable = new GenericSmtLibSymbolTable(); final var transformationManager = new MathSATSmtLibTransformationManager(symbolTable); - final var termTransformer = new GenericSmtLibTermTransformer(symbolTable); + final var termTransformer = new GenericSmtLibTermTransformer(symbolTable, enumStrategy); final var solverBinary = new GenericSmtLibSolverBinary(solverPath, args); return new MathSATSmtLibItpSolver(symbolTable, transformationManager, termTransformer, diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/mathsat/MathSATSmtLibTransformationManager.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/mathsat/MathSATSmtLibTransformationManager.java index 7c148969ca..12dd71c7bb 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/mathsat/MathSATSmtLibTransformationManager.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/mathsat/MathSATSmtLibTransformationManager.java @@ -28,7 +28,8 @@ public MathSATSmtLibTransformationManager(final SmtLibSymbolTable symbolTable) { @Override protected SmtLibExprTransformer instantiateExprTransformer( - final SmtLibTransformationManager transformer) { - return new MathSATSmtLibExprTransformer(transformer); + final SmtLibTransformationManager transformer, final SmtLibSymbolTable symbolTable + ) { + return new MathSATSmtLibExprTransformer(transformer, symbolTable); } } diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/princess/PrincessSmtLibItpSolver.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/princess/PrincessSmtLibItpSolver.java index 8ab0bc7590..4a797c200e 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/princess/PrincessSmtLibItpSolver.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/princess/PrincessSmtLibItpSolver.java @@ -19,13 +19,10 @@ import hu.bme.mit.theta.core.type.Expr; import hu.bme.mit.theta.core.type.booltype.BoolExprs; import hu.bme.mit.theta.core.type.booltype.BoolType; -import hu.bme.mit.theta.solver.Interpolant; -import hu.bme.mit.theta.solver.ItpMarker; -import hu.bme.mit.theta.solver.ItpMarkerTree; -import hu.bme.mit.theta.solver.ItpPattern; -import hu.bme.mit.theta.solver.SolverStatus; +import hu.bme.mit.theta.solver.*; import hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Lexer; import hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser; +import hu.bme.mit.theta.solver.smtlib.solver.SmtLibEnumStrategy; import hu.bme.mit.theta.solver.smtlib.solver.SmtLibItpSolver; import hu.bme.mit.theta.solver.smtlib.solver.SmtLibSolverException; import hu.bme.mit.theta.solver.smtlib.solver.binary.SmtLibSolverBinary; @@ -44,9 +41,7 @@ import java.util.*; import java.util.stream.Collectors; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Preconditions.*; import static hu.bme.mit.theta.core.type.booltype.BoolExprs.False; public final class PrincessSmtLibItpSolver extends SmtLibItpSolver { @@ -58,9 +53,10 @@ public final class PrincessSmtLibItpSolver extends SmtLibItpSolver { @@ -65,9 +53,10 @@ public final class SMTInterpolSmtLibItpSolver extends SmtLibItpSolver final var name = String.format(assertionNamePattern, assertionCount++); assertionNames.put(assertion, name); - issueGeneralCommand(String.format("(assert (! %s :named %s))", term, name)); + issueGeneralCommand(String.format("(assert (! %s :named %s))", enumStrategy.wrapAssertionExpression(term, consts.stream().collect(Collectors.toMap(c -> c, symbolTable::getSymbol))), name)); } @Override diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/smtinterpol/SMTInterpolSmtLibSolverFactory.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/smtinterpol/SMTInterpolSmtLibSolverFactory.java index 4068d72f02..1ca42d77f3 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/smtinterpol/SMTInterpolSmtLibSolverFactory.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/smtinterpol/SMTInterpolSmtLibSolverFactory.java @@ -23,55 +23,59 @@ import hu.bme.mit.theta.solver.smtlib.impl.generic.GenericSmtLibSymbolTable; import hu.bme.mit.theta.solver.smtlib.impl.generic.GenericSmtLibTermTransformer; import hu.bme.mit.theta.solver.smtlib.impl.generic.GenericSmtLibTransformationManager; +import hu.bme.mit.theta.solver.smtlib.solver.SmtLibEnumStrategy; import hu.bme.mit.theta.solver.smtlib.solver.SmtLibSolver; import java.nio.file.Path; public class SMTInterpolSmtLibSolverFactory implements SolverFactory { + private final SmtLibEnumStrategy enumStrategy; + private final Path solverPath; private final String[] args; - private SMTInterpolSmtLibSolverFactory(Path solverPath, String[] args) { + private SMTInterpolSmtLibSolverFactory(Path solverPath, String[] args, final SmtLibEnumStrategy enumStrategy) { this.solverPath = solverPath; this.args = args; + this.enumStrategy = enumStrategy; } - public static SMTInterpolSmtLibSolverFactory create(Path solverPath, String[] args) { - return new SMTInterpolSmtLibSolverFactory(solverPath, args); + public static SMTInterpolSmtLibSolverFactory create(Path solverPath, String[] args, final SmtLibEnumStrategy enumStrategy) { + return new SMTInterpolSmtLibSolverFactory(solverPath, args, enumStrategy); } @Override public Solver createSolver() { final var symbolTable = new GenericSmtLibSymbolTable(); final var transformationManager = new GenericSmtLibTransformationManager(symbolTable); - final var termTransformer = new GenericSmtLibTermTransformer(symbolTable); + final var termTransformer = new GenericSmtLibTermTransformer(symbolTable, enumStrategy); final var solverBinary = new GenericSmtLibSolverBinary(getJavaBinary(), getSolverArgs()); return new SmtLibSolver(symbolTable, transformationManager, termTransformer, solverBinary, - false); + false, enumStrategy); } @Override public UCSolver createUCSolver() { final var symbolTable = new GenericSmtLibSymbolTable(); final var transformationManager = new GenericSmtLibTransformationManager(symbolTable); - final var termTransformer = new GenericSmtLibTermTransformer(symbolTable); + final var termTransformer = new GenericSmtLibTermTransformer(symbolTable, enumStrategy); final var solverBinary = new GenericSmtLibSolverBinary(getJavaBinary(), getSolverArgs()); return new SmtLibSolver(symbolTable, transformationManager, termTransformer, solverBinary, - true); + true, enumStrategy); } @Override public ItpSolver createItpSolver() { final var symbolTable = new GenericSmtLibSymbolTable(); final var transformationManager = new GenericSmtLibTransformationManager(symbolTable); - final var termTransformer = new GenericSmtLibTermTransformer(symbolTable); + final var termTransformer = new GenericSmtLibTermTransformer(symbolTable, enumStrategy); final var solverBinary = new GenericSmtLibSolverBinary(getJavaBinary(), getSolverArgs()); return new SMTInterpolSmtLibItpSolver(symbolTable, transformationManager, termTransformer, - solverBinary); + solverBinary, enumStrategy); } private Path getJavaBinary() { @@ -82,9 +86,7 @@ private String[] getSolverArgs() { final var solverArgs = new String[args.length + 2]; solverArgs[0] = "-jar"; solverArgs[1] = solverPath.toAbsolutePath().toString(); - for (var i = 0; i < args.length; i++) { - solverArgs[i + 2] = args[i]; - } + System.arraycopy(args, 0, solverArgs, 2, args.length); return solverArgs; } } diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/smtinterpol/SMTInterpolSmtLibSolverInstaller.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/smtinterpol/SMTInterpolSmtLibSolverInstaller.java index 3fbdc13376..a97ba7a0c0 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/smtinterpol/SMTInterpolSmtLibSolverInstaller.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/smtinterpol/SMTInterpolSmtLibSolverInstaller.java @@ -17,6 +17,7 @@ import hu.bme.mit.theta.common.logging.Logger; import hu.bme.mit.theta.solver.SolverFactory; +import hu.bme.mit.theta.solver.smtlib.solver.SmtLibEnumStrategy; import hu.bme.mit.theta.solver.smtlib.solver.installer.SmtLibSolverInstaller; import hu.bme.mit.theta.solver.smtlib.solver.installer.SmtLibSolverInstallerException; @@ -76,39 +77,28 @@ public SolverFactory getSolverFactory(final Path installDir, final String versio final Path solverPath, final String[] solverArgs) throws SmtLibSolverInstallerException { final var solverFilePath = solverPath != null ? solverPath : installDir.resolve(getSolverBinaryName(version)); - return SMTInterpolSmtLibSolverFactory.create(solverFilePath, solverArgs); + return SMTInterpolSmtLibSolverFactory.create(solverFilePath, solverArgs, getEnumStrategyForVersion(version)); } @Override public List getSupportedVersions() { - return Arrays.asList("2.5-1256", "2.5-1230", "2.5-916", "2.5-663", "2.5-479", "2.5-7"); + //TODO download won't work on 2.5-1301 yet, so in order for 'latest' to work, order has to stay like this for now + return Arrays.asList("2.5-1256", "2.5-1301", "2.5-1230", "2.5-916", "2.5-663", "2.5-479", "2.5-7"); } private URL getDownloadUrl(final String version) throws SmtLibSolverInstallerException, MalformedURLException { - final String fileName; - switch (version) { - case "2.5-1256": - fileName = "2.5-1256-g55d6ba76"; - break; - case "2.5-1230": - fileName = "2.5-1230-g3eafb46a"; - break; - case "2.5-916": - fileName = "2.5-916-ga5843d8b"; - break; - case "2.5-663": - fileName = "2.5-663-gf15aa217"; - break; - case "2.5-479": - fileName = "2.5-479-ga49e50b1"; - break; - case "2.5-7": - fileName = "2.5-7-g64ec65d"; - break; - default: - throw new SmtLibSolverInstallerException("Unsupported solver version."); - } + final String fileName = switch (version) { + + case "2.5-1301" -> "2.5-1301-g2c871e40"; + case "2.5-1256" -> "2.5-1256-g55d6ba76"; + case "2.5-1230" -> "2.5-1230-g3eafb46a"; + case "2.5-916" -> "2.5-916-ga5843d8b"; + case "2.5-663" -> "2.5-663-gf15aa217"; + case "2.5-479" -> "2.5-479-ga49e50b1"; + case "2.5-7" -> "2.5-7-g64ec65d"; + default -> throw new SmtLibSolverInstallerException("Unsupported solver version."); + }; return URI.create(String.format( "https://ultimate.informatik.uni-freiburg.de/smtinterpol/smtinterpol-%s.jar", @@ -119,4 +109,12 @@ private URL getDownloadUrl(final String version) private String getSolverBinaryName(final String version) { return String.format("smtinterpol-%s.jar", version); } + + private SmtLibEnumStrategy getEnumStrategyForVersion(final String version) { + // pre-release version 2.5-1301-g2c871e40 already suppoprted datatype interpolation + if (Integer.valueOf(version.split("-")[1]) > 1256) { + return SmtLibEnumStrategy.DATATYPES; + } + return SmtLibEnumStrategy.SORTS; + } } diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/z3/Z3SmtLibSolverFactory.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/z3/Z3SmtLibSolverFactory.java index be6a399b8b..926e89b0e9 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/z3/Z3SmtLibSolverFactory.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/impl/z3/Z3SmtLibSolverFactory.java @@ -47,7 +47,7 @@ public ItpSolver createItpSolver() { if (!itpSupport.equals(Z3ItpSupport.NONE)) { final var symbolTable = new GenericSmtLibSymbolTable(); final var transformationManager = new GenericSmtLibTransformationManager(symbolTable); - final var termTransformer = new GenericSmtLibTermTransformer(symbolTable); + final var termTransformer = new GenericSmtLibTermTransformer(symbolTable, enumStrategy); final var solverBinary = new GenericSmtLibSolverBinary(solverPath, args); if (itpSupport.equals(Z3ItpSupport.OLD)) { diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/SmtLibEnumStrategy.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/SmtLibEnumStrategy.java new file mode 100644 index 0000000000..f72ee5939c --- /dev/null +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/SmtLibEnumStrategy.java @@ -0,0 +1,125 @@ +/* + * 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.smtlib.solver; + +import hu.bme.mit.theta.core.decl.ConstDecl; +import hu.bme.mit.theta.core.type.Type; +import hu.bme.mit.theta.core.type.enumtype.EnumLitExpr; +import hu.bme.mit.theta.core.type.enumtype.EnumType; +import hu.bme.mit.theta.solver.Stack; +import hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser; +import hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser.Function_defContext; +import hu.bme.mit.theta.solver.smtlib.solver.model.SmtLibModel; + +import java.util.*; +import java.util.function.Consumer; + +/** + * EnumTypes need to be handled on SMT solvers too. SmtLib standard contains datatypes, and the + * behaviour for that is implemented in the DATATYPES strategy. However, most solvers don't support + * interpolation with datatypes. For this, a workaround is implemented in the SORTS strategy. + */ +public enum SmtLibEnumStrategy { + + DATATYPES { + @Override + public void declareDatatypes(final Collection allTypes, final Stack typeStack, final Consumer issueGeneralCommand) { + List types = new ArrayList<>(allTypes); + types.removeAll(typeStack.toCollection()); + Set typeSet = new HashSet<>(types); + for (Type t : + typeSet) { + if (t instanceof EnumType enumType) { + typeStack.add(enumType); + Collection literals = enumType.getLongValues().stream().map(name -> String.format("(%s)", name)).toList(); + issueGeneralCommand.accept(String.format("(declare-datatypes ((%s 0)) ((%s)))", enumType.getName(), String.join(" ", literals))); + } + } + } + + @Override + public EnumLitExpr transformEnumTerm(Function_defContext funcDef, EnumType type, SmtLibModel model) { + final String longName = funcDef.term().qual_identifier().identifier().symbol().getText(); + return type.litFromLongName(longName); + } + }, + + SORTS { + @Override + public void declareDatatypes(Collection allTypes, Stack typeStack, Consumer issueGeneralCommand) { + List types = new ArrayList<>(allTypes); + types.removeAll(typeStack.toCollection()); + Set typeSet = new HashSet<>(types); + for (Type t : + typeSet) { + if (t instanceof EnumType enumType) { + typeStack.add(enumType); + issueGeneralCommand.accept(String.format("(declare-sort %s 0)", enumType.getName())); + enumType.getLongValues().forEach(literal -> issueGeneralCommand.accept(String.format("(declare-const %s %s)", literal, enumType.getName()))); + issueGeneralCommand.accept(String.format("(assert (distinct %s))", String.join(" ", enumType.getLongValues()))); + } + } + } + + @Override + public String wrapAssertionExpression(String assertion, Map, String> consts) { + boolean needsWrap = false; + StringBuilder sb = new StringBuilder("(and ").append(assertion); + for (var constDeclEntry : consts.entrySet()) { + var constDecl = constDeclEntry.getKey(); + var nameOnSolver = constDeclEntry.getValue(); + if (constDecl.getType() instanceof EnumType enumType) { + sb.append(" (or"); + enumType.getLongValues().forEach(val -> sb.append(String.format(" (= %s %s)", nameOnSolver, val))); + sb.append(")"); + needsWrap = true; + } + } + sb.append(")"); + return needsWrap ? sb.toString() : assertion; + } + + @Override + public EnumLitExpr transformEnumTerm(Function_defContext funcDef, EnumType type, SmtLibModel model) { + final String id = funcDef.term().qual_identifier().identifier().symbol().getText(); + for (var lit : type.getLongValues()) { + if (model.getTerm(lit).contains(id)) + return type.litFromLongName(lit); + } + throw new RuntimeException(); + } + }; + + + public abstract void declareDatatypes(final Collection allTypes, final Stack typeStack, final Consumer issueGeneralCommand); + + /** + * Wraps an expression with additional ones if needed. + * + * @param assertion the expression part that was going to be asserted. (e.g. "(= x 1)") + * @param consts all variables part of the expression + */ + public String wrapAssertionExpression(final String assertion, final Map, String> consts) { + return assertion; + } + + public abstract EnumLitExpr transformEnumTerm(final SMTLIBv2Parser.Function_defContext funcDef, final EnumType type, final SmtLibModel model); + + public static SmtLibEnumStrategy getDefaultStrategy() { + return SmtLibEnumStrategy.SORTS; + } + +} diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/SmtLibItpSolver.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/SmtLibItpSolver.java index 6fe9ce060c..02faec669d 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/SmtLibItpSolver.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/SmtLibItpSolver.java @@ -18,16 +18,11 @@ import hu.bme.mit.theta.core.decl.ConstDecl; import hu.bme.mit.theta.core.model.Valuation; import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.Type; import hu.bme.mit.theta.core.type.booltype.BoolType; +import hu.bme.mit.theta.core.type.enumtype.EnumType; import hu.bme.mit.theta.core.utils.ExprUtils; -import hu.bme.mit.theta.solver.Interpolant; -import hu.bme.mit.theta.solver.ItpMarker; -import hu.bme.mit.theta.solver.ItpMarkerTree; -import hu.bme.mit.theta.solver.ItpPattern; -import hu.bme.mit.theta.solver.ItpSolver; -import hu.bme.mit.theta.solver.SolverStatus; -import hu.bme.mit.theta.solver.Stack; -import hu.bme.mit.theta.solver.UnknownSolverStatusException; +import hu.bme.mit.theta.solver.*; import hu.bme.mit.theta.solver.impl.StackImpl; import hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Lexer; import hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser; @@ -46,10 +41,9 @@ import java.util.Collection; import java.util.Set; +import java.util.stream.Collectors; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Preconditions.*; public abstract class SmtLibItpSolver implements ItpSolver { @@ -62,6 +56,8 @@ public abstract class SmtLibItpSolver implements ItpS protected final Stack> assertions; protected final Stack markers; protected final Stack> declarationStack; + protected final Stack typeStack; + protected final SmtLibEnumStrategy enumStrategy; private Valuation model; private SolverStatus status; @@ -71,22 +67,31 @@ public SmtLibItpSolver( final SmtLibSymbolTable symbolTable, final SmtLibTransformationManager transformationManager, final SmtLibTermTransformer termTransformer, final SmtLibSolverBinary solverBinary + ) { + this(symbolTable, transformationManager, termTransformer, solverBinary, SmtLibEnumStrategy.getDefaultStrategy()); + } + + public SmtLibItpSolver( + final SmtLibSymbolTable symbolTable, + final SmtLibTransformationManager transformationManager, + final SmtLibTermTransformer termTransformer, final SmtLibSolverBinary solverBinary, + final SmtLibEnumStrategy enumStrategy ) { this.symbolTable = symbolTable; this.transformationManager = transformationManager; this.termTransformer = termTransformer; + this.enumStrategy = enumStrategy; this.solverBinary = solverBinary; this.assertions = new StackImpl<>(); this.markers = new StackImpl<>(); this.declarationStack = new StackImpl<>(); + typeStack = new StackImpl<>(); init(); } - @Override - public abstract ItpPattern createTreePattern(ItpMarkerTree root); @Override public abstract T createMarker(); @@ -107,13 +112,15 @@ public void add(final ItpMarker marker, final Expr assertion) { final var consts = ExprUtils.getConstants(assertion); consts.removeAll(declarationStack.toCollection()); declarationStack.add(consts); + enumStrategy.declareDatatypes((Collection) consts.stream().map(ConstDecl::getType).toList(), typeStack, this::issueGeneralCommand); final var itpMarker = (T) marker; final var term = transformationManager.toTerm(assertion); - itpMarker.add(assertion, term); + + itpMarker.add(assertion, enumStrategy.wrapAssertionExpression(term, ExprUtils.getConstants(assertion).stream().collect(Collectors.toMap(c -> c, symbolTable::getSymbol)))); assertions.add(assertion); - add(itpMarker, assertion, consts, term); + add(itpMarker, assertion, consts, enumStrategy.wrapAssertionExpression(term, ExprUtils.getConstants(assertion).stream().collect(Collectors.toMap(c -> c, symbolTable::getSymbol)))); clearState(); } @@ -151,6 +158,7 @@ public void push() { } assertions.push(); declarationStack.push(); + typeStack.push(); issueGeneralCommand("(push 1)"); } @@ -162,6 +170,7 @@ public void pop(final int n) { } assertions.pop(n); declarationStack.pop(n); + typeStack.pop(n); issueGeneralCommand(String.format("(pop %d)", n)); clearState(); } @@ -207,9 +216,6 @@ private Valuation extractModel() { } } - @Override - public abstract Interpolant getInterpolant(ItpPattern pattern); - @Override public Collection> getAssertions() { return assertions.toCollection(); diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/SmtLibSolver.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/SmtLibSolver.java index 9cbd53991b..6f285c5292 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/SmtLibSolver.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/SmtLibSolver.java @@ -18,51 +18,42 @@ import hu.bme.mit.theta.core.decl.ConstDecl; import hu.bme.mit.theta.core.model.Valuation; import hu.bme.mit.theta.core.type.Expr; +import hu.bme.mit.theta.core.type.Type; import hu.bme.mit.theta.core.type.booltype.BoolType; +import hu.bme.mit.theta.core.type.enumtype.EnumType; import hu.bme.mit.theta.core.utils.ExprUtils; -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.UnknownSolverStatusException; +import hu.bme.mit.theta.solver.*; import hu.bme.mit.theta.solver.impl.StackImpl; import hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Lexer; import hu.bme.mit.theta.solver.smtlib.dsl.gen.SMTLIBv2Parser; import hu.bme.mit.theta.solver.smtlib.solver.binary.SmtLibSolverBinary; import hu.bme.mit.theta.solver.smtlib.solver.model.SmtLibValuation; -import hu.bme.mit.theta.solver.smtlib.solver.parser.CheckSatResponse; -import hu.bme.mit.theta.solver.smtlib.solver.parser.GeneralResponse; -import hu.bme.mit.theta.solver.smtlib.solver.parser.GetModelResponse; -import hu.bme.mit.theta.solver.smtlib.solver.parser.GetUnsatCoreResponse; -import hu.bme.mit.theta.solver.smtlib.solver.parser.ThrowExceptionErrorListener; +import hu.bme.mit.theta.solver.smtlib.solver.parser.*; import hu.bme.mit.theta.solver.smtlib.solver.transformer.SmtLibSymbolTable; import hu.bme.mit.theta.solver.smtlib.solver.transformer.SmtLibTermTransformer; import hu.bme.mit.theta.solver.smtlib.solver.transformer.SmtLibTransformationManager; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; +import java.util.*; +import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkState; public class SmtLibSolver implements UCSolver, Solver { + private static final String ASSUMPTION_LABEL = "_LABEL_%d"; protected final SmtLibSymbolTable symbolTable; protected final SmtLibTransformationManager transformationManager; protected final SmtLibTermTransformer termTransformer; - protected final SmtLibSolverBinary solverBinary; - private final boolean unsatCoreEnabled; - protected final Stack> assertions; protected final Map> assumptions; protected final Stack> declarationStack; - - private static final String ASSUMPTION_LABEL = "_LABEL_%d"; + protected final Stack typeStack; + protected final SmtLibEnumStrategy enumStrategy; + private final boolean unsatCoreEnabled; private int labelNum = 0; private Valuation model; @@ -74,34 +65,38 @@ public SmtLibSolver( final SmtLibTransformationManager transformationManager, final SmtLibTermTransformer termTransformer, final SmtLibSolverBinary solverBinary, boolean unsatCoreEnabled + ) { + this(symbolTable, transformationManager, termTransformer, solverBinary, unsatCoreEnabled, SmtLibEnumStrategy.getDefaultStrategy()); + } + + public SmtLibSolver( + final SmtLibSymbolTable symbolTable, + final SmtLibTransformationManager transformationManager, + final SmtLibTermTransformer termTransformer, final SmtLibSolverBinary solverBinary, + boolean unsatCoreEnabled, + final SmtLibEnumStrategy enumStrategy ) { this.solverBinary = solverBinary; this.symbolTable = symbolTable; this.transformationManager = transformationManager; this.termTransformer = termTransformer; + this.enumStrategy = enumStrategy; this.unsatCoreEnabled = unsatCoreEnabled; assertions = new StackImpl<>(); assumptions = new HashMap<>(); declarationStack = new StackImpl<>(); + typeStack = new StackImpl<>(); init(); } @Override public void add(Expr assertion) { - final var consts = ExprUtils.getConstants(assertion); - consts.removeAll(declarationStack.toCollection()); - declarationStack.add(consts); - - final var term = transformationManager.toTerm(assertion); - - assertions.add(assertion); - consts.stream().map(symbolTable::getDeclaration).forEach(this::issueGeneralCommand); - issueGeneralCommand(String.format("(assert %s)", term)); - - clearState(); + final var simplifiedAssertion = ExprUtils.simplify(assertion); + final var term = transformationManager.toTerm(simplifiedAssertion); + add(simplifiedAssertion, term); } public void add(final Expr assertion, final String term) { @@ -110,8 +105,9 @@ public void add(final Expr assertion, final String term) { declarationStack.add(consts); assertions.add(assertion); + enumStrategy.declareDatatypes((Collection) consts.stream().map(ConstDecl::getType).toList(), typeStack, this::issueGeneralCommand); consts.stream().map(symbolTable::getDeclaration).forEach(this::issueGeneralCommand); - issueGeneralCommand(String.format("(assert %s)", term)); + issueGeneralCommand(String.format("(assert %s)", enumStrategy.wrapAssertionExpression(term, ExprUtils.getConstants(assertion).stream().collect(Collectors.toMap(c -> c, symbolTable::getSymbol))))); clearState(); } @@ -128,7 +124,8 @@ public void track(Expr assertion) { assertions.add(assertion); consts.stream().map(symbolTable::getDeclaration).forEach(this::issueGeneralCommand); - issueGeneralCommand(String.format("(assert (! %s :named %s))", term, label)); + enumStrategy.declareDatatypes((Collection) consts.stream().map(ConstDecl::getType).toList(), typeStack, this::issueGeneralCommand); + issueGeneralCommand(String.format("(assert (! %s :named %s))", enumStrategy.wrapAssertionExpression(term, ExprUtils.getConstants(assertion).stream().collect(Collectors.toMap(c -> c, symbolTable::getSymbol))), label)); clearState(); } @@ -136,29 +133,32 @@ public void track(Expr assertion) { @Override public SolverStatus check() { solverBinary.issueCommand("(check-sat)"); - var res = parseResponse(solverBinary.readResponse()); + + final String rp = solverBinary.readResponse(); + final var res = parseResponse(rp); if (res.isError()) { throw new SmtLibSolverException(res.getReason()); - } else if (res.isSpecific()) { - final CheckSatResponse checkSatResponse = res.asSpecific().asCheckSatResponse(); - if (checkSatResponse.isSat()) { - status = SolverStatus.SAT; - } else if (checkSatResponse.isUnsat()) { - status = SolverStatus.UNSAT; - } else { - throw new UnknownSolverStatusException(); - } - } else { + } + if (!res.isSpecific()) { throw new AssertionError(); } - - return status; + final CheckSatResponse checkSatResponse = res.asSpecific().asCheckSatResponse(); + if (checkSatResponse.isSat()) { + status = SolverStatus.SAT; + return status; + } + if (checkSatResponse.isUnsat()) { + status = SolverStatus.UNSAT; + return status; + } + throw new UnknownSolverStatusException(); } @Override public void push() { assertions.push(); declarationStack.push(); + typeStack.push(); issueGeneralCommand("(push 1)"); } @@ -166,6 +166,7 @@ public void push() { public void pop(int n) { assertions.pop(n); declarationStack.pop(n); + typeStack.pop(n); issueGeneralCommand("(pop 1)"); clearState(); } diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/model/SmtLibValuation.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/model/SmtLibValuation.java index 37ed606968..0f88e2d4ff 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/model/SmtLibValuation.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/model/SmtLibValuation.java @@ -28,11 +28,7 @@ import hu.bme.mit.theta.solver.smtlib.solver.transformer.SmtLibTermTransformer; import hu.bme.mit.theta.solver.smtlib.solver.transformer.SmtLibTransformationManager; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; +import java.util.*; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/transformer/SmtLibSymbolTable.java b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/transformer/SmtLibSymbolTable.java index ba506f5a51..32d122c6a0 100644 --- a/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/transformer/SmtLibSymbolTable.java +++ b/subprojects/solver/solver-smtlib/src/main/java/hu/bme/mit/theta/solver/smtlib/solver/transformer/SmtLibSymbolTable.java @@ -16,6 +16,7 @@ package hu.bme.mit.theta.solver.smtlib.solver.transformer; import hu.bme.mit.theta.core.decl.ConstDecl; +import hu.bme.mit.theta.core.type.enumtype.EnumLitExpr; public interface SmtLibSymbolTable { @@ -23,11 +24,17 @@ public interface SmtLibSymbolTable { boolean definesSymbol(String symbol); + boolean definesEnumLiteral(String literal); + String getSymbol(ConstDecl constDecl); String getDeclaration(ConstDecl constDecl); ConstDecl getConst(String symbol); + EnumLitExpr getEnumLiteral(String literal); + void put(ConstDecl constDecl, String symbol, String declaration); + + void putEnumLiteral(String symbol, EnumLitExpr litExpr); } From 660345a5dbf03ed16c0144adf2f22f1a871376e7 Mon Sep 17 00:00:00 2001 From: RipplB Date: Thu, 20 Jun 2024 15:29:33 +0200 Subject: [PATCH 7/8] Add EnumType support to JavaSMT --- .../javasmt/JavaSMTDeclTransformer.java | 11 +- .../javasmt/JavaSMTExprTransformer.java | 257 +++++---------- .../theta/solver/javasmt/JavaSMTSolver.java | 12 + .../javasmt/JavaSMTTermTransformer.java | 300 ++++++++++-------- .../javasmt/JavaSMTTransformationManager.java | 2 +- .../javasmt/JavaSMTTypeTransformer.java | 14 +- .../xsts/xsts-analysis/build.gradle.kts | 1 + .../bme/mit/theta/xsts/analysis/XstsTest.java | 4 +- 8 files changed, 283 insertions(+), 318 deletions(-) diff --git a/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTDeclTransformer.java b/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTDeclTransformer.java index 27e53ea8ac..ff81f913e6 100644 --- a/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTDeclTransformer.java +++ b/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTDeclTransformer.java @@ -71,12 +71,17 @@ private Formula transformConst(final ConstDecl decl) { .toList(); - if (paramSorts.isEmpty()) { - symbol = context.getFormulaManager().makeVariable(returnSort, symbolNameFor(decl)); - } else { + if (!paramSorts.isEmpty()) { throw new JavaSMTSolverException("Function consts not yet supported."); } + // Enums can't be yet handled by formulamanager directly + if (returnSort.isEnumerationType()) { + symbol = context.getFormulaManager().getEnumerationFormulaManager().makeVariable(symbolNameFor(decl), (FormulaType.EnumerationFormulaType) returnSort); + } else { + symbol = context.getFormulaManager().makeVariable(returnSort, symbolNameFor(decl)); + } + symbolTable.put(decl, symbol); } diff --git a/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTExprTransformer.java b/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTExprTransformer.java index 309976586a..240d5a4e07 100644 --- a/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTExprTransformer.java +++ b/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTExprTransformer.java @@ -31,136 +31,23 @@ 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.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.arraytype.*; +import hu.bme.mit.theta.core.type.booltype.*; +import hu.bme.mit.theta.core.type.bvtype.*; +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.*; 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.type.inttype.*; +import hu.bme.mit.theta.core.type.rattype.*; 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.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.*; 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; @@ -182,6 +69,7 @@ final class JavaSMTExprTransformer { private final FloatingPointFormulaManager floatingPointFormulaManager; private final QuantifiedFormulaManager quantifiedFormulaManager; private final ArrayFormulaManager arrayFormulaManager; + private final EnumerationFormulaManager enumFormulaManager; private final JavaSMTTransformationManager transformer; private final JavaSMTSymbolTable symbolTable; @@ -204,6 +92,7 @@ public JavaSMTExprTransformer(final JavaSMTTransformationManager transformer, fi 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(); @@ -445,6 +334,14 @@ public JavaSMTExprTransformer(final JavaSMTTransformationManager transformer, fi .addCase(Dereference.class, this::transformDereference) + // Enums + + .addCase(EnumLitExpr.class, this::transformEnumLit) + + .addCase(EnumNeqExpr.class, this::transformEnumNeq) + + .addCase(EnumEqExpr.class, this::transformEnumEq) + .build(); } @@ -456,6 +353,32 @@ private static T orElseNull(Supplier supplier) { } } + 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; + }; + } + + private static Tuple2, List>> extractFuncAndArgs(final FuncAppExpr expr) { + final Expr func = expr.getFunc(); + final Expr arg = expr.getParam(); + if (func instanceof FuncAppExpr) { + final FuncAppExpr funcApp = (FuncAppExpr) func; + final Tuple2, List>> funcAndArgs = extractFuncAndArgs(funcApp); + final Expr resFunc = funcAndArgs.get1(); + final List> args = funcAndArgs.get2(); + final List> resArgs = ImmutableList.>builder().addAll(args).add(arg) + .build(); + return Tuple2.of(resFunc, resArgs); + } else { + return Tuple2.of(func, ImmutableList.of(arg)); + } + } + //// /* @@ -557,6 +480,10 @@ private Formula transformForall(final ForallExpr expr) { return result; } + /* + * Rationals + */ + private List transformParamDecls(final List> paramDecls) { final List paramTerms = new ArrayList<>(paramDecls.size()); for (final ParamDecl paramDecl : paramDecls) { @@ -577,10 +504,6 @@ private Formula transformParamDecl(final ParamDecl paramDecl) { } } - /* - * Rationals - */ - private Formula transformRatLit(final RatLitExpr expr) { var num = rationalFormulaManager.makeNumber(expr.getNum().toString()); var denom = rationalFormulaManager.makeNumber(expr.getDenom().toString()); @@ -654,6 +577,10 @@ private Formula transformRatGt(final RatGtExpr expr) { return rationalFormulaManager.greaterThan(leftOpTerm, rightOpTerm); } + /* + * Integers + */ + private Formula transformRatLeq(final RatLeqExpr expr) { final RationalFormula leftOpTerm = (RationalFormula) toTerm( expr.getLeftOp()); @@ -670,10 +597,6 @@ private Formula transformRatLt(final RatLtExpr expr) { return rationalFormulaManager.lessThan(leftOpTerm, rightOpTerm); } - /* - * Integers - */ - private Formula transformRatToInt(final RatToIntExpr expr) { return rationalFormulaManager.floor((NumeralFormula) toTerm(expr.getOp())); } @@ -777,6 +700,10 @@ private Formula transformIntLeq(final IntLeqExpr expr) { return integerFormulaManager.lessOrEquals(leftOpTerm, rightOpTerm); } + /* + * Bitvectors + */ + private Formula transformIntLt(final IntLtExpr expr) { final IntegerFormula leftOpTerm = (IntegerFormula) toTerm( expr.getLeftOp()); @@ -789,10 +716,6 @@ private Formula transformIntToRat(final IntToRatExpr expr) { return rationalFormulaManager.sum(List.of((IntegerFormula) toTerm(expr.getOp()))); } - /* - * Bitvectors - */ - private Formula transformBvLit(final BvLitExpr expr) { return bitvectorFormulaManager.makeBitvector( expr.getType().getSize(), @@ -1018,6 +941,10 @@ private Formula transformBvSGt(final BvSGtExpr expr) { 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()); @@ -1032,11 +959,6 @@ private Formula transformBvSLt(final BvSLtExpr expr) { return bitvectorFormulaManager.lessThan(leftOpTerm, rightOpTerm, true); } - /* - * Floating points - */ - - private Formula transformFpLit(final FpLitExpr expr) { return floatingPointFormulaManager.makeNumber( BvUtils.neutralBvLitExprToBigInteger(expr.getExponent()), @@ -1190,6 +1112,9 @@ private Formula transformFpFromBv(final FpFromBvExpr expr) { 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()); @@ -1198,19 +1123,6 @@ private Formula transformFpToBv(final FpToBvExpr expr) { return floatingPointFormulaManager.castTo(op, expr.getSgn(), FormulaType.getBitvectorTypeWithSize(expr.getSize()), roundingMode); } - 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; - }; - } - /* - * Arrays - */ - private Formula transformFpToFp(final FpToFpExpr expr) { final FloatingPointFormula op = (FloatingPointFormula) toTerm(expr.getOp()); @@ -1264,6 +1176,11 @@ private Formula transformArrayLit(final 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()); @@ -1280,11 +1197,6 @@ private Formula transformArrayInit(fina return arr; } - - /* - * Functions - */ - private Formula transformFuncApp(final FuncAppExpr expr) { final Tuple2, List>> funcAndArgs = extractFuncAndArgs(expr); final Expr func = funcAndArgs.get1(); @@ -1333,22 +1245,21 @@ private Formula transformDereference(final Dereference expr) { return func; } - private static Tuple2, List>> extractFuncAndArgs(final FuncAppExpr expr) { - final Expr func = expr.getFunc(); - final Expr arg = expr.getParam(); - if (func instanceof FuncAppExpr) { - final FuncAppExpr funcApp = (FuncAppExpr) func; - final Tuple2, List>> funcAndArgs = extractFuncAndArgs(funcApp); - final Expr resFunc = funcAndArgs.get1(); - final List> args = funcAndArgs.get2(); - final List> resArgs = ImmutableList.>builder().addAll(args).add(arg) - .build(); - return Tuple2.of(resFunc, resArgs); - } else { - return Tuple2.of(func, ImmutableList.of(arg)); - } + // 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(); } diff --git a/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTSolver.java b/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTSolver.java index a3d7a05cd0..dd1632768e 100644 --- a/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTSolver.java +++ b/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTSolver.java @@ -27,6 +27,8 @@ 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; @@ -287,6 +289,8 @@ private LitExpr extractLiteral(final ConstDecl extractBvConstLiteral(final Formula formula) { } } + private EnumLitExpr 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) { diff --git a/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTTermTransformer.java b/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTTermTransformer.java index c14d63856c..ae859fc10d 100644 --- a/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTTermTransformer.java +++ b/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTTermTransformer.java @@ -30,63 +30,38 @@ import hu.bme.mit.theta.core.type.arraytype.ArrayLitExpr; 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.BvExtractExpr; -import hu.bme.mit.theta.core.type.bvtype.BvLitExpr; -import hu.bme.mit.theta.core.type.bvtype.BvSExtExpr; -import hu.bme.mit.theta.core.type.bvtype.BvType; -import hu.bme.mit.theta.core.type.bvtype.BvZExtExpr; -import hu.bme.mit.theta.core.type.fptype.FpFromBvExpr; -import hu.bme.mit.theta.core.type.fptype.FpLitExpr; -import hu.bme.mit.theta.core.type.fptype.FpRoundingMode; -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.fptype.FpType; +import hu.bme.mit.theta.core.type.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.fptype.*; import hu.bme.mit.theta.core.type.functype.FuncExprs; import hu.bme.mit.theta.core.type.functype.FuncType; import hu.bme.mit.theta.core.type.inttype.IntLitExpr; import hu.bme.mit.theta.core.utils.BvUtils; import hu.bme.mit.theta.core.utils.TypeUtils; import org.sosy_lab.common.rationals.Rational; -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.FloatingPointNumber; -import org.sosy_lab.java_smt.api.Formula; -import org.sosy_lab.java_smt.api.FormulaType; +import org.sosy_lab.java_smt.api.*; import org.sosy_lab.java_smt.api.FormulaType.ArrayFormulaType; import org.sosy_lab.java_smt.api.FormulaType.BitvectorType; import org.sosy_lab.java_smt.api.FormulaType.FloatingPointType; -import org.sosy_lab.java_smt.api.FunctionDeclaration; -import org.sosy_lab.java_smt.api.Model; import org.sosy_lab.java_smt.api.QuantifiedFormulaManager.Quantifier; -import org.sosy_lab.java_smt.api.SolverContext; import org.sosy_lab.java_smt.api.visitors.FormulaVisitor; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.function.BiFunction; -import java.util.function.BinaryOperator; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.function.UnaryOperator; +import java.util.function.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Preconditions.*; import static com.google.common.collect.ImmutableList.toImmutableList; import static hu.bme.mit.theta.core.decl.Decls.Const; import static hu.bme.mit.theta.core.decl.Decls.Param; import static hu.bme.mit.theta.core.type.abstracttype.AbstractExprs.Eq; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Bool; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Exists; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.False; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.Forall; -import static hu.bme.mit.theta.core.type.booltype.BoolExprs.True; +import static hu.bme.mit.theta.core.type.booltype.BoolExprs.*; import static hu.bme.mit.theta.core.type.fptype.FpExprs.FpAssign; import static hu.bme.mit.theta.core.type.inttype.IntExprs.Int; import static hu.bme.mit.theta.core.type.rattype.RatExprs.Rat; @@ -97,118 +72,121 @@ final class JavaSMTTermTransformer { private final JavaSMTSymbolTable symbolTable; private final SolverContext context; - private final Map, QuadFunction, Model, List>, Expr>> environment; + private final Map, QuadFunction, Model, List>, Expr>> environment; + private final Map, QuadFunction, Model, List>, Expr>> otherFuncs; public JavaSMTTermTransformer(final JavaSMTSymbolTable symbolTable, SolverContext context) { this.symbolTable = symbolTable; this.context = context; environment = Containers.createMap(); - addFunc("and", exprMultiaryOperator(hu.bme.mit.theta.core.type.booltype.AndExpr::create)); - addFunc("false", exprNullaryOperator(hu.bme.mit.theta.core.type.booltype.FalseExpr::getInstance)); - addFunc("true", exprNullaryOperator(hu.bme.mit.theta.core.type.booltype.TrueExpr::getInstance)); - addFunc("iff", exprBinaryOperator(hu.bme.mit.theta.core.type.booltype.IffExpr::create)); - addFunc("not", exprUnaryOperator(hu.bme.mit.theta.core.type.booltype.NotExpr::create)); - addFunc("=>", exprBinaryOperator(hu.bme.mit.theta.core.type.booltype.ImplyExpr::create)); - addFunc("xor", exprBinaryOperator(hu.bme.mit.theta.core.type.booltype.XorExpr::create)); - addFunc("or", exprMultiaryOperator(hu.bme.mit.theta.core.type.booltype.OrExpr::create)); - addFunc("ite", exprTernaryOperator(hu.bme.mit.theta.core.type.anytype.IteExpr::create)); - addFunc("if", exprTernaryOperator(hu.bme.mit.theta.core.type.anytype.IteExpr::create)); - addFunc("prime", exprUnaryOperator(hu.bme.mit.theta.core.type.anytype.PrimeExpr::of)); - addFunc("=", exprBinaryOperator((expr, expr2) -> expr.getType() instanceof FpType ? FpAssign((Expr) expr, (Expr) expr2) : Eq(expr, expr2))); - addFunc(">=", exprBinaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Geq)); - addFunc(">", exprBinaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Gt)); - addFunc("<=", exprBinaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Leq)); - addFunc("<", exprBinaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Lt)); - addFunc("+", exprBinaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Add)); - addFunc("-", exprBinaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Sub)); - addFunc("+", exprUnaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Pos)); - addFunc("-", exprUnaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Neg)); - addFunc("*", exprBinaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Mul)); - addFunc("/", exprBinaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Div)); - addFunc("to_int", exprUnaryOperator(hu.bme.mit.theta.core.type.rattype.RatToIntExpr::create)); - addFunc("div", exprBinaryOperator(hu.bme.mit.theta.core.type.inttype.IntDivExpr::create)); - addFunc("to_rat", exprUnaryOperator(hu.bme.mit.theta.core.type.inttype.IntToRatExpr::create)); - addFunc("mod", exprBinaryOperator(hu.bme.mit.theta.core.type.inttype.IntModExpr::create)); - addFunc("rem", exprBinaryOperator(hu.bme.mit.theta.core.type.inttype.IntRemExpr::create)); - addFunc("fp.add", exprFpMultiaryOperator(hu.bme.mit.theta.core.type.fptype.FpAddExpr::create)); - addFunc("fp.sub", exprFpBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpSubExpr::create)); - addFunc("fp.pos", exprUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpPosExpr::create)); - addFunc("fp.neg", exprUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpNegExpr::create)); - addFunc("fp.mul", exprFpMultiaryOperator(hu.bme.mit.theta.core.type.fptype.FpMulExpr::create)); - addFunc("fp.div", exprFpBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpDivExpr::create)); - addFunc("fp.rem", exprBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpRemExpr::create)); - addFunc("fprem", exprBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpRemExpr::create)); - addFunc("fp.abs", exprUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpAbsExpr::create)); - addFunc("fp.leq", exprBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpLeqExpr::create)); - addFunc("fp.lt", exprBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpLtExpr::create)); - addFunc("fp.geq", exprBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpGeqExpr::create)); - addFunc("fp.gt", exprBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpGtExpr::create)); - addFunc("fp.eq", exprBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpEqExpr::create)); - addFunc("fp.isnan", exprUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpIsNanExpr::create)); - addFunc("fp.isNaN", exprUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpIsNanExpr::create)); - addFunc("isinfinite", exprUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpIsInfiniteExpr::create)); - addFunc("fp.isInfinite", exprUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpIsInfiniteExpr::create)); - addFunc("fp.roundtoint", exprFpUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpRoundToIntegralExpr::create)); - addFunc("fp.roundToIntegral", exprFpUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpRoundToIntegralExpr::create)); - addFunc("fp.sqrt", exprFpUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpSqrtExpr::create)); - addFunc("fp.max", exprBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpMaxExpr::create)); - addFunc("fp.min", exprBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpMinExpr::create)); - addFunc("++", exprMultiaryOperator(hu.bme.mit.theta.core.type.bvtype.BvConcatExpr::create)); - addFunc("concat", exprMultiaryOperator(hu.bme.mit.theta.core.type.bvtype.BvConcatExpr::create)); - addFunc("bvadd", exprMultiaryOperator(hu.bme.mit.theta.core.type.bvtype.BvAddExpr::create)); - addFunc("bvsub", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvSubExpr::create)); - addFunc("bvpos", exprUnaryOperator(hu.bme.mit.theta.core.type.bvtype.BvPosExpr::create)); - addFunc("bvneg", exprUnaryOperator(hu.bme.mit.theta.core.type.bvtype.BvNegExpr::create)); - addFunc("bvmul", exprMultiaryOperator(hu.bme.mit.theta.core.type.bvtype.BvMulExpr::create)); - addFunc("bvudiv", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvUDivExpr::create)); - addFunc("bvsdiv", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvSDivExpr::create)); - addFunc("bvsmod", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvSModExpr::create)); - addFunc("bvurem", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvURemExpr::create)); - addFunc("bvsrem", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvSRemExpr::create)); - addFunc("bvor", exprMultiaryOperator(hu.bme.mit.theta.core.type.bvtype.BvOrExpr::create)); - addFunc("bvand", exprMultiaryOperator(hu.bme.mit.theta.core.type.bvtype.BvAndExpr::create)); - addFunc("bvxor", exprMultiaryOperator(hu.bme.mit.theta.core.type.bvtype.BvXorExpr::create)); - addFunc("bvnot", exprUnaryOperator(hu.bme.mit.theta.core.type.bvtype.BvNotExpr::create)); - addFunc("bvshl", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvShiftLeftExpr::create)); - addFunc("bvashr", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvArithShiftRightExpr::create)); - addFunc("bvlshr", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvLogicShiftRightExpr::create)); - addFunc("bvrol", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvRotateLeftExpr::create)); - addFunc("ext_rotate_left", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvRotateLeftExpr::create)); - addFunc("bvror", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvRotateRightExpr::create)); - addFunc("ext_rotate_right", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvRotateRightExpr::create)); - addFunc("bvult", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvULtExpr::create)); - addFunc("bvule", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvULeqExpr::create)); - addFunc("bvugt", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvUGtExpr::create)); - addFunc("bvuge", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvUGeqExpr::create)); - addFunc("bvslt", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvSLtExpr::create)); - addFunc("bvsle", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvSLeqExpr::create)); - addFunc("bvsgt", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvSGtExpr::create)); - addFunc("bvsge", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvSGeqExpr::create)); - addFunc("read", exprBinaryOperator(hu.bme.mit.theta.core.type.arraytype.ArrayReadExpr::create)); - addFunc("write", exprTernaryOperator(hu.bme.mit.theta.core.type.arraytype.ArrayWriteExpr::create)); - addFunc("select", exprBinaryOperator(hu.bme.mit.theta.core.type.arraytype.ArrayReadExpr::create)); - addFunc("store", exprTernaryOperator(hu.bme.mit.theta.core.type.arraytype.ArrayWriteExpr::create)); - - environment.put(Tuple2.of("fp.frombv", 1), (term, args, model, vars) -> { + otherFuncs = Containers.createMap(); + addEnvFunc(FunctionDeclarationKind.AND, exprMultiaryOperator(hu.bme.mit.theta.core.type.booltype.AndExpr::create)); +// addEnvFunc("false", exprNullaryOperator(hu.bme.mit.theta.core.type.booltype.FalseExpr::getInstance)); +// addEnvFunc("true", exprNullaryOperator(hu.bme.mit.theta.core.type.booltype.TrueExpr::getInstance)); + addEnvFunc(FunctionDeclarationKind.IFF, exprBinaryOperator(hu.bme.mit.theta.core.type.booltype.IffExpr::create)); + addEnvFunc(FunctionDeclarationKind.NOT, exprUnaryOperator(hu.bme.mit.theta.core.type.booltype.NotExpr::create)); + addEnvFunc(FunctionDeclarationKind.IMPLIES, exprBinaryOperator(hu.bme.mit.theta.core.type.booltype.ImplyExpr::create)); + addEnvFunc(FunctionDeclarationKind.XOR, exprBinaryOperator(hu.bme.mit.theta.core.type.booltype.XorExpr::create)); + addEnvFunc(FunctionDeclarationKind.OR, exprMultiaryOperator(hu.bme.mit.theta.core.type.booltype.OrExpr::create)); + addEnvFunc(FunctionDeclarationKind.ITE, exprTernaryOperator(hu.bme.mit.theta.core.type.anytype.IteExpr::create)); +// addEnvFunc("if", exprTernaryOperator(hu.bme.mit.theta.core.type.anytype.IteExpr::create)); +// addEnvFunc("prime", exprUnaryOperator(hu.bme.mit.theta.core.type.anytype.PrimeExpr::of)); + addEnvFunc(FunctionDeclarationKind.EQ, exprBinaryOperator((expr, expr2) -> expr.getType() instanceof FpType ? FpAssign((Expr) expr, (Expr) expr2) : Eq(expr, expr2))); + addEnvFunc(FunctionDeclarationKind.GTE, exprBinaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Geq)); + addEnvFunc(FunctionDeclarationKind.GT, exprBinaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Gt)); + addEnvFunc(FunctionDeclarationKind.LTE, exprBinaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Leq)); + addEnvFunc(FunctionDeclarationKind.LT, exprBinaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Lt)); + addEnvFunc(FunctionDeclarationKind.ADD, exprBinaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Add)); + addEnvFunc(FunctionDeclarationKind.SUB, exprBinaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Sub)); + addEnvFunc(FunctionDeclarationKind.ADD, exprUnaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Pos)); + addEnvFunc(FunctionDeclarationKind.UMINUS, exprUnaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Neg)); + addEnvFunc(FunctionDeclarationKind.MUL, exprBinaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Mul)); + addEnvFunc(FunctionDeclarationKind.DIV, exprBinaryOperator(hu.bme.mit.theta.core.type.abstracttype.AbstractExprs::Div)); + addEnvFunc(FunctionDeclarationKind.FLOOR, exprUnaryOperator(hu.bme.mit.theta.core.type.rattype.RatToIntExpr::create)); + addEnvFunc(FunctionDeclarationKind.FP_ROUND_TO_INTEGRAL, exprUnaryOperator(hu.bme.mit.theta.core.type.rattype.RatToIntExpr::create)); +// addEnvFunc("div", exprBinaryOperator(hu.bme.mit.theta.core.type.inttype.IntDivExpr::create)); + addEnvFunc(FunctionDeclarationKind.TO_REAL, exprUnaryOperator(hu.bme.mit.theta.core.type.inttype.IntToRatExpr::create)); + addEnvFunc(FunctionDeclarationKind.MODULO, exprBinaryOperator(hu.bme.mit.theta.core.type.inttype.IntModExpr::create)); +// addEnvFunc("rem", exprBinaryOperator(hu.bme.mit.theta.core.type.inttype.IntRemExpr::create)); + addEnvFunc(FunctionDeclarationKind.FP_ADD, exprFpMultiaryOperator(hu.bme.mit.theta.core.type.fptype.FpAddExpr::create)); + addEnvFunc(FunctionDeclarationKind.FP_SUB, exprFpBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpSubExpr::create)); +// addEnvFunc("fp.pos", exprUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpPosExpr::create)); + addEnvFunc(FunctionDeclarationKind.FP_NEG, exprUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpNegExpr::create)); + addEnvFunc(FunctionDeclarationKind.FP_MUL, exprFpMultiaryOperator(hu.bme.mit.theta.core.type.fptype.FpMulExpr::create)); + addEnvFunc(FunctionDeclarationKind.FP_DIV, exprFpBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpDivExpr::create)); + addOtherFunc("fp.rem", exprBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpRemExpr::create)); + addOtherFunc("fprem", exprBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpRemExpr::create)); + addEnvFunc(FunctionDeclarationKind.FP_ABS, exprUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpAbsExpr::create)); + addEnvFunc(FunctionDeclarationKind.FP_LE, exprBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpLeqExpr::create)); + addEnvFunc(FunctionDeclarationKind.FP_LT, exprBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpLtExpr::create)); + addEnvFunc(FunctionDeclarationKind.FP_GE, exprBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpGeqExpr::create)); + addEnvFunc(FunctionDeclarationKind.FP_GT, exprBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpGtExpr::create)); + addEnvFunc(FunctionDeclarationKind.FP_EQ, exprBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpEqExpr::create)); + addEnvFunc(FunctionDeclarationKind.FP_IS_NAN, exprUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpIsNanExpr::create)); +// addEnvFunc("fp.isNaN", exprUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpIsNanExpr::create)); + addEnvFunc(FunctionDeclarationKind.FP_IS_INF, exprUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpIsInfiniteExpr::create)); +// addEnvFunc("fp.isInfinite", exprUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpIsInfiniteExpr::create)); + addEnvFunc(FunctionDeclarationKind.FP_ROUND_TO_INTEGRAL, exprFpUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpRoundToIntegralExpr::create)); +// addEnvFunc("fp.roundToIntegral", exprFpUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpRoundToIntegralExpr::create)); + addEnvFunc(FunctionDeclarationKind.FP_SQRT, exprFpUnaryOperator(hu.bme.mit.theta.core.type.fptype.FpSqrtExpr::create)); + addEnvFunc(FunctionDeclarationKind.FP_MAX, exprBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpMaxExpr::create)); + addEnvFunc(FunctionDeclarationKind.FP_MIN, exprBinaryOperator(hu.bme.mit.theta.core.type.fptype.FpMinExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_CONCAT, exprMultiaryOperator(hu.bme.mit.theta.core.type.bvtype.BvConcatExpr::create)); +// addEnvFunc("concat", exprMultiaryOperator(hu.bme.mit.theta.core.type.bvtype.BvConcatExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_ADD, exprMultiaryOperator(hu.bme.mit.theta.core.type.bvtype.BvAddExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_SUB, exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvSubExpr::create)); +// addEnvFunc("bvpos", exprUnaryOperator(hu.bme.mit.theta.core.type.bvtype.BvPosExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_NEG, exprUnaryOperator(hu.bme.mit.theta.core.type.bvtype.BvNegExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_MUL, exprMultiaryOperator(hu.bme.mit.theta.core.type.bvtype.BvMulExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_UDIV, exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvUDivExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_SDIV, exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvSDivExpr::create)); + addOtherFunc("bvsmod", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvSModExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_UREM, exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvURemExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_SREM, exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvSRemExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_OR, exprMultiaryOperator(hu.bme.mit.theta.core.type.bvtype.BvOrExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_AND, exprMultiaryOperator(hu.bme.mit.theta.core.type.bvtype.BvAndExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_XOR, exprMultiaryOperator(hu.bme.mit.theta.core.type.bvtype.BvXorExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_NOT, exprUnaryOperator(hu.bme.mit.theta.core.type.bvtype.BvNotExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_SHL, exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvShiftLeftExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_ASHR, exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvArithShiftRightExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_LSHR, exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvLogicShiftRightExpr::create)); +// addEnvFunc("bvrol", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvRotateLeftExpr::create)); + addOtherFunc("ext_rotate_left", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvRotateLeftExpr::create)); +// addEnvFunc("bvror", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvRotateRightExpr::create)); + addOtherFunc("ext_rotate_right", exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvRotateRightExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_ULT, exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvULtExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_ULE, exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvULeqExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_UGT, exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvUGtExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_UGE, exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvUGeqExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_SLT, exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvSLtExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_SLE, exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvSLeqExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_SGT, exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvSGtExpr::create)); + addEnvFunc(FunctionDeclarationKind.BV_SGE, exprBinaryOperator(hu.bme.mit.theta.core.type.bvtype.BvSGeqExpr::create)); +// addEnvFunc("read", exprBinaryOperator(hu.bme.mit.theta.core.type.arraytype.ArrayReadExpr::create)); +// addEnvFunc("write", exprTernaryOperator(hu.bme.mit.theta.core.type.arraytype.ArrayWriteExpr::create)); + addEnvFunc(FunctionDeclarationKind.SELECT, exprBinaryOperator(hu.bme.mit.theta.core.type.arraytype.ArrayReadExpr::create)); + addEnvFunc(FunctionDeclarationKind.STORE, exprTernaryOperator(hu.bme.mit.theta.core.type.arraytype.ArrayWriteExpr::create)); + + environment.put(Tuple2.of(FunctionDeclarationKind.FP_FROM_IEEEBV, 1), (term, args, model, vars) -> { FloatingPointType type = (FloatingPointType) context.getFormulaManager().getFormulaType((FloatingPointFormula) term); final var roundingmode = getRoundingMode(args.get(0).toString()); final Expr op = (Expr) transform(args.get(1), model, vars); return FpFromBvExpr.of(roundingmode, op, FpType.of(type.getExponentSize(), type.getMantissaSize() + 1), true); }); - environment.put(Tuple2.of("fp.to_sbv", 2), (term, args, model, vars) -> { + environment.put(Tuple2.of(FunctionDeclarationKind.FP_CASTTO_SBV, 2), (term, args, model, vars) -> { BitvectorType type = (BitvectorType) context.getFormulaManager().getFormulaType((BitvectorFormula) term); final var roundingmode = getRoundingMode(args.get(0).toString()); final Expr op = (Expr) transform(args.get(1), model, vars); return FpToBvExpr.of(roundingmode, op, type.getSize(), true); }); - environment.put(Tuple2.of("fp.to_ubv", 2), (term, args, model, vars) -> { + environment.put(Tuple2.of(FunctionDeclarationKind.FP_CASTTO_UBV, 2), (term, args, model, vars) -> { BitvectorType type = (BitvectorType) context.getFormulaManager().getFormulaType((BitvectorFormula) term); final var roundingmode = getRoundingMode(args.get(0).toString()); final Expr op = (Expr) transform(args.get(1), model, vars); return FpToBvExpr.of(roundingmode, op, type.getSize(), false); }); - environment.put(Tuple2.of("to_fp", 2), (term, args, model, vars) -> { + environment.put(Tuple2.of(FunctionDeclarationKind.BV_SCASTTO_FP, 2), (term, args, model, vars) -> { FloatingPointType type = (FloatingPointType) context.getFormulaManager().getFormulaType((FloatingPointFormula) term); final var roundingmode = getRoundingMode(args.get(0).toString()); final Expr op = transform(args.get(1), model, vars); @@ -220,13 +198,25 @@ public JavaSMTTermTransformer(final JavaSMTSymbolTable symbolTable, SolverContex throw new JavaSMTSolverException("Unsupported:" + op.getType()); } }); - environment.put(Tuple2.of("to_fp", 1), (term, args, model, vars) -> { + environment.put(Tuple2.of(FunctionDeclarationKind.FP_CASTTO_FP, 2), (term, args, model, vars) -> { + FloatingPointType type = (FloatingPointType) context.getFormulaManager().getFormulaType((FloatingPointFormula) term); + final var roundingmode = getRoundingMode(args.get(0).toString()); + final Expr op = transform(args.get(1), model, vars); + if (op.getType() instanceof FpType) { + return FpToFpExpr.of(roundingmode, (Expr) op, type.getExponentSize(), type.getMantissaSize() + 1); + } else if (op.getType() instanceof BvType) { + return FpFromBvExpr.of(roundingmode, (Expr) op, FpType.of(type.getExponentSize(), type.getMantissaSize() + 1), false); + } else { + throw new JavaSMTSolverException("Unsupported:" + op.getType()); + } + }); + otherFuncs.put(Tuple2.of("to_fp", 1), (term, args, model, vars) -> { FloatingPointType type = (FloatingPointType) context.getFormulaManager().getFormulaType((FloatingPointFormula) term); final Expr op = (Expr) transform(args.get(0), model, vars); return FpFromBvExpr.of(FpRoundingMode.getDefaultRoundingMode(), op, FpType.of(type.getExponentSize(), type.getMantissaSize() + 1), true); }); - environment.put(Tuple2.of("extract", 1), (term, args, model, vars) -> { + environment.put(Tuple2.of(FunctionDeclarationKind.BV_EXTRACT, 1), (term, args, model, vars) -> { final Pattern pattern = Pattern.compile("extract ([0-9]+) ([0-9]+)"); final String termStr = term.toString(); final Matcher match = pattern.matcher(termStr); @@ -238,34 +228,37 @@ public JavaSMTTermTransformer(final JavaSMTSymbolTable symbolTable, SolverContex } throw new JavaSMTSolverException("Not supported: " + term); }); - environment.put(Tuple2.of("zero_extend", 1), (term, args, model, vars) -> { + environment.put(Tuple2.of(FunctionDeclarationKind.BV_ZERO_EXTENSION, 1), (term, args, model, vars) -> { BitvectorType type = (BitvectorType) context.getFormulaManager().getFormulaType((BitvectorFormula) term); final Expr op = (Expr) transform(args.get(0), model, vars); return BvZExtExpr.of(op, BvType.of(type.getSize())); }); - environment.put(Tuple2.of("sign_extend", 1), (term, args, model, vars) -> { + environment.put(Tuple2.of(FunctionDeclarationKind.BV_SIGN_EXTENSION, 1), (term, args, model, vars) -> { BitvectorType type = (BitvectorType) context.getFormulaManager().getFormulaType((BitvectorFormula) term); final Expr op = (Expr) transform(args.get(0), model, vars); return BvSExtExpr.of(op, BvType.of(type.getSize())); }); - environment.put(Tuple2.of("EqZero", 1), (term, args, model, vars) -> { + environment.put(Tuple2.of(FunctionDeclarationKind.EQ_ZERO, 1), (term, args, model, vars) -> { final Expr op = transform(args.get(0), model, vars); return Eq(op, TypeUtils.getDefaultValue(op.getType())); }); - environment.put(Tuple2.of("fp", 3), (term, args, model, vars) -> { + otherFuncs.put(Tuple2.of("const", 1), (term, args, model, vars) -> transformLit(term, transform(args.get(0), model, vars))); + otherFuncs.put(Tuple2.of("fp", 3), (term, args, model, vars) -> { final Expr op1 = (Expr) transform(args.get(0), model, vars); final Expr op2 = (Expr) transform(args.get(1), model, vars); final Expr op3 = (Expr) transform(args.get(2), model, vars); return FpLitExpr.of((BvLitExpr) op1, (BvLitExpr) op2, (BvLitExpr) op3); }); - environment.put(Tuple2.of("const", 1), (term, args, model, vars) -> { - return transformLit(term, transform(args.get(0), model, vars)); - }); } - private void addFunc(String name, Tuple2, Model, List>, Expr>> func) { - checkArgument(!environment.containsKey(Tuple2.of(name, func.get1())), "Duplicate key: " + Tuple2.of(name, func.get1())); - environment.put(Tuple2.of(name, func.get1()), func.get2()); + private void addEnvFunc(FunctionDeclarationKind declarationKind, Tuple2, Model, List>, Expr>> func) { + checkArgument(!environment.containsKey(Tuple2.of(declarationKind, func.get1())), "Duplicate key: " + Tuple2.of(declarationKind, func.get1())); + environment.put(Tuple2.of(declarationKind, func.get1()), func.get2()); + } + + private void addOtherFunc(String name, Tuple2, Model, List>, Expr>> func) { + checkArgument(!otherFuncs.containsKey(Tuple2.of(name, func.get1())), "Duplicate key: " + Tuple2.of(name, func.get1())); + otherFuncs.put(Tuple2.of(name, func.get1()), func.get2()); } public Expr toExpr(final Formula term) { @@ -278,7 +271,7 @@ private Expr transform(final Formula term, final Model model, final List> vars) { try { - return context.getFormulaManager().visit(term, new FormulaVisitor>() { + return context.getFormulaManager().visit(term, new FormulaVisitor<>() { @Override public Expr visitFreeVariable(Formula f, String name) { return transformVar(f, name, vars); @@ -382,12 +375,18 @@ private Expr transformApp(Formula f, final FunctionDeclaration funcDecl, final Model model, final List> vars) { - final var key1 = Tuple2.of(funcDecl.getName(), args.size()); - final var key2 = Tuple2.of(funcDecl.getName(), -1); + final var key1 = Tuple2.of(funcDecl.getKind(), args.size()); + final var key2 = Tuple2.of(funcDecl.getKind(), -1); + final var key3 = Tuple2.of(funcDecl.getName(), args.size()); + final var key4 = Tuple2.of(funcDecl.getName(), -1); if (environment.containsKey(key1)) { return environment.get(key1).apply(f, args, model, vars); } else if (environment.containsKey(key2)) { return environment.get(key2).apply(f, args, model, vars); + } else if (otherFuncs.containsKey(key3)) { + return otherFuncs.get(key3).apply(f, args, model, vars); + } else if (otherFuncs.containsKey(key4)) { + return otherFuncs.get(key4).apply(f, args, model, vars); } else { final var paramExprs = args.stream().map((Formula term) -> (Expr) toExpr(term)).toList(); @@ -477,6 +476,8 @@ private Type transformType(FormulaType type) { return ArrayType.of(transformType(indexType), transformType(elemType)); } else if (type.isBooleanType()) { return Bool(); + } else if (type.isEnumerationType()) { + return null; } throw new JavaSMTSolverException("Type not supported: " + type); } @@ -504,12 +505,33 @@ private Tuple2, Model, List final BinaryOperator> function) { return Tuple2.of(2, (term, args, model, vars) -> { checkArgument(args.size() == 2, "Number of arguments must be two"); + if (context.getFormulaManager().getFormulaType(args.get(0)).isEnumerationType()) { + // binary operator is on enum types + // if either arg is a literal, we need special handling to get its type + int litIndex = -1; + for (int i = 0; i < 2; i++) { + if (context.getFormulaManager().extractVariables(args.get(i)).isEmpty()) { + litIndex = i; + } + } + if (litIndex > -1) { + // one is a literal + int refIndex = Math.abs(litIndex - 1); + final Expr refOp = transform(args.get(refIndex), model, vars); + final Expr litExpr = transformEnumLit(args.get(litIndex), (EnumType) refOp.getType()); + return function.apply(refOp, litExpr); + } + } final Expr op1 = transform(args.get(0), model, vars); final Expr op2 = transform(args.get(1), model, vars); return function.apply(op1, op2); }); } + private Expr transformEnumLit(Formula formula, EnumType type) { + return EnumLitExpr.of(type, EnumType.getShortName(formula.toString())); + } + private Tuple2, Model, List>, Expr>> exprTernaryOperator( final TernaryOperator> function) { return Tuple2.of(3, (term, args, model, vars) -> { diff --git a/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTTransformationManager.java b/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTTransformationManager.java index 4ea1d6dda3..0b3f45224f 100644 --- a/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTTransformationManager.java +++ b/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTTransformationManager.java @@ -29,7 +29,7 @@ final class JavaSMTTransformationManager { private final JavaSMTExprTransformer exprTransformer; public JavaSMTTransformationManager(final JavaSMTSymbolTable symbolTable, final SolverContext context) { - this.typeTransformer = new JavaSMTTypeTransformer(); + this.typeTransformer = new JavaSMTTypeTransformer(context); this.declTransformer = new JavaSMTDeclTransformer(this, symbolTable, context); this.exprTransformer = new JavaSMTExprTransformer(this, symbolTable, context); } diff --git a/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTTypeTransformer.java b/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTTypeTransformer.java index cf6d051354..8f994c4ca0 100644 --- a/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTTypeTransformer.java +++ b/subprojects/solver/solver-javasmt/src/main/java/hu/bme/mit/theta/solver/javasmt/JavaSMTTypeTransformer.java @@ -19,24 +19,34 @@ 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.BvType; +import hu.bme.mit.theta.core.type.enumtype.EnumType; import hu.bme.mit.theta.core.type.fptype.FpType; import hu.bme.mit.theta.core.type.inttype.IntType; import hu.bme.mit.theta.core.type.rattype.RatType; import org.sosy_lab.java_smt.api.BooleanFormula; +import org.sosy_lab.java_smt.api.EnumerationFormula; import org.sosy_lab.java_smt.api.FormulaType; 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.SolverContext; + +import java.util.HashMap; +import java.util.Map; final class JavaSMTTypeTransformer { + private final SolverContext solverContext; private final FormulaType boolSort; private final FormulaType intSort; private final FormulaType realSort; + private final Map> enumSorts; - JavaSMTTypeTransformer() { + JavaSMTTypeTransformer(final SolverContext solverContext) { + this.solverContext = solverContext; boolSort = FormulaType.BooleanType; intSort = FormulaType.IntegerType; realSort = FormulaType.RationalType; + enumSorts = new HashMap<>(); } public FormulaType toSort(final Type type) { @@ -46,6 +56,8 @@ public FormulaType toSort(final Type type) { return intSort; } else if (type instanceof RatType) { return realSort; + } else if (type instanceof EnumType enumType) { + return enumSorts.computeIfAbsent(enumType.getName(), name -> solverContext.getFormulaManager().getEnumerationFormulaManager().declareEnumeration(name, enumType.getLongValues())); } else if (type instanceof BvType bvType) { return FormulaType.getBitvectorTypeWithSize(bvType.getSize()); } else if (type instanceof FpType fpType) { diff --git a/subprojects/xsts/xsts-analysis/build.gradle.kts b/subprojects/xsts/xsts-analysis/build.gradle.kts index 4b2513efbf..2f3d02e007 100644 --- a/subprojects/xsts/xsts-analysis/build.gradle.kts +++ b/subprojects/xsts/xsts-analysis/build.gradle.kts @@ -27,4 +27,5 @@ dependencies { testImplementation(project(":theta-solver-z3")) testImplementation(project(":theta-solver-z3-legacy")) testImplementation(project(":theta-solver-smtlib")) + testImplementation(project(":theta-solver-javasmt")) } diff --git a/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsTest.java b/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsTest.java index b527738861..dad84105f5 100644 --- a/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsTest.java +++ b/subprojects/xsts/xsts-analysis/src/test/java/hu/bme/mit/theta/xsts/analysis/XstsTest.java @@ -21,6 +21,7 @@ import hu.bme.mit.theta.common.logging.Logger.Level; import hu.bme.mit.theta.solver.SolverFactory; import hu.bme.mit.theta.solver.SolverManager; +import hu.bme.mit.theta.solver.javasmt.JavaSMTSolverManager; import hu.bme.mit.theta.solver.smtlib.SmtLibSolverManager; import hu.bme.mit.theta.xsts.XSTS; import hu.bme.mit.theta.xsts.analysis.config.XstsConfig; @@ -353,7 +354,7 @@ public static Collection data() { @BeforeClass public static void installSolver() { - if (SOLVER_STRING.contains("Z3")) { + if (SOLVER_STRING.contains("Z3") || SOLVER_STRING.contains("JavaSMT")) { return; } try (final var solverManager = SmtLibSolverManager.create(SMTLIB_HOME, new ConsoleLogger(Level.DETAIL))) { @@ -373,6 +374,7 @@ public void test() throws Exception { SolverManager.registerSolverManager(hu.bme.mit.theta.solver.z3legacy.Z3SolverManager.create()); SolverManager.registerSolverManager(hu.bme.mit.theta.solver.z3.Z3SolverManager.create()); SolverManager.registerSolverManager(SmtLibSolverManager.create(SMTLIB_HOME, logger)); + SolverManager.registerSolverManager(JavaSMTSolverManager.create()); final SolverFactory solverFactory; try { From 285b991abeb47609faec9b9578b5acdb4f9e4476 Mon Sep 17 00:00:00 2001 From: Balazs Robert Rippl Date: Fri, 5 Jul 2024 15:23:08 +0200 Subject: [PATCH 8/8] Fix simplifying of fp NaN literal (non)equalities NaN floating point values should not be equal to any other value. This behavior is correctly implemented in the FpLitExpr #eq and #neq methods. To utilize that, manual comparison in simplification is now swapped to call these methods, resulting in correct behaviour: (= (NaN) (NaN)) for example now simplifies to false. --- .../hu/bme/mit/theta/core/utils/ExprSimplifier.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java index a79d7b109f..cbdee2d98b 100644 --- a/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java +++ b/subprojects/common/core/src/main/java/hu/bme/mit/theta/core/utils/ExprSimplifier.java @@ -71,7 +71,9 @@ public static ExprSimplifier create(final SimplifierLevel level) { @SuppressWarnings("unchecked") public Expr simplify(final Expr expr, final Valuation valuation) { return (Expr) TABLE.dispatch(expr, valuation); - } private final DispatchTable2> TABLE = DispatchTable2.>builder() + } + + private final DispatchTable2> TABLE = DispatchTable2.>builder() // Boolean @@ -1958,8 +1960,8 @@ private Expr simplifyFpEq(final FpEqExpr expr, final Valuation val) { final Expr leftOp = simplify(expr.getLeftOp(), val); final Expr rightOp = simplify(expr.getRightOp(), val); - if (leftOp instanceof FpLitExpr && rightOp instanceof FpLitExpr) { - return Bool(leftOp.equals(rightOp)); + if (leftOp instanceof FpLitExpr lLit && rightOp instanceof FpLitExpr rLit) { + return lLit.eq(rLit); } return expr.with(leftOp, rightOp); @@ -2024,8 +2026,8 @@ private Expr simplifyFpNeq(final FpNeqExpr expr, final Valuation val) final Expr leftOp = simplify(expr.getLeftOp(), val); final Expr rightOp = simplify(expr.getRightOp(), val); - if (leftOp instanceof FpLitExpr && rightOp instanceof FpLitExpr) { - return Bool(!leftOp.equals(rightOp)); + if (leftOp instanceof FpLitExpr lLit && rightOp instanceof FpLitExpr rLit) { + return lLit.neq(rLit); } else if (leftOp instanceof RefExpr && rightOp instanceof RefExpr) { if (level != LITERAL_ONLY && leftOp.equals(rightOp)) { return False();