diff --git a/README.md b/README.md index d9fb8fc22..cefc4deb7 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Get the most out of SMT solving with KSMT features: * Streamlined [solver delivery](#ksmt-distribution) with no need for building a solver or implementing JVM bindings [![KSMT: build](https://github.com/UnitTestBot/ksmt/actions/workflows/build-and-run-tests.yml/badge.svg)](https://github.com/UnitTestBot/ksmt/actions/workflows/build-and-run-tests.yml) -[![Maven Central](https://img.shields.io/maven-central/v/io.ksmt/ksmt-core)](https://central.sonatype.com/artifact/io.ksmt/ksmt-core/0.5.13) +[![Maven Central](https://img.shields.io/maven-central/v/io.ksmt/ksmt-core)](https://central.sonatype.com/artifact/io.ksmt/ksmt-core/0.5.14) [![javadoc](https://javadoc.io/badge2/io.ksmt/ksmt-core/javadoc.svg)](https://javadoc.io/doc/io.ksmt/ksmt-core) ## Get started @@ -20,9 +20,9 @@ To start using KSMT, install it via [Gradle](https://gradle.org/): ```kotlin // core -implementation("io.ksmt:ksmt-core:0.5.13") +implementation("io.ksmt:ksmt-core:0.5.14") // z3 solver -implementation("io.ksmt:ksmt-z3:0.5.13") +implementation("io.ksmt:ksmt-z3:0.5.14") ``` Find basic instructions in the [Getting started](docs/getting-started.md) guide and try it out with the diff --git a/buildSrc/src/main/kotlin/io.ksmt.ksmt-base.gradle.kts b/buildSrc/src/main/kotlin/io.ksmt.ksmt-base.gradle.kts index 9f6a75210..749500ba0 100644 --- a/buildSrc/src/main/kotlin/io.ksmt.ksmt-base.gradle.kts +++ b/buildSrc/src/main/kotlin/io.ksmt.ksmt-base.gradle.kts @@ -11,7 +11,7 @@ plugins { } group = "io.ksmt" -version = "0.5.13" +version = "0.5.14" repositories { mavenCentral() diff --git a/docs/getting-started.md b/docs/getting-started.md index 41d76bbaa..f1eeb9141 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -34,7 +34,7 @@ repositories { ```kotlin dependencies { // core - implementation("io.ksmt:ksmt-core:0.5.13") + implementation("io.ksmt:ksmt-core:0.5.14") } ``` @@ -43,9 +43,9 @@ dependencies { ```kotlin dependencies { // z3 - implementation("io.ksmt:ksmt-z3:0.5.13") + implementation("io.ksmt:ksmt-z3:0.5.14") // bitwuzla - implementation("io.ksmt:ksmt-bitwuzla:0.5.13") + implementation("io.ksmt:ksmt-bitwuzla:0.5.14") } ``` diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index ec8a6ce6d..be8527bb7 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -9,11 +9,11 @@ repositories { dependencies { // core - implementation("io.ksmt:ksmt-core:0.5.13") + implementation("io.ksmt:ksmt-core:0.5.14") // z3 solver - implementation("io.ksmt:ksmt-z3:0.5.13") + implementation("io.ksmt:ksmt-z3:0.5.14") // Runner and portfolio solver - implementation("io.ksmt:ksmt-runner:0.5.13") + implementation("io.ksmt:ksmt-runner:0.5.14") } java { diff --git a/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KArrayExprSimplifier.kt b/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KArrayExprSimplifier.kt index 3dcae72f4..886b37f5c 100644 --- a/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KArrayExprSimplifier.kt +++ b/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KArrayExprSimplifier.kt @@ -953,7 +953,7 @@ interface KArrayExprSimplifier : KExprSimplifierBase { val original: KExpr, val base: KExpr, val values: List> - ) : KExpr(ctx) { + ) : KExpr(ctx), KSimplifierAuxExpr { override val sort: A get() = base.sort @@ -1146,7 +1146,7 @@ interface KArrayExprSimplifier : KExprSimplifierBase { private sealed class SimplifierArraySelectBaseExpr, R : KSort>( ctx: KContext, val array: KExpr - ) : KExpr(ctx) { + ) : KExpr(ctx), KSimplifierAuxExpr { override val sort: R get() = array.sort.range @@ -1217,7 +1217,7 @@ interface KArrayExprSimplifier : KExprSimplifierBase { private sealed class SelectFromStoreExprBase, R : KSort>( ctx: KContext, array: KArrayStoreBase - ) : KExpr(ctx) { + ) : KExpr(ctx), KSimplifierAuxExpr { val storeValue: KExpr = array.value override val sort: R = storeValue.sort diff --git a/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KBoolExprSimplifier.kt b/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KBoolExprSimplifier.kt index 81b012048..40540f921 100644 --- a/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KBoolExprSimplifier.kt +++ b/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KBoolExprSimplifier.kt @@ -15,6 +15,7 @@ import io.ksmt.expr.KXorExpr import io.ksmt.expr.transformer.KTransformerBase import io.ksmt.sort.KBoolSort import io.ksmt.sort.KSort +import java.util.IdentityHashMap interface KBoolExprSimplifier : KExprSimplifierBase { @@ -213,7 +214,7 @@ interface KBoolExprSimplifier : KExprSimplifierBase { val condition: KExpr, val trueBranch: KExpr, val falseBranch: KExpr - ) : KApp(ctx) { + ) : KApp(ctx), KSimplifierAuxExpr { override val decl: KDecl get() = ctx.mkIteDecl(trueBranch.sort) @@ -240,7 +241,7 @@ interface KBoolExprSimplifier : KExprSimplifierBase { val simplifiedCondition: KExpr, val trueBranch: KExpr, val falseBranch: KExpr - ) : KApp(ctx) { + ) : KApp(ctx), KSimplifierAuxExpr { override val decl: KDecl get() = ctx.mkIteDecl(trueBranch.sort) @@ -272,7 +273,7 @@ interface KBoolExprSimplifier : KExprSimplifierBase { val neutralElement: KExpr, val zeroElement: KExpr, override val args: List> - ) : KApp(ctx) { + ) : KApp(ctx), KSimplifierAuxExpr { override val sort: KBoolSort = ctx.boolSort override val decl: KDecl get() = when (operation) { @@ -287,6 +288,7 @@ interface KBoolExprSimplifier : KExprSimplifierBase { val simplifiedArgs = arrayListOf>() + private val visitedArgs = IdentityHashMap, Unit>() private val argsIteratorStack = arrayListOf(args.iterator()) private var currentArgument: KExpr? = null @@ -309,6 +311,9 @@ interface KBoolExprSimplifier : KExprSimplifierBase { while (hasUnprocessedArgument()) { val argument = argsIteratorStack.last().next() + + if (visitedArgs.put(argument, Unit) != null) continue + if (!tryFlatExpr(argument)) { currentArgument = argument return diff --git a/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KBvExprSimplifier.kt b/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KBvExprSimplifier.kt index 779fd5eb1..f737f7b4d 100644 --- a/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KBvExprSimplifier.kt +++ b/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KBvExprSimplifier.kt @@ -1083,7 +1083,7 @@ interface KBvExprSimplifier : KExprSimplifierBase { private class SimplifierFlatBvAddExpr( ctx: KContext, override val args: List> - ) : KApp(ctx) { + ) : KApp(ctx), KSimplifierAuxExpr { override val decl: KDecl get() = ctx.mkBvAddDecl(sort, sort) @@ -1104,7 +1104,7 @@ interface KBvExprSimplifier : KExprSimplifierBase { private class SimplifierFlatBvMulExpr( ctx: KContext, override val args: List> - ) : KApp(ctx) { + ) : KApp(ctx), KSimplifierAuxExpr { override val decl: KDecl get() = ctx.mkBvMulDecl(sort, sort) @@ -1125,7 +1125,7 @@ interface KBvExprSimplifier : KExprSimplifierBase { private class SimplifierFlatBvOrExpr( ctx: KContext, override val args: List> - ) : KApp(ctx) { + ) : KApp(ctx), KSimplifierAuxExpr { override val decl: KDecl get() = ctx.mkBvOrDecl(sort, sort) @@ -1146,7 +1146,7 @@ interface KBvExprSimplifier : KExprSimplifierBase { private class SimplifierFlatBvAndExpr( ctx: KContext, override val args: List> - ) : KApp(ctx) { + ) : KApp(ctx), KSimplifierAuxExpr { override val decl: KDecl get() = ctx.mkBvAndDecl(sort, sort) @@ -1167,7 +1167,7 @@ interface KBvExprSimplifier : KExprSimplifierBase { private class SimplifierFlatBvXorExpr( ctx: KContext, override val args: List> - ) : KApp(ctx) { + ) : KApp(ctx), KSimplifierAuxExpr { override val decl: KDecl get() = ctx.mkBvXorDecl(sort, sort) @@ -1189,7 +1189,7 @@ interface KBvExprSimplifier : KExprSimplifierBase { ctx: KContext, override val sort: KBvSort, override val args: List> - ) : KApp(ctx) { + ) : KApp(ctx), KSimplifierAuxExpr { // We have no decl, but we don't care since decl is unused override val decl: KDecl diff --git a/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KExprSimplifier.kt b/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KExprSimplifier.kt index 3d1eda88f..0335f1a09 100644 --- a/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KExprSimplifier.kt +++ b/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KExprSimplifier.kt @@ -343,6 +343,10 @@ open class KExprSimplifier(override val ctx: KContext) : val result = transformedExpr(rewriteFrame.rewritten) ?: error("Nested rewrite failed") + if (rewriteFrame.rewritten is KSimplifierAuxExpr) { + eraseTransformationResult(rewriteFrame.rewritten) + } + return result.uncheckedCast() } diff --git a/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KExprSimplifierBase.kt b/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KExprSimplifierBase.kt index 46c7b9698..38721ec46 100644 --- a/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KExprSimplifierBase.kt +++ b/ksmt-core/src/main/kotlin/io/ksmt/expr/rewrite/simplify/KExprSimplifierBase.kt @@ -46,6 +46,11 @@ interface KExprSimplifierBase : KTransformer { @JvmInline internal value class SimplifierAuxExpression(val expr: KExpr) +/** + * Mark simplifier auxiliary expressions. + * */ +internal interface KSimplifierAuxExpr + internal inline fun auxExpr(builder: () -> KExpr): SimplifierAuxExpression = SimplifierAuxExpression(builder()) diff --git a/ksmt-core/src/main/kotlin/io/ksmt/expr/transformer/KNonRecursiveTransformerBase.kt b/ksmt-core/src/main/kotlin/io/ksmt/expr/transformer/KNonRecursiveTransformerBase.kt index 00abc2a83..feaf36820 100644 --- a/ksmt-core/src/main/kotlin/io/ksmt/expr/transformer/KNonRecursiveTransformerBase.kt +++ b/ksmt-core/src/main/kotlin/io/ksmt/expr/transformer/KNonRecursiveTransformerBase.kt @@ -128,6 +128,14 @@ abstract class KNonRecursiveTransformerBase: KTransformer { return transformed[expr] as? KExpr } + /** + * Erase [expr] transformation result. + * Useful for transformer auxiliary expressions. + * */ + fun eraseTransformationResult(expr: KExpr<*>) { + transformed.remove(expr) + } + /** * Allows to skip expression transformation and stop deepening. * */ diff --git a/ksmt-runner/src/main/kotlin/io/ksmt/runner/core/ChildProcessBase.kt b/ksmt-runner/src/main/kotlin/io/ksmt/runner/core/ChildProcessBase.kt index be7d8dc1c..dcb56e4c5 100644 --- a/ksmt-runner/src/main/kotlin/io/ksmt/runner/core/ChildProcessBase.kt +++ b/ksmt-runner/src/main/kotlin/io/ksmt/runner/core/ChildProcessBase.kt @@ -29,7 +29,7 @@ abstract class ChildProcessBase { private val synchronizer = Channel(capacity = 1) abstract fun initProtocolModel(protocol: IProtocol): Model - abstract fun Model.setup(astSerializationCtx: AstSerializationCtx) + abstract fun Model.setup(astSerializationCtx: AstSerializationCtx, lifetime: Lifetime) abstract fun parseArgs(args: Array): KsmtWorkerArgs fun start(args: Array) = runBlocking { @@ -84,7 +84,7 @@ abstract class ChildProcessBase { initProtocolModel(clientProtocol) }.await() - protocolModel.setup(astSerializationCtx) + protocolModel.setup(astSerializationCtx, lifetime) clientProtocol.syncProtocolModel.synchronizationSignal.let { sync -> val answerFromMainProcess = sync.adviseForConditionAsync(lifetime) { diff --git a/ksmt-runner/src/main/kotlin/io/ksmt/solver/runner/KSolverWorkerProcess.kt b/ksmt-runner/src/main/kotlin/io/ksmt/solver/runner/KSolverWorkerProcess.kt index 2506d578a..48ff7c29b 100644 --- a/ksmt-runner/src/main/kotlin/io/ksmt/solver/runner/KSolverWorkerProcess.kt +++ b/ksmt-runner/src/main/kotlin/io/ksmt/solver/runner/KSolverWorkerProcess.kt @@ -1,6 +1,7 @@ package io.ksmt.solver.runner import com.jetbrains.rd.framework.IProtocol +import com.jetbrains.rd.util.lifetime.Lifetime import io.ksmt.KContext import io.ksmt.expr.KExpr import io.ksmt.runner.core.ChildProcessBase @@ -44,7 +45,7 @@ class KSolverWorkerProcess : ChildProcessBase() { protocol.solverProtocolModel @Suppress("LongMethod") - override fun SolverProtocolModel.setup(astSerializationCtx: AstSerializationCtx) { + override fun SolverProtocolModel.setup(astSerializationCtx: AstSerializationCtx, lifetime: Lifetime) { initSolver.measureExecutionForTermination { params -> check(workerCtx == null) { "Solver is initialized" } @@ -141,6 +142,10 @@ class KSolverWorkerProcess : ChildProcessBase() { interrupt.measureExecutionForTermination { solver.interrupt() } + lifetime.onTermination { + workerSolver?.close() + workerCtx?.close() + } } private fun serializeFunctionInterpretation(interp: KFuncInterp<*>): ModelEntry { diff --git a/ksmt-test/src/main/kotlin/io/ksmt/test/TestWorkerProcess.kt b/ksmt-test/src/main/kotlin/io/ksmt/test/TestWorkerProcess.kt index d6308d7de..0a702df7d 100644 --- a/ksmt-test/src/main/kotlin/io/ksmt/test/TestWorkerProcess.kt +++ b/ksmt-test/src/main/kotlin/io/ksmt/test/TestWorkerProcess.kt @@ -1,6 +1,7 @@ package io.ksmt.test import com.jetbrains.rd.framework.IProtocol +import com.jetbrains.rd.util.lifetime.Lifetime import com.microsoft.z3.AST import com.microsoft.z3.BoolSort import com.microsoft.z3.Context @@ -236,7 +237,7 @@ class TestWorkerProcess : ChildProcessBase() { protocol.testProtocolModel @Suppress("LongMethod") - override fun TestProtocolModel.setup(astSerializationCtx: AstSerializationCtx) { + override fun TestProtocolModel.setup(astSerializationCtx: AstSerializationCtx, lifetime: Lifetime) { // Limit z3 native memory usage to avoid OOM Native.globalParamSet("memory_high_watermark_mb", "2048") // 2048 megabytes