main.io.ksmt.solver.cvc5.KCvc5Model.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ksmt-cvc5-core Show documentation
Show all versions of ksmt-cvc5-core Show documentation
Kotlin API for various SMT solvers
The newest version!
package io.ksmt.solver.cvc5
import io.github.cvc5.Solver
import io.github.cvc5.Term
import io.ksmt.KContext
import io.ksmt.decl.KConstDecl
import io.ksmt.decl.KDecl
import io.ksmt.decl.KFuncDecl
import io.ksmt.expr.KExpr
import io.ksmt.expr.KUninterpretedSortValue
import io.ksmt.solver.model.KFuncInterp
import io.ksmt.solver.model.KFuncInterpVarsFree
import io.ksmt.solver.model.KFuncInterpWithVars
import io.ksmt.solver.KModel
import io.ksmt.solver.model.KModelEvaluator
import io.ksmt.solver.model.KModelImpl
import io.ksmt.sort.KSort
import io.ksmt.sort.KUninterpretedSort
import io.ksmt.utils.mkFreshConst
open class KCvc5Model(
private val ctx: KContext,
private val cvc5Ctx: KCvc5Context,
private val solver: Solver,
private val internalizer: KCvc5ExprInternalizer,
override val declarations: Set>,
override val uninterpretedSorts: Set
) : KModel {
private val tm = cvc5Ctx.termManager
private val converter: KCvc5ExprConverter by lazy { KCvc5ExprConverter(ctx, cvc5Ctx, solver, this) }
private val interpretations = hashMapOf, KFuncInterp<*>?>()
private val uninterpretedSortValues = hashMapOf()
private val evaluatorWithCompletion by lazy { KModelEvaluator(ctx, this, isComplete = true) }
private val evaluatorWithoutCompletion by lazy { KModelEvaluator(ctx, this, isComplete = false) }
private var isValid: Boolean = true
fun markInvalid() {
isValid = false
}
private fun ensureModelValid() {
ensureContextActive()
check(isValid) { "The model is no longer valid" }
}
override fun eval(expr: KExpr, isComplete: Boolean): KExpr {
ctx.ensureContextMatch(expr)
val evaluator = if (isComplete) evaluatorWithCompletion else evaluatorWithoutCompletion
return evaluator.apply(expr)
}
@Suppress("UNCHECKED_CAST")
override fun interpretation(decl: KDecl): KFuncInterp? = interpretations.getOrPut(decl) {
ensureModelValid()
ctx.ensureContextMatch(decl)
if (decl !in declarations) return@getOrPut null
val cvc5Decl = with(internalizer) { decl.internalizeDecl() }
when (decl) {
is KConstDecl -> constInterp(decl, cvc5Decl)
is KFuncDecl -> funcInterp(decl, cvc5Decl)
else -> error("Unknown declaration")
}
} as? KFuncInterp
// cvc5 function interpretation - declaration is Term of kind Lambda
private fun funcInterp(
decl: KDecl,
internalizedDecl: Term
): KFuncInterp = with(converter) {
val cvc5Interp = solver.getValue(internalizedDecl).also { tm.registerPointer(it) }
val vars = decl.argSorts.map { it.mkFreshConst("x") }
val cvc5Vars = vars.map { with(internalizer) { it.internalizeExpr() } }.toTypedArray()
val cvc5InterpArgs = tm.termChild(cvc5Interp, 0).getChildren()
val cvc5FreshVarsInterp = tm.termOp(cvc5Interp) { substitute(cvc5InterpArgs, cvc5Vars) }
val defaultBody = tm.termChild(cvc5FreshVarsInterp, 1).convertExpr()
KFuncInterpWithVars(decl, vars.map { it.decl }, emptyList(), defaultBody)
}
private fun constInterp(decl: KDecl, const: Term): KFuncInterp = with(converter) {
val cvc5Interp = solver.getValue(const).also { tm.registerPointer(it) }
val interp = cvc5Interp.convertExpr()
KFuncInterpVarsFree(decl = decl, entries = emptyList(), default = interp)
}
override fun uninterpretedSortUniverse(sort: KUninterpretedSort): Set? =
getUninterpretedSortContext(sort).getSortUniverse()
internal fun resolveUninterpretedSortValue(sort: KUninterpretedSort, value: Term): KUninterpretedSortValue =
getUninterpretedSortContext(sort).getValue(value)
override fun detach(): KModel {
val interpretations = declarations.associateWith {
interpretation(it) ?: error("missed interpretation for $it")
}
val uninterpretedSortsUniverses = uninterpretedSorts.associateWith {
uninterpretedSortUniverse(it) ?: error("missed sort universe for $it")
}
// The model is detached from the solver and therefore invalid
markInvalid()
return KModelImpl(ctx, interpretations, uninterpretedSortsUniverses)
}
override fun close() {
markInvalid()
}
private fun ensureContextActive() = check(cvc5Ctx.isActive) { "Context already closed" }
private fun getUninterpretedSortContext(sort: KUninterpretedSort): UninterpretedSortValueContext =
uninterpretedSortValues.getOrPut(sort) { UninterpretedSortValueContext(sort) }
private inner class UninterpretedSortValueContext(val sort: KUninterpretedSort) {
private var initialized = false
private var currentValueIdx = 0
private val modelValues = KCvc5TermMap()
private val sortUniverse = hashSetOf()
fun getSortUniverse(): Set {
ensureInitialized()
return sortUniverse
}
fun getValue(modelValue: Term): KUninterpretedSortValue {
ensureInitialized()
return mkValue(modelValue)
}
private fun ensureInitialized() {
if (initialized) return
initialize()
initialized = true
}
private fun initialize() {
if (sort !in uninterpretedSorts) {
return
}
ensureModelValid()
initializeModelValues()
val cvc5Sort = with(internalizer) { sort.internalizeSort() }
val cvc5SortUniverse = solver.getModelDomainElements(cvc5Sort)
.onEach { tm.registerPointer(it) }
initializeSortUniverse(cvc5SortUniverse)
}
private fun initializeModelValues() {
val registeredValues = cvc5Ctx.getRegisteredSortValues(sort)
registeredValues.forEach { (nativeValue, value) ->
val modelValue = solver.getValue(nativeValue).also { tm.registerPointer(it) }
modelValues[modelValue] = value
currentValueIdx = maxOf(currentValueIdx, value.valueIdx + 1)
}
}
private fun initializeSortUniverse(universe: Array) {
universe.forEach {
sortUniverse.add(mkValue(it))
}
}
private fun mkValue(modelValue: Term): KUninterpretedSortValue = modelValues.getOrPut(modelValue) {
mkFreshValue()
}
private fun mkFreshValue() = ctx.mkUninterpretedSortValue(sort, currentValueIdx++)
}
}