All Downloads are FREE. Search and download functionalities are using the official Maven repository.

main.io.ksmt.solver.cvc5.KCvc5Model.kt Maven / Gradle / Ivy

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++)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy