Skip to content

Commit

Permalink
Fix expressions simplification (#144)
Browse files Browse the repository at this point in the history
* Runner: fix child process termination

* Core: avoid explosive flattening

* Upgrade version to 0.5.14
  • Loading branch information
Saloed committed Nov 3, 2023
1 parent d848167 commit 3769986
Show file tree
Hide file tree
Showing 13 changed files with 54 additions and 26 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/io.ksmt.ksmt-base.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ plugins {
}

group = "io.ksmt"
version = "0.5.13"
version = "0.5.14"

repositories {
mavenCentral()
Expand Down
6 changes: 3 additions & 3 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ repositories {
```kotlin
dependencies {
// core
implementation("io.ksmt:ksmt-core:0.5.13")
implementation("io.ksmt:ksmt-core:0.5.14")
}
```

Expand All @@ -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")
}
```

Expand Down
6 changes: 3 additions & 3 deletions examples/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -953,7 +953,7 @@ interface KArrayExprSimplifier : KExprSimplifierBase {
val original: KExpr<A>,
val base: KExpr<A>,
val values: List<KExpr<R>>
) : KExpr<A>(ctx) {
) : KExpr<A>(ctx), KSimplifierAuxExpr {
override val sort: A
get() = base.sort

Expand Down Expand Up @@ -1146,7 +1146,7 @@ interface KArrayExprSimplifier : KExprSimplifierBase {
private sealed class SimplifierArraySelectBaseExpr<A : KArraySortBase<R>, R : KSort>(
ctx: KContext,
val array: KExpr<A>
) : KExpr<R>(ctx) {
) : KExpr<R>(ctx), KSimplifierAuxExpr {
override val sort: R
get() = array.sort.range

Expand Down Expand Up @@ -1217,7 +1217,7 @@ interface KArrayExprSimplifier : KExprSimplifierBase {
private sealed class SelectFromStoreExprBase<A : KArraySortBase<R>, R : KSort>(
ctx: KContext,
array: KArrayStoreBase<A, R>
) : KExpr<R>(ctx) {
) : KExpr<R>(ctx), KSimplifierAuxExpr {
val storeValue: KExpr<R> = array.value

override val sort: R = storeValue.sort
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -213,7 +214,7 @@ interface KBoolExprSimplifier : KExprSimplifierBase {
val condition: KExpr<KBoolSort>,
val trueBranch: KExpr<T>,
val falseBranch: KExpr<T>
) : KApp<T, KBoolSort>(ctx) {
) : KApp<T, KBoolSort>(ctx), KSimplifierAuxExpr {

override val decl: KDecl<T>
get() = ctx.mkIteDecl(trueBranch.sort)
Expand All @@ -240,7 +241,7 @@ interface KBoolExprSimplifier : KExprSimplifierBase {
val simplifiedCondition: KExpr<KBoolSort>,
val trueBranch: KExpr<T>,
val falseBranch: KExpr<T>
) : KApp<T, T>(ctx) {
) : KApp<T, T>(ctx), KSimplifierAuxExpr {

override val decl: KDecl<T>
get() = ctx.mkIteDecl(trueBranch.sort)
Expand Down Expand Up @@ -272,7 +273,7 @@ interface KBoolExprSimplifier : KExprSimplifierBase {
val neutralElement: KExpr<KBoolSort>,
val zeroElement: KExpr<KBoolSort>,
override val args: List<KExpr<KBoolSort>>
) : KApp<KBoolSort, KBoolSort>(ctx) {
) : KApp<KBoolSort, KBoolSort>(ctx), KSimplifierAuxExpr {
override val sort: KBoolSort = ctx.boolSort
override val decl: KDecl<KBoolSort>
get() = when (operation) {
Expand All @@ -287,6 +288,7 @@ interface KBoolExprSimplifier : KExprSimplifierBase {

val simplifiedArgs = arrayListOf<KExpr<KBoolSort>>()

private val visitedArgs = IdentityHashMap<KExpr<*>, Unit>()
private val argsIteratorStack = arrayListOf(args.iterator())
private var currentArgument: KExpr<KBoolSort>? = null

Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1083,7 +1083,7 @@ interface KBvExprSimplifier : KExprSimplifierBase {
private class SimplifierFlatBvAddExpr<T : KBvSort>(
ctx: KContext,
override val args: List<KExpr<T>>
) : KApp<T, T>(ctx) {
) : KApp<T, T>(ctx), KSimplifierAuxExpr {

override val decl: KDecl<T>
get() = ctx.mkBvAddDecl(sort, sort)
Expand All @@ -1104,7 +1104,7 @@ interface KBvExprSimplifier : KExprSimplifierBase {
private class SimplifierFlatBvMulExpr<T : KBvSort>(
ctx: KContext,
override val args: List<KExpr<T>>
) : KApp<T, T>(ctx) {
) : KApp<T, T>(ctx), KSimplifierAuxExpr {

override val decl: KDecl<T>
get() = ctx.mkBvMulDecl(sort, sort)
Expand All @@ -1125,7 +1125,7 @@ interface KBvExprSimplifier : KExprSimplifierBase {
private class SimplifierFlatBvOrExpr<T : KBvSort>(
ctx: KContext,
override val args: List<KExpr<T>>
) : KApp<T, T>(ctx) {
) : KApp<T, T>(ctx), KSimplifierAuxExpr {

override val decl: KDecl<T>
get() = ctx.mkBvOrDecl(sort, sort)
Expand All @@ -1146,7 +1146,7 @@ interface KBvExprSimplifier : KExprSimplifierBase {
private class SimplifierFlatBvAndExpr<T : KBvSort>(
ctx: KContext,
override val args: List<KExpr<T>>
) : KApp<T, T>(ctx) {
) : KApp<T, T>(ctx), KSimplifierAuxExpr {

override val decl: KDecl<T>
get() = ctx.mkBvAndDecl(sort, sort)
Expand All @@ -1167,7 +1167,7 @@ interface KBvExprSimplifier : KExprSimplifierBase {
private class SimplifierFlatBvXorExpr<T : KBvSort>(
ctx: KContext,
override val args: List<KExpr<T>>
) : KApp<T, T>(ctx) {
) : KApp<T, T>(ctx), KSimplifierAuxExpr {

override val decl: KDecl<T>
get() = ctx.mkBvXorDecl(sort, sort)
Expand All @@ -1189,7 +1189,7 @@ interface KBvExprSimplifier : KExprSimplifierBase {
ctx: KContext,
override val sort: KBvSort,
override val args: List<KExpr<KBvSort>>
) : KApp<KBvSort, KBvSort>(ctx) {
) : KApp<KBvSort, KBvSort>(ctx), KSimplifierAuxExpr {

// We have no decl, but we don't care since decl is unused
override val decl: KDecl<KBvSort>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ interface KExprSimplifierBase : KTransformer {
@JvmInline
internal value class SimplifierAuxExpression<T : KSort>(val expr: KExpr<T>)

/**
* Mark simplifier auxiliary expressions.
* */
internal interface KSimplifierAuxExpr

internal inline fun <T : KSort> auxExpr(builder: () -> KExpr<T>): SimplifierAuxExpression<T> =
SimplifierAuxExpression(builder())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,14 @@ abstract class KNonRecursiveTransformerBase: KTransformer {
return transformed[expr] as? KExpr<T>
}

/**
* Erase [expr] transformation result.
* Useful for transformer auxiliary expressions.
* */
fun eraseTransformationResult(expr: KExpr<*>) {
transformed.remove(expr)
}

/**
* Allows to skip expression transformation and stop deepening.
* */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ abstract class ChildProcessBase<Model> {
private val synchronizer = Channel<State>(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<String>): KsmtWorkerArgs

fun start(args: Array<String>) = runBlocking {
Expand Down Expand Up @@ -84,7 +84,7 @@ abstract class ChildProcessBase<Model> {
initProtocolModel(clientProtocol)
}.await()

protocolModel.setup(astSerializationCtx)
protocolModel.setup(astSerializationCtx, lifetime)

clientProtocol.syncProtocolModel.synchronizationSignal.let { sync ->
val answerFromMainProcess = sync.adviseForConditionAsync(lifetime) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -44,7 +45,7 @@ class KSolverWorkerProcess : ChildProcessBase<SolverProtocolModel>() {
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" }

Expand Down Expand Up @@ -141,6 +142,10 @@ class KSolverWorkerProcess : ChildProcessBase<SolverProtocolModel>() {
interrupt.measureExecutionForTermination {
solver.interrupt()
}
lifetime.onTermination {
workerSolver?.close()
workerCtx?.close()
}
}

private fun serializeFunctionInterpretation(interp: KFuncInterp<*>): ModelEntry {
Expand Down
3 changes: 2 additions & 1 deletion ksmt-test/src/main/kotlin/io/ksmt/test/TestWorkerProcess.kt
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -236,7 +237,7 @@ class TestWorkerProcess : ChildProcessBase<TestProtocolModel>() {
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

Expand Down

0 comments on commit 3769986

Please sign in to comment.