Skip to content

Commit d14a703

Browse files
authored
Merge pull request #524 from jwkai/condqp-skolem-fn
Add Skolem functions to QP framing axioms
2 parents 098c706 + 686b4c3 commit d14a703

1 file changed

Lines changed: 28 additions & 8 deletions

File tree

src/main/scala/viper/carbon/modules/impls/DefaultFuncPredModule.scala

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ with DefinednessComponent with ExhaleComponent with InhaleComponent {
7575
private val resultName = Identifier("Result")
7676
private val insidePredicateName = Identifier("InsidePredicate")
7777

78+
private val qpCondPostfix = "#condqp"
7879
private var qpPrecondId = 0
7980
private var qpCondFuncs: ListBuffer[(Func,sil.Forall)] = new ListBuffer[(Func, sil.Forall)]();
8081

@@ -539,7 +540,7 @@ with DefinednessComponent with ExhaleComponent with InhaleComponent {
539540
case QuantifiedPermissionAssertion(forall, _, _ : sil.AccessPredicate) => // works the same for fields and predicates
540541
qpPrecondId = qpPrecondId+1
541542
val heap = heapModule.staticStateContributions(true, true)
542-
val condName = Identifier(name + "#condqp" +qpPrecondId.toString)
543+
val condName = Identifier(name + qpCondPostfix + qpPrecondId.toString)
543544
val condFunc = Func(condName, heap++args,Int)
544545
val res = (condFunc, forall)
545546
qpCondFuncs += res
@@ -599,16 +600,35 @@ with DefinednessComponent with ExhaleComponent with InhaleComponent {
599600

600601
val funApp2 = FuncApp(condFunc.name, (heap2++origArgs) map (_.l), condFunc.typ)
601602

602-
val triggers = if (locationAccess.exists(lvds.toSet)) Seq(Trigger(Seq(locationAccess1,locationAccess2))) else Seq() // TODO: we could (also in general) raise an error/warning if the tools fail to find triggers
603+
// Pair each quantified variable with a Skolem function on condFunc applications (rather than all condFunc params)
604+
// This shares witness variables for term equalities, resulting in fewer evaluated heap accesses in framing proofs
605+
val lvsToSkFunctions: Seq[(LocalVar, Func)] = vsFresh.map(vFresh => {
606+
val lvd = translateLocalVarDecl(vFresh)
607+
(lvd.l,
608+
Func(Identifier(env.uniqueName("sk_" + condFunc.name.name)),
609+
Seq(LocalVarDecl(Identifier(env.uniqueName("fnAppH1")), condFunc.typ),
610+
LocalVarDecl(Identifier(env.uniqueName("fnAppH2")), condFunc.typ)),
611+
lvd.typ))
612+
})
613+
val skSubs = lvsToSkFunctions.map(lvSkPair =>
614+
(lvSkPair._1, FuncApp(lvSkPair._2.name, Seq(funApp1, funApp2), lvSkPair._2.typ)))
615+
616+
// Replace quantified index variables with Skolem functions in extensional equality on heap locations
617+
val extEq = (translatedCond1 <==> translatedCond2) && (translatedCond1 ==> (locationAccess1 === locationAccess2))
618+
val skExtEq = skSubs.foldLeft(extEq)((body, skSub) => body.replace(skSub._1, skSub._2))
603619

604620
val res = CommentedDecl("Function used for framing of quantified permission " + qp.toString + " in " + originalName,
605621
condFunc ++
606-
Axiom(
607-
Forall(heap1 ++ heap2 ++ origArgs, Seq(Trigger(Seq(funApp1, funApp2, heapModule.successorHeapState(heap1,heap2)))),
608-
(Forall(vsFresh.map(vFresh => translateLocalVarDecl(vFresh)), triggers,
609-
(translatedCond1 <==> translatedCond2) && (translatedCond1 ==> (locationAccess1 === locationAccess2))) ==> (funApp1 === funApp2))
610-
))
611-
);
622+
lvsToSkFunctions.map(_._2) ++
623+
Axiom(
624+
Forall(
625+
heap1 ++ heap2 ++ origArgs,
626+
Seq(Trigger(Seq(funApp1, funApp2, heapModule.successorHeapState(heap1,heap2)))),
627+
skExtEq ==> (funApp1 === funApp2)
628+
)
629+
)
630+
)
631+
612632
vsFresh.foreach(vFresh => env.undefine(vFresh.localVar))
613633
stateModule.replaceState(curState)
614634
res

0 commit comments

Comments
 (0)