11package org.ksmt.solver.bitwuzla
22
33import org.ksmt.KContext
4+ import org.ksmt.decl.KConstDecl
45import org.ksmt.decl.KDecl
5- import org.ksmt.decl.KFuncDecl
66import org.ksmt.expr.KExpr
77import org.ksmt.expr.KUninterpretedSortValue
88import org.ksmt.solver.KModel
99import org.ksmt.solver.KSolverUnsupportedFeatureException
1010import org.ksmt.solver.bitwuzla.bindings.BitwuzlaNativeException
1111import org.ksmt.solver.bitwuzla.bindings.BitwuzlaTerm
12+ import org.ksmt.solver.bitwuzla.bindings.FunValue
1213import org.ksmt.solver.bitwuzla.bindings.Native
1314import org.ksmt.solver.model.KModelEvaluator
1415import org.ksmt.solver.model.KModelImpl
1516import org.ksmt.sort.KArraySort
17+ import org.ksmt.sort.KArraySortBase
1618import org.ksmt.sort.KSort
1719import org.ksmt.sort.KUninterpretedSort
1820import org.ksmt.utils.mkFreshConstDecl
@@ -99,7 +101,7 @@ open class KBitwuzlaModel(
99101 term : BitwuzlaTerm
100102 ): KModel .KFuncInterp <T > = converter.withUninterpretedSortValueContext(uninterpretedSortValueContext) {
101103 when {
102- Native .bitwuzlaTermIsArray(term) -> ctx. arrayInterpretation(decl, term)
104+ Native .bitwuzlaTermIsArray(term) -> arrayInterpretation(decl, term)
103105 Native .bitwuzlaTermIsFun(term) -> functionInterpretation(decl, term)
104106 else -> {
105107 val value = Native .bitwuzlaGetValue(bitwuzlaCtx.bitwuzla, term)
@@ -117,36 +119,56 @@ open class KBitwuzlaModel(
117119 private fun <T : KSort > functionInterpretation (
118120 decl : KDecl <T >,
119121 term : BitwuzlaTerm
120- ): KModel .KFuncInterp <T > = with (converter) {
121- check(decl is KFuncDecl <T >) { " function expected but actual is $decl " }
122-
123- val entries = mutableListOf<KModel .KFuncInterpEntry <T >>()
122+ ): KModel .KFuncInterp <T > {
124123 val interp = Native .bitwuzlaGetFunValue(bitwuzlaCtx.bitwuzla, term)
125-
126- check(interp.arity == decl.argSorts.size) {
127- " function arity mismatch: ${interp.arity} and ${decl.argSorts.size} "
124+ return if (interp.size != 0 ) {
125+ handleArrayFunctionDecl(decl) { functionDecl, vars ->
126+ functionValueInterpretation(functionDecl, vars, interp)
127+ }
128+ } else {
129+ /* *
130+ * Function has default value or bitwuzla can't retrieve its entries.
131+ * Try parse function interpretation from value term.
132+ * */
133+ converter.retrieveFunctionValue(decl, term)
128134 }
135+ }
136+
137+ private fun <T : KSort > KBitwuzlaExprConverter.functionValueInterpretation (
138+ decl : KDecl <T >,
139+ vars : List <KConstDecl <* >>,
140+ interp : FunValue
141+ ): KModel .KFuncInterp <T > {
142+ val entries = mutableListOf<KModel .KFuncInterpEntry <T >>()
129143
130- val vars = decl.argSorts.map { it.mkFreshConstDecl(" x" ) }
131144 for (i in 0 until interp.size) {
132145 // Don't substitute vars since arguments in Bitwuzla model are always constants
133146 val args = interp.args!! [i].zip(decl.argSorts) { arg, sort -> arg.convertExpr(sort) }
134147 val value = interp.values!! [i].convertExpr(decl.sort)
135148 entries + = KModel .KFuncInterpEntry (args, value)
136149 }
137150
138- KModel .KFuncInterp (
151+ return KModel .KFuncInterp (
139152 decl = decl,
140153 vars = vars,
141154 entries = entries,
142155 default = null
143156 )
144157 }
145158
146- private fun <T : KSort > KContext.arrayInterpretation (
159+ private fun <T : KSort > KBitwuzlaExprConverter.retrieveFunctionValue (
160+ decl : KDecl <T >,
161+ functionTerm : BitwuzlaTerm
162+ ): KModel .KFuncInterp <T > = handleArrayFunctionInterpretation(decl) { arraySort ->
163+ // We expect lambda expression here. Therefore, we convert function interpretation as array.
164+ val functionValue = Native .bitwuzlaGetValue(bitwuzlaCtx.bitwuzla, functionTerm)
165+ functionValue.convertExpr(arraySort)
166+ }
167+
168+ private fun <T : KSort > arrayInterpretation (
147169 decl : KDecl <T >,
148170 term : BitwuzlaTerm
149- ): KModel .KFuncInterp <T > = with (converter ) {
171+ ): KModel .KFuncInterp <T > = handleArrayFunctionDecl(decl ) { arrayFunctionDecl, vars ->
150172 val sort: KArraySort <KSort , KSort > = decl.sort.uncheckedCast()
151173 val entries = mutableListOf<KModel .KFuncInterpEntry <KSort >>()
152174 val interp = Native .bitwuzlaGetArrayValue(bitwuzlaCtx.bitwuzla, term)
@@ -158,22 +180,73 @@ open class KBitwuzlaModel(
158180 }
159181
160182 val default = interp.defaultValue.takeIf { it != 0L }?.convertExpr(sort.range)
161- val arrayInterpDecl = mkFreshFuncDecl(" array" , sort.range, listOf (sort.domain))
162- val arrayInterpIndexDecl = mkFreshConstDecl(" idx" , sort.domain)
163183
164- modelDeclarations + = arrayInterpDecl
165- interpretations[arrayInterpDecl] = KModel .KFuncInterp (
166- decl = arrayInterpDecl,
167- vars = listOf (arrayInterpIndexDecl),
184+ KModel .KFuncInterp (
185+ decl = arrayFunctionDecl,
186+ vars = vars,
168187 entries = entries,
169188 default = default
170189 )
190+ }
191+
192+ private inline fun <T : KSort > handleArrayFunctionDecl (
193+ decl : KDecl <T >,
194+ body : KBitwuzlaExprConverter .(KDecl <KSort >, List <KConstDecl <* >>) -> KModel .KFuncInterp <* >
195+ ): KModel .KFuncInterp <T > = with (ctx) {
196+ val sort = decl.sort
197+
198+ if (sort !is KArraySortBase <* >) {
199+ val vars = decl.argSorts.mapIndexed { i, s -> s.mkFreshConstDecl(" x!$i " ) }
200+ return converter.body(decl.uncheckedCast(), vars).uncheckedCast()
201+ }
202+
203+ check(decl.argSorts.isEmpty()) { " Unexpected function with array range" }
204+
205+ val arrayInterpDecl = mkFreshFuncDecl(" array" , sort.range, sort.domainSorts)
206+ val arrayInterpIndicesDecls = sort.domainSorts.mapIndexed { i, s ->
207+ s.mkFreshConstDecl(" idx!$i " )
208+ }
209+
210+ modelDeclarations + = arrayInterpDecl
211+ interpretations[arrayInterpDecl] = converter.body(arrayInterpDecl, arrayInterpIndicesDecls)
171212
172213 KModel .KFuncInterp (
173214 decl = decl,
174215 vars = emptyList(),
175216 entries = emptyList(),
176- default = mkFunctionAsArray(sort, arrayInterpDecl).uncheckedCast()
217+ default = mkFunctionAsArray(sort.uncheckedCast(), arrayInterpDecl).uncheckedCast()
218+ )
219+ }
220+
221+ private inline fun <T : KSort > KBitwuzlaExprConverter.handleArrayFunctionInterpretation (
222+ decl : KDecl <T >,
223+ convertInterpretation : (KArraySortBase <* >) -> KExpr <KArraySortBase <* >>
224+ ): KModel .KFuncInterp <T > {
225+ val sort = decl.sort
226+
227+ if (sort is KArraySortBase <* > && decl.argSorts.isEmpty()) {
228+ val arrayInterpretation = convertInterpretation(sort)
229+ return KModel .KFuncInterp (
230+ decl = decl,
231+ vars = emptyList(),
232+ entries = emptyList(),
233+ default = arrayInterpretation.uncheckedCast()
234+ )
235+ }
236+
237+ check(decl.argSorts.isEmpty()) { " Unexpected function with array range" }
238+
239+ val interpretationSort = ctx.mkAnyArraySort(decl.argSorts, decl.sort)
240+ val arrayInterpretation = convertInterpretation(interpretationSort)
241+
242+ val functionVars = decl.argSorts.mapIndexed { i, s -> s.mkFreshConstDecl(" x!$i " ) }
243+ val functionValue = ctx.mkAnyArraySelect(arrayInterpretation, functionVars.map { it.apply () })
244+
245+ return KModel .KFuncInterp (
246+ decl = decl,
247+ vars = functionVars,
248+ entries = emptyList(),
249+ default = functionValue.uncheckedCast()
177250 )
178251 }
179252
0 commit comments