@@ -32,19 +32,28 @@ import io.ksmt.sort.KSortVisitor
3232import io.ksmt.sort.KUninterpretedSort
3333import java.util.TreeMap
3434
35- class KCvc5Context (
35+ class KCvc5Context private constructor (
3636 private val solver : Solver ,
37- private val ctx : KContext
37+ private val ctx : KContext ,
38+ parent : KCvc5Context ? ,
39+ isForking : Boolean
3840) : AutoCloseable {
41+ constructor (solver: Solver , ctx: KContext , isForking: Boolean = false ) : this (solver, ctx, null , isForking)
42+
3943 private var isClosed = false
44+ private val isChild = parent != null
4045
4146 private val uninterpretedSortCollector = KUninterpretedSortCollector (this )
4247 private var exprCurrentLevelCacheRestorer = KCurrentScopeExprCacheRestorer (uninterpretedSortCollector, ctx)
4348
49+ private val uninterpretedSorts: ScopedFrame <HashSet <KUninterpretedSort >>
50+ private val declarations: ScopedFrame <HashSet <KDecl <* >>>
51+
52+
4453 /* *
4554 * We use double-scoped expression internalization cache:
46- * * current (before pop operation) - [currentScopeExpressions ]
47- * * global (after pop operation) - [expressions]
55+ * * current accumulated (before pop operation) - [currentAccumulatedScopeExpressions ]
56+ * * global (current + all previously met) - [expressions]
4857 *
4958 * Due to incremental collect of declarations and uninterpreted sorts for the model,
5059 * we collect them during internalizing.
@@ -57,98 +66,137 @@ class KCvc5Context(
5766 *
5867 * **solution**: Recollect sorts / decls for each expression
5968 * that is in global cache, but whose sorts / decls have been erased after pop()
60- * (and put this expr to the current scope cache )
69+ * (and put this expr to the cache of current accumulated scope )
6170 */
62- private val currentScopeExpressions = HashMap <KExpr <* >, Term > ()
63- private val expressions = HashMap <KExpr <* >, Term > ()
64- // we can't use HashMap with Term and Sort (hashcode is not implemented)
65- private val cvc5Expressions = TreeMap <Term , KExpr <* >>()
66- private val sorts = HashMap <KSort , Sort >()
67- private val cvc5Sorts = TreeMap <Sort , KSort >()
68- private val decls = HashMap <KDecl <* >, Term > ()
69- private val cvc5Decls = TreeMap <Term , KDecl <* >>()
71+ private val currentAccumulatedScopeExpressions: HashMap <KExpr <* >, Term >
72+ private val expressions: HashMap <KExpr <* >, Term >
7073
71- private var currentLevelUninterpretedSorts = hashSetOf<KUninterpretedSort >()
72- private val uninterpretedSorts = mutableListOf (currentLevelUninterpretedSorts)
73-
74- private var currentLevelDeclarations = hashSetOf<KDecl <* >>()
75- private val declarations = mutableListOf (currentLevelDeclarations)
74+ // we can't use HashMap with Term and Sort (hashcode is not implemented)
75+ private val cvc5Expressions: TreeMap <Term , KExpr <* >>
76+ private val sorts: HashMap <KSort , Sort >
77+ private val cvc5Sorts: TreeMap <Sort , KSort >
78+ private val decls: HashMap <KDecl <* >, Term >
79+ private val cvc5Decls: TreeMap <Term , KDecl <* >>
7680
77- fun addUninterpretedSort (sort : KUninterpretedSort ) { currentLevelUninterpretedSorts + = sort }
81+ private val uninterpretedSortValueDescriptors: ArrayList <UninterpretedSortValueDescriptor >
82+ private val uninterpretedSortValueInterpreter: HashMap <KUninterpretedSort , Term >
7883
7984 /* *
80- * uninterpreted sorts of active push-levels
85+ * Uninterpreted sort values and universe are shared for whole forking hierarchy (from parent to children)
86+ * due to shared expressions cache,
87+ * that's why once [registerUninterpretedSortValue] and [saveUninterpretedSortValue] are called,
88+ * each solver in hierarchy should assert newly internalized uninterpreted sort values via [assertPendingAxioms]
89+ *
90+ * @see KCvc5Model.uninterpretedSortUniverse
8191 */
82- fun uninterpretedSorts (): List <Set <KUninterpretedSort >> = uninterpretedSorts
92+ private val uninterpretedSortValues: HashMap <KUninterpretedSort , MutableList <Pair <Term , KUninterpretedSortValue >>>
93+
94+ init {
95+ if (isForking) {
96+ uninterpretedSorts = (parent?.uninterpretedSorts as ? ScopedLinkedFrame )?.fork()
97+ ? : ScopedLinkedFrame (::HashSet , ::HashSet )
98+ declarations = (parent?.declarations as ? ScopedLinkedFrame )?.fork()
99+ ? : ScopedLinkedFrame (::HashSet , ::HashSet )
100+ } else {
101+ uninterpretedSorts = ScopedArrayFrame (::HashSet )
102+ declarations = ScopedArrayFrame (::HashSet )
103+ }
104+
105+ if (parent != null ) {
106+ currentAccumulatedScopeExpressions = parent.currentAccumulatedScopeExpressions.toMap(HashMap ())
107+ expressions = parent.expressions
108+ cvc5Expressions = parent.cvc5Expressions
109+ sorts = parent.sorts
110+ cvc5Sorts = parent.cvc5Sorts
111+ decls = parent.decls
112+ cvc5Decls = parent.cvc5Decls
113+ uninterpretedSortValueDescriptors = parent.uninterpretedSortValueDescriptors
114+ uninterpretedSortValueInterpreter = parent.uninterpretedSortValueInterpreter
115+ uninterpretedSortValues = parent.uninterpretedSortValues
116+ } else {
117+ currentAccumulatedScopeExpressions = HashMap ()
118+ expressions = HashMap ()
119+ cvc5Expressions = TreeMap ()
120+ sorts = HashMap ()
121+ cvc5Sorts = TreeMap ()
122+ decls = HashMap ()
123+ cvc5Decls = TreeMap ()
124+ uninterpretedSortValueDescriptors = arrayListOf ()
125+ uninterpretedSortValueInterpreter = hashMapOf()
126+ uninterpretedSortValues = hashMapOf()
127+ }
128+ }
129+
130+ fun addUninterpretedSort (sort : KUninterpretedSort ) {
131+ uninterpretedSorts.currentFrame + = sort
132+ }
133+
134+ fun uninterpretedSorts (): Set <KUninterpretedSort > = uninterpretedSorts.flatten { this + = it }
83135
84136 fun addDeclaration (decl : KDecl <* >) {
85- currentLevelDeclarations + = decl
137+ declarations.currentFrame + = decl
86138 uninterpretedSortCollector.collect(decl)
87139 }
88140
89- /* *
90- * declarations of active push-levels
91- */
92- fun declarations (): List <Set <KDecl <* >>> = declarations
141+ fun declarations (): Set <KDecl <* >> = declarations.flatten { this + = it }
93142
94143 val nativeSolver: Solver
95144 get() = solver
96145
97146 val isActive: Boolean
98147 get() = ! isClosed
99148
149+ fun fork (solver : Solver ): KCvc5Context = KCvc5Context (solver, ctx, this , true ).also { forkCtx ->
150+ repeat(assertedConstraintLevels.size) {
151+ forkCtx.pushAssertionLevel()
152+ }
153+ }
154+
100155 fun push () {
101- currentLevelDeclarations = hashSetOf()
102- declarations.add(currentLevelDeclarations)
103- currentLevelUninterpretedSorts = hashSetOf()
104- uninterpretedSorts.add(currentLevelUninterpretedSorts)
156+ declarations.push()
157+ uninterpretedSorts.push()
105158
106159 pushAssertionLevel()
107160 }
108161
109162 fun pop (n : UInt ) {
110- repeat(n.toInt()) {
111- declarations.removeLast()
112- uninterpretedSorts.removeLast()
163+ declarations.pop(n)
164+ uninterpretedSorts.pop(n)
113165
114- popAssertionLevel()
115- }
166+ repeat(n.toInt()) { popAssertionLevel() }
116167
117- currentLevelDeclarations = declarations.last()
118- currentLevelUninterpretedSorts = uninterpretedSorts.last()
119-
120- expressions + = currentScopeExpressions
121- currentScopeExpressions.clear()
168+ currentAccumulatedScopeExpressions.clear()
122169 // recreate cache restorer to avoid KNonRecursiveTransformer cache
123170 exprCurrentLevelCacheRestorer = KCurrentScopeExprCacheRestorer (uninterpretedSortCollector, ctx)
124171 }
125172
126- // expr
127- fun findInternalizedExpr (expr : KExpr <* >): Term ? = currentScopeExpressions[expr]
173+ fun findInternalizedExpr (expr : KExpr <* >): Term ? = currentAccumulatedScopeExpressions[expr]
128174 ? : expressions[expr]?.also {
129175 /*
130- * expr is not in current scope cache , but in global cache.
176+ * expr is not in cache of current accumulated scope , but in global cache.
131177 * Recollect declarations and uninterpreted sorts
132- * and add entire expression tree to the current scope cache from the global
133- * to avoid re-internalizing with native calls
178+ * and add entire expression tree to the current accumulated scope cache from the global
179+ * to avoid re-internalization
134180 */
135181 exprCurrentLevelCacheRestorer.apply (expr)
136182 }
137183
138184 fun findConvertedExpr (expr : Term ): KExpr <* >? = cvc5Expressions[expr]
139185
140186 fun saveInternalizedExpr (expr : KExpr <* >, internalized : Term ): Term =
141- internalizeAst(currentScopeExpressions, cvc5Expressions, expr) { internalized }
187+ internalizeAst(currentAccumulatedScopeExpressions, cvc5Expressions, expr) { internalized }
188+ .also { expressions[expr] = internalized }
142189
143190 /* *
144191 * save expr, which is in global cache, to the current scope cache
145192 */
146- fun savePreviouslyInternalizedExpr (expr : KExpr <* >): Term = saveInternalizedExpr(expr, expressions[expr]!! )
193+ fun saveInternalizedExprToCurrentAccumulatedScope (expr : KExpr <* >): Term =
194+ currentAccumulatedScopeExpressions.getOrPut(expr) { expressions[expr]!! }
147195
148196 fun saveConvertedExpr (expr : Term , converted : KExpr <* >): KExpr <* > =
149- convertAst(currentScopeExpressions, cvc5Expressions, expr) { converted }
197+ convertAst(currentAccumulatedScopeExpressions, cvc5Expressions, expr) { converted }
198+ .also { expressions[converted] = expr }
150199
151- // sort
152200 fun findInternalizedSort (sort : KSort ): Sort ? = sorts[sort]
153201
154202 fun findConvertedSort (sort : Sort ): KSort ? = cvc5Sorts[sort]
@@ -165,7 +213,6 @@ class KCvc5Context(
165213 inline fun convertSort (sort : Sort , converter : () -> KSort ): KSort =
166214 findOrSave(sort, converter, ::findConvertedSort, ::saveConvertedSort)
167215
168- // decl
169216 fun findInternalizedDecl (decl : KDecl <* >): Term ? = decls[decl]
170217
171218 fun findConvertedDecl (decl : Term ): KDecl <* >? = cvc5Decls[decl]
@@ -211,17 +258,20 @@ class KCvc5Context(
211258 val nativeValueTerm : Term
212259 )
213260
261+ /* *
262+ * Uninterpreted sort value axioms will not be lost for [KCvc5ForkingSolver] on [fork].
263+ *
264+ * On child initialization, "[currentValueConstraintsLevel] = 0"
265+ * will be pushed to [assertedConstraintLevels] for each push-level ([currentValueConstraintsLevel] times).
266+ * At the first call of [assertPendingAxioms] each descriptor from [uninterpretedSortValueDescriptors]
267+ * will be asserted to the child [KCvc5ForkingSolver]
268+ */
214269 private var currentValueConstraintsLevel = 0
215270 private val assertedConstraintLevels = arrayListOf<Int >()
216- private val uninterpretedSortValueDescriptors = arrayListOf<UninterpretedSortValueDescriptor >()
217- private val uninterpretedSortValueInterpreter = hashMapOf<KUninterpretedSort , Term >()
218-
219- private val uninterpretedSortValues =
220- hashMapOf<KUninterpretedSort , MutableList <Pair <Term , KUninterpretedSortValue >>>()
221271
222272 fun saveUninterpretedSortValue (nativeValue : Term , value : KUninterpretedSortValue ): Term {
223273 val sortValues = uninterpretedSortValues.getOrPut(value.sort) { arrayListOf () }
224- sortValues.add( nativeValue to value)
274+ sortValues + = nativeValue to value
225275 return nativeValue
226276 }
227277
@@ -266,7 +316,7 @@ class KCvc5Context(
266316 uninterpretedSortValues[sort] ? : emptyList()
267317
268318 private fun pushAssertionLevel () {
269- assertedConstraintLevels.add( currentValueConstraintsLevel)
319+ assertedConstraintLevels + = currentValueConstraintsLevel
270320 }
271321
272322 private fun popAssertionLevel () {
@@ -354,20 +404,18 @@ class KCvc5Context(
354404 if (isClosed) return
355405 isClosed = true
356406
357- currentScopeExpressions.clear()
358- expressions.clear()
359- cvc5Expressions.clear()
407+ currentAccumulatedScopeExpressions.clear()
360408
361- uninterpretedSorts.clear()
362- currentLevelUninterpretedSorts.clear()
409+ if (isChild) {
410+ expressions.clear()
411+ cvc5Expressions.clear()
363412
364- declarations .clear()
365- currentLevelDeclarations .clear()
413+ sorts .clear()
414+ cvc5Sorts .clear()
366415
367- sorts.clear()
368- cvc5Sorts.clear()
369- decls.clear()
370- cvc5Decls.clear()
416+ decls.clear()
417+ cvc5Decls.clear()
418+ }
371419 }
372420
373421 class KUninterpretedSortCollector (private val cvc5Ctx : KCvc5Context ) : KSortVisitor<Unit> {
@@ -416,7 +464,8 @@ class KCvc5Context(
416464 ctx : KContext
417465 ) : KNonRecursiveTransformer(ctx) {
418466
419- override fun <T : KSort > exprTransformationRequired (expr : KExpr <T >): Boolean = expr !in currentScopeExpressions
467+ override fun <T : KSort > exprTransformationRequired (expr : KExpr <T >): Boolean =
468+ expr !in currentAccumulatedScopeExpressions
420469
421470 override fun <T : KSort > transform (expr : KFunctionApp <T >): KExpr <T > = cacheIfNeed(expr) {
422471 this @KCvc5Context.addDeclaration(expr.decl)
@@ -426,7 +475,7 @@ class KCvc5Context(
426475 override fun <T : KSort > transform (expr : KConst <T >): KExpr <T > = cacheIfNeed(expr) {
427476 this @KCvc5Context.addDeclaration(expr.decl)
428477 uninterpretedSortCollector.collect(expr.decl)
429- this @KCvc5Context.savePreviouslyInternalizedExpr (expr)
478+ saveInternalizedExprToCurrentAccumulatedScope (expr)
430479 }
431480
432481 override fun <A : KArraySortBase <R >, R : KSort > transform (expr : KFunctionAsArray <A , R >): KExpr <A > =
@@ -446,7 +495,7 @@ class KCvc5Context(
446495
447496 override fun transform (expr : KUniversalQuantifier ): KExpr <KBoolSort > = cacheIfNeed(expr) {
448497 transformQuantifier(expr.bounds.toSet(), expr.body)
449- this @KCvc5Context.savePreviouslyInternalizedExpr (expr)
498+ saveInternalizedExprToCurrentAccumulatedScope (expr)
450499 }
451500
452501 private fun transformQuantifier (bounds : Set <KDecl <* >>, body : KExpr <* >) {
@@ -455,11 +504,11 @@ class KCvc5Context(
455504 }
456505
457506 private fun <S : KSort , E : KExpr <S >> cacheIfNeed (expr : E , transform : E .() -> Unit ): KExpr <S > {
458- if (expr in currentScopeExpressions )
507+ if (expr in currentAccumulatedScopeExpressions )
459508 return expr
460509
461510 expr.transform()
462- this @KCvc5Context.savePreviouslyInternalizedExpr (expr)
511+ saveInternalizedExprToCurrentAccumulatedScope (expr)
463512 return expr
464513 }
465514 }
0 commit comments