Comments (3)
I mentioned this at some point (maybe to @gsps ?): we should be able to move the mergeCalls
logic into the template generator which would make it much cleaner.
The idea is to change the IfExpr
case in TemplateGenerator.mkExprClauses
. We would change the following lines to call mkExprClauses
recursively and then unify function calls which occur in both branches:
inox/src/main/scala/inox/solvers/unrolling/TemplateGenerator.scala
Lines 370 to 371 in 22de8d6
would become
val (trec, tClauses) = mkExprClauses(newBool1, thenn, localSubst, pol)
val (erec, eClauses) = mkExprClauses(newBool2, elze, localSubst, pol)
builder ++= mergeCalls(pathVar, localSubst, tClauses, eClauses)
The new mergeCalls
logic (inside TemplateGenerator.scala
) would look something like this:
def mergeCalls(pathVar: Variable, condVar: Variable, substMap: Map[Variable, Encoded],
thenClauses: TemplateClauses, elseClauses: TemplateClauses): TemplateClauses = {
val builder = new Builder(pathVar, substMap)
builder ++= thenClauses
builder ++ elseClauses
// Clear all guardedExprs in builder since we're going to transform them by merging calls.
// The transformed guardedExprs will be added to builder at the end of the function.
builder.guardedExprs = Map.empty
def collectCalls(expr: Expr): Set[FunctionInvocation] =
exprOps.collect { case fi: FunctionInvocation => Set(fi) case _ => Set.empty[FunctionInvocation] }(expr)
def countCalls(expr: Expr): Int =
exprOps.count { case fi: FunctionInvocation => 1 case _ => 0}(expr)
def replaceCall(call: FunctionInvocation, newExpr: Expr)(e: Expr): Expr =
exprOps.replace(Map(call, newExpr), e)
def getCalls(guardedExprs: Map[Variable, Seq[Expr]]): Map[TypedFunDef, Seq[(FunctionInvocation, Set[Variable])]] =
(for {(b, es) <- guardedExprs; e <- es; fi <- collectCalls(e)) yield (b -> fi))
.groupBy(_._2)
.mapValues(_.map(_._1).toSet)
.toSeq
.groupBy(_._1.tfd)
.mapValues(_.toList.distinct.sortBy(p => countCalls(p._1))) // place inner calls first
.toMap
var thenGuarded = thenClauses._4
var elseGuarded = elseClauses._4
val thenCalls = getCalls(thenGuarded)
val elseCalls = getCalls(elseGuarded)
// We sort common function calls in order to merge nested calls first.
var toMerge = (thenCalls.keys() & elseCalls.keys())
.flatMap(tfd => thenCalls(tfd) zip elseCalls(tfd))
.toSeq
.sortBy(p => countCalls(p._1._1) + countCalls(p._2._1))
while (toMerge.nonEmpty) {
val ((thenCall, thenBlockers), (elseCall, elseBlockers)) = toMerge.head
toMerge = toMerge.tail
val newExpr: Variable = Variable.fresh("call", thenCall.tfd.getType, true)
builder.storeExpr(newExpr)
val replaceThen = replaceCall(thenCall, newExpr) _
val replaceElse = replaceCall(elseCall, newExpr) _
thenGuarded = thenGuarded.mapValues(_.map(replaceThen)
elseGuarded = elseGuarded.mapValues(_.map(replaceElse)
toMerge = toMerge.map(p => (replaceThen(p._1), replaceElse(p._2))
val newBlocker: Variable = Variable.fresh("bm", BooleanType(), true)
// TODO: make this a method in Builder similar to storeCond
builder.storeConds(thenBlockers ++ elseBlockers, newBlocker)
builder.iff(orJoin((thenBlockers ++ elseBlockers).toSeq), newBlocker)
val newArgs = (thenCall.args zip elseCall.args).map { case (thenArg, elseArg) =>
val (newArg, argClauses) = mkExprClauses(newBlocker, IfExpr(condVar, thenArg, elseArg), builder.localSubst)
builder ++= argClauses
newArg
}
val newCall = thenCall.tfd.applied(newArgs)
builder.storeGuarded(newBlocker, Equals(newExpr, newCall))
}
for ((b, es) <- thenGuarded; e <- es) builder.storeGuarded(b, e)
for ((b, es) <- elseGuarded; e <- es) builder.storeGuarded(b, e)
builder.result
}
from inox.
Should liftCalls
remain?
from inox.
No, I think it shouldn't be necessary.
from inox.
Related Issues (20)
- Key not found exception on Stainless test case with extern method with quantifiers HOT 9
- Parse error with CVC4 1.8 HOT 3
- Retrieving defunctionalized string? HOT 1
- NullPointerException with solvers option HOT 1
- Unsat file reported as SAT HOT 2
- Error in documentation when compiling HOT 6
- Inox error when using set.toList in Stainless HOT 3
- Lookup failure in Definitions.scala (line 197), for apply. HOT 4
- Choose under lamba HOT 13
- Missing support for str.++
- Key not found error when using --debug=tip from Stainless HOT 3
- Mismatch between hasInstance and simplestValue HOT 6
- Integration of `rust-interop` in `master`
- Type error in tip printed from Stainless HOT 2
- ChooseEncoder doesn't transform all the trees
- Underapproximate unfolding
- StackOverflowError on an equivalence checking example
- Enable reading smt-lib files with dependent types for future text interface from Stainless
- Migrate to Scala 3.2 HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from inox.