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

main.io.ksmt.solver.yices.KYicesModel.kt Maven / Gradle / Ivy

The newest version!
package io.ksmt.solver.yices

import com.sri.yices.Model
import com.sri.yices.YVal
import com.sri.yices.YValTag
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.KFuncInterpEntryVarsFree
import io.ksmt.solver.model.KFuncInterpVarsFree
import io.ksmt.solver.KModel
import io.ksmt.solver.model.KModelEvaluator
import io.ksmt.solver.model.KModelImpl
import io.ksmt.sort.KArray2Sort
import io.ksmt.sort.KArray3Sort
import io.ksmt.sort.KArrayNSort
import io.ksmt.sort.KArraySort
import io.ksmt.sort.KArraySortBase
import io.ksmt.sort.KBoolSort
import io.ksmt.sort.KBvSort
import io.ksmt.sort.KFpRoundingModeSort
import io.ksmt.sort.KFpSort
import io.ksmt.sort.KIntSort
import io.ksmt.sort.KRealSort
import io.ksmt.sort.KSort
import io.ksmt.sort.KSortVisitor
import io.ksmt.sort.KUninterpretedSort
import io.ksmt.utils.uncheckedCast

class KYicesModel(
    nativeModel: Model,
    private val ctx: KContext,
    private val yicesCtx: KYicesContext,
    private val internalizer: KYicesExprInternalizer,
    private val converter: KYicesExprConverter
) : KModel {
    private var nativeModel: Model? = nativeModel
    private val model: Model
        get() = nativeModel ?: error("Native model released")

    override val declarations: Set> by lazy {
        model.collectDefinedTerms().mapTo(hashSetOf()) { converter.convertDecl(it) }
    }

    override val uninterpretedSorts: Set by lazy {
        uninterpretedSortDependencies.keys
    }

    private val uninterpretedSortDependencies: Map>> by lazy {
        val sortsWithDependencies = hashMapOf>>()
        val sortCollector = UninterpretedSortCollector(sortsWithDependencies)
        declarations.forEach { sortCollector.collect(it) }
        sortsWithDependencies
    }

    private val uninterpretedSortUniverse =
        hashMapOf>()

    private val knownUninterpretedSortValues =
        hashMapOf>()

    private val interpretations = hashMapOf, KFuncInterp<*>>()
    private val funcInterpretationsToDo = arrayListOf>>()

    override fun uninterpretedSortUniverse(
        sort: KUninterpretedSort
    ): Set? = uninterpretedSortUniverse.getOrPut(sort) {
        val sortDependencies = uninterpretedSortDependencies[sort] ?: return null

        sortDependencies.forEach { interpretation(it) }

        knownUninterpretedSortValues[sort]?.values?.toHashSet() ?: hashSetOf()
    }

    private val evaluatorWithModelCompletion by lazy { KModelEvaluator(ctx, this, isComplete = true) }
    private val evaluatorWithoutModelCompletion by lazy { KModelEvaluator(ctx, this, isComplete = false) }

    override fun  eval(expr: KExpr, isComplete: Boolean): KExpr {
        ctx.ensureContextMatch(expr)

        val evaluator = if (isComplete) evaluatorWithModelCompletion else evaluatorWithoutModelCompletion
        return evaluator.apply(expr)
    }

    private fun getValue(yval: YVal, sort: KSort): KExpr<*> = with(ctx) {
        return when (sort) {
            is KBoolSort -> model.boolValue(yval).expr
            is KBvSort -> mkBv(model.bvValue(yval), sort.sizeBits)
            is KRealSort -> mkRealNum(model.bigRationalValue(yval))
            is KIntSort -> mkIntNum(model.bigRationalValue(yval))
            is KUninterpretedSort -> {
                val uninterpretedSortValueId = model.scalarValue(yval)[0]
                val sortValues = knownUninterpretedSortValues.getOrPut(sort) { hashMapOf() }
                sortValues.getOrPut(uninterpretedSortValueId) {
                    val valueIndex = yicesCtx.convertUninterpretedSortValueIndex(uninterpretedSortValueId)
                    mkUninterpretedSortValue(sort, valueIndex)
                }
            }
            is KArraySortBase<*> -> {
                val funcDecl = ctx.mkFreshFuncDecl("array", sort.range, sort.domainSorts)

                funcInterpretationsToDo.add(Pair(yval, funcDecl))

                mkFunctionAsArray(sort.uncheckedCast(), funcDecl)
            }
            else -> error("Unsupported sort $sort")
        }
    }

    private fun  functionInterpretation(yval: YVal, decl: KFuncDecl): KFuncInterp {
        val functionChildren = model.expandFunction(yval)
        val default = if (yval.tag != YValTag.UNKNOWN) {
            getValue(functionChildren.value, decl.sort).uncheckedCast<_, KExpr>()
        } else {
            null
        }

        val entries = functionChildren.vector.map { mapping ->
            val entry = model.expandMapping(mapping)
            val args = entry.vector.zip(decl.argSorts).map { (arg, sort) ->
                getValue(arg, sort)
            }
            val res = getValue(entry.value, decl.sort).uncheckedCast<_, KExpr>()

            KFuncInterpEntryVarsFree.create(args, res)
        }

        return KFuncInterpVarsFree(
            decl = decl,
            entries = entries,
            default = default
        )
    }

    override fun  interpretation(decl: KDecl): KFuncInterp? = with(ctx) {
        interpretations.getOrPut(decl) {
            if (decl !in declarations) return@with null

            val yicesDecl = with(internalizer) { decl.internalizeDecl() }
            val yval = model.getValue(yicesDecl)

            val result = when (decl) {
                is KConstDecl -> KFuncInterpVarsFree(
                    decl = decl,
                    entries = emptyList(),
                    default = getValue(yval, decl.sort).uncheckedCast()
                )
                is KFuncDecl -> functionInterpretation(yval, decl)
                else -> error("Unexpected declaration $decl")
            }

            while (funcInterpretationsToDo.isNotEmpty()) {
                val (yvalT, declT) = funcInterpretationsToDo.removeLast()

                interpretations[declT] = functionInterpretation(yvalT, declT)
            }

            result
        }.uncheckedCast<_, KFuncInterp?>()
    }

    override fun detach(): KModel {
        declarations.forEach { interpretation(it) }

        val uninterpretedSortsUniverses = uninterpretedSorts.associateWith {
            uninterpretedSortUniverse(it) ?: error("missed sort universe for $it")
        }

        // The model is detached from the solver and therefore can be released
        releaseNativeModel()

        return KModelImpl(ctx, interpretations.toMap(), uninterpretedSortsUniverses)
    }

    override fun close() {
        releaseNativeModel()
    }

    private fun releaseNativeModel() {
        nativeModel?.close()
        nativeModel = null
    }

    private class UninterpretedSortCollector(
        private val sorts: MutableMap>>
    ) : KSortVisitor {
        private lateinit var currentDecl: KDecl<*>

        fun collect(decl: KDecl<*>) {
            currentDecl = decl

            decl.sort.accept(this)
            decl.argSorts.forEach { it.accept(this) }
        }

        override fun  visit(sort: KArraySort) {
            sort.range.accept(this)
            sort.domain.accept(this)
        }

        override fun  visit(sort: KArray2Sort) {
            sort.range.accept(this)
            sort.domain0.accept(this)
            sort.domain1.accept(this)
        }

        override fun  visit(sort: KArray3Sort) {
            sort.range.accept(this)
            sort.domain0.accept(this)
            sort.domain1.accept(this)
            sort.domain2.accept(this)
        }

        override fun  visit(sort: KArrayNSort) {
            sort.range.accept(this)
            sort.domainSorts.forEach { it.accept(this) }
        }

        override fun visit(sort: KUninterpretedSort) {
            val sortDependencies = sorts.getOrPut(sort) { hashSetOf() }
            sortDependencies.add(currentDecl)
        }

        override fun visit(sort: KBoolSort) = Unit
        override fun visit(sort: KIntSort) = Unit
        override fun visit(sort: KRealSort) = Unit
        override fun  visit(sort: S) = Unit
        override fun  visit(sort: S) = Unit
        override fun visit(sort: KFpRoundingModeSort) = Unit
    }
}