@@ -32,10 +32,13 @@ case class InverseFunctions(condition: Term,
3232 additionalArguments : Vector [Var ],
3333 axiomInversesOfInvertibles : Quantification ,
3434 axiomInvertiblesOfInverses : Quantification ,
35- qvarsToInverses : Map [Var , Function ]) {
35+ qvarsToInverses : Map [Var , Function ],
36+ qvarsToImages : Map [Var , Function ]) {
3637
3738 val inverses : Iterable [Function ] = qvarsToInverses.values
3839
40+ val images : Iterable [Function ] = qvarsToImages.values
41+
3942 val definitionalAxioms : Vector [Quantification ] =
4043 Vector (axiomInversesOfInvertibles, axiomInvertiblesOfInverses)
4144
@@ -93,6 +96,8 @@ trait QuantifiedChunkSupport extends SymbolicExecutionRules {
9396 /** Creates `n` fresh (partial) inverse functions `inv_i` that invert an `n`-ary
9497 * function `fct`, where `n == qvars.length`, and returns the inverse functions as
9598 * well as the definitional axioms.
99+ * If the types of the quantified variables could be finite, additionally creates n fresh
100+ * boolean functions `img_i` denoting the domain of the respective inverse functions.
96101 *
97102 * Let
98103 * - `x_1: T_1`, ..., `x_n: T_n` denote the quantified variables (argument `qvars`)
@@ -103,18 +108,21 @@ trait QuantifiedChunkSupport extends SymbolicExecutionRules {
103108 * the partial inverses are defined
104109 *
105110 * The following definitional axioms will be returned, in addition to the fresh
106- * inverse functions `inv_1`, ..., `inv_n`:
111+ * inverse functions `inv_1`, ..., `inv_n` and the respective image functions :
107112 *
108113 * forall x_1: T_1, ..., x_n: T_n :: {fct(x_1, ..., x_n)}
109114 * c(x_1, ..., x_n) ==>
110- * inv_1(fct(x_1, ..., x_n)) == x_1
115+ * inv_1(fct(x_1, ..., x_n)) == x_1 && img_1(fct(x_1, ..., x_n))
111116 * && ...
112- * && inv_n(fct(x_1, ..., x_n)) == x_n
117+ * && inv_n(fct(x_1, ..., x_n)) == x_n && img_n(fct(x_1, ..., x_n))
113118 *
114119 * forall r: R :: {inv_1(r), ..., inv_n(r)}
115- * c(inv_1(r), ..., inv_n(r)) ==>
120+ * c(inv_1(r), ..., inv_n(r)) && img_1(r) && ... && img_n(r) ==>
116121 * fct(inv_1(r), ..., inv_n(r)) == r
117122 *
123+ * For all i where x_i is of type Ref or Int, we do not generate the img_i constraints in
124+ * either axiom, since those types are known to have the same cardinality as Ref.
125+ *
118126 * @param qvars Quantified variables that occur in the invertible function and for
119127 * which partial inverse functions are to be defined..
120128 * @param condition A condition (containing the quantified variables) determining
@@ -125,7 +133,10 @@ trait QuantifiedChunkSupport extends SymbolicExecutionRules {
125133 * @param additionalInvArgs Additional arguments on which `inv` depends (typically
126134 * quantified variables bound by some surrounding scope).
127135 * Currently omitted from the axioms shown above.
128- * @return The generated partial inverse functions and corresponding definitional axioms.
136+ * @return The generated partial inverse functions and corresponding definitional axioms, and
137+ * the images of the given codomain variables (returned separately, since nothing else
138+ * in the returned InverseFunctions object references or contains the codomain
139+ * variables, and thus they only have meaning for the caller).
129140 */
130141 def getFreshInverseFunctions (qvars : Seq [Var ],
131142 condition : Term ,
@@ -135,7 +146,7 @@ trait QuantifiedChunkSupport extends SymbolicExecutionRules {
135146 userProvidedTriggers : Option [Seq [Trigger ]],
136147 qidPrefix : String ,
137148 v : Verifier )
138- : InverseFunctions
149+ : ( InverseFunctions , Seq [ Term ])
139150
140151 def injectivityAxiom (qvars : Seq [Var ],
141152 condition : Term ,
@@ -247,7 +258,7 @@ object quantifiedChunkSupporter extends QuantifiedChunkSupport {
247258 program : ast.Program )
248259 : (QuantifiedBasicChunk , InverseFunctions ) = {
249260
250- val inverseFunctions =
261+ val ( inverseFunctions, imagesOfCodomain) =
251262 getFreshInverseFunctions(
252263 qvars,
253264 And (condition, IsPositive (permissions)),
@@ -262,7 +273,7 @@ object quantifiedChunkSupporter extends QuantifiedChunkSupport {
262273
263274 val conditionalizedPermissions =
264275 Ite (
265- condition.replace(qvarsToInversesOfCodomain),
276+ And ( And (imagesOfCodomain), condition.replace(qvarsToInversesOfCodomain) ),
266277 permissions.replace(qvarsToInversesOfCodomain),
267278 NoPerm ())
268279
@@ -1014,7 +1025,7 @@ object quantifiedChunkSupporter extends QuantifiedChunkSupport {
10141025 (Q : (State , Heap , Term , Verifier ) => VerificationResult )
10151026 : VerificationResult = {
10161027
1017- val inverseFunctions =
1028+ val ( inverseFunctions, imagesOfFormalQVars) =
10181029 quantifiedChunkSupporter.getFreshInverseFunctions(
10191030 qvars,
10201031 And (tCond, IsPositive (tPerm)),
@@ -1124,13 +1135,13 @@ object quantifiedChunkSupporter extends QuantifiedChunkSupport {
11241135 s2,
11251136 relevantChunks,
11261137 formalQVars,
1127- condOfInvOfLoc,
1138+ And ( condOfInvOfLoc, And (imagesOfFormalQVars)) ,
11281139 resource,
11291140 rPerm,
11301141 chunkOrderHeuristics,
11311142 v2)
11321143 val optSmDomainDefinitionCondition2 =
1133- if (s3.smDomainNeeded) Some (And (condOfInvOfLoc, IsPositive (lossOfInvOfLoc)))
1144+ if (s3.smDomainNeeded) Some (And (condOfInvOfLoc, IsPositive (lossOfInvOfLoc), And (imagesOfFormalQVars) ))
11341145 else None
11351146 val (smDef2, smCache2) =
11361147 quantifiedChunkSupporter.summarisingSnapshotMap(
@@ -1170,7 +1181,7 @@ object quantifiedChunkSupporter extends QuantifiedChunkSupport {
11701181 s.copy(smCache = smCache1),
11711182 relevantChunks,
11721183 formalQVars,
1173- condOfInvOfLoc,
1184+ And ( condOfInvOfLoc, And (imagesOfFormalQVars)) ,
11741185 resource,
11751186 lossOfInvOfLoc,
11761187 chunkOrderHeuristics,
@@ -1180,7 +1191,7 @@ object quantifiedChunkSupporter extends QuantifiedChunkSupport {
11801191 case (Complete (), s2, remainingChunks) =>
11811192 val h3 = Heap (remainingChunks ++ otherChunks)
11821193 val optSmDomainDefinitionCondition2 =
1183- if (s2.smDomainNeeded) Some (And (condOfInvOfLoc, IsPositive (lossOfInvOfLoc)))
1194+ if (s2.smDomainNeeded) Some (And (condOfInvOfLoc, IsPositive (lossOfInvOfLoc), And ( And (imagesOfFormalQVars)) ))
11841195 else None
11851196 val (smDef2, smCache2) =
11861197 quantifiedChunkSupporter.summarisingSnapshotMap(
@@ -1577,7 +1588,7 @@ object quantifiedChunkSupporter extends QuantifiedChunkSupport {
15771588 userProvidedTriggers : Option [Seq [Trigger ]],
15781589 qidPrefix : String ,
15791590 v : Verifier )
1580- : InverseFunctions = {
1591+ : ( InverseFunctions , Seq [ Term ]) = {
15811592
15821593 assert(
15831594 invertibles.length == codomainQVars.length,
@@ -1593,6 +1604,9 @@ object quantifiedChunkSupporter extends QuantifiedChunkSupport {
15931604 val qvarsWithIndices = qvars.zipWithIndex
15941605
15951606 val inverseFunctions = Array .ofDim[Function ](qvars.length) /* inv_i */
1607+ val imageFunctions = Array .ofDim[Function ](qvars.length) /* img_i */
1608+ val imagesOfFcts = Array .ofDim[Term ](qvars.length) // /* img_i(f_1(xs), ..., f_m(xs)) */
1609+ val imagesOfCodomains = Array .ofDim[Term ](qvars.length) /* img_i(rs) */
15961610 val inversesOfFcts = Array .ofDim[Term ](qvars.length) /* inv_i(f_1(xs), ..., f_m(xs)) */
15971611 val inversesOfCodomains = Array .ofDim[Term ](qvars.length) /* inv_i(rs) */
15981612
@@ -1603,6 +1617,20 @@ object quantifiedChunkSupporter extends QuantifiedChunkSupport {
16031617 inverseFunctions(idx) = fun
16041618 inversesOfFcts(idx) = inv(invertibles)
16051619 inversesOfCodomains(idx) = inv(codomainQVars)
1620+
1621+ if (qvar.sort != sorts.Int && qvar.sort != sorts.Ref ) {
1622+ // Types known to be infinite, thus there is no need to constrain the domain using image functions.
1623+ val imgFun = v.decider.fresh(" img" , (additionalInvArgs map (_.sort)) ++ invertibles.map(_.sort), sorts.Bool )
1624+ val img = (ts : Seq [Term ]) => App (imgFun, additionalInvArgs ++ ts)
1625+
1626+ imageFunctions(idx) = imgFun
1627+ imagesOfFcts(idx) = img(invertibles)
1628+ imagesOfCodomains(idx) = img(codomainQVars)
1629+ } else {
1630+ // imageFunctions(idx) remains null, will be filtered out later.
1631+ imagesOfFcts(idx) = True ()
1632+ imagesOfCodomains(idx) = True ()
1633+ }
16061634 }
16071635
16081636 /* f_1(inv_1(rs), ..., inv_n(rs)), ..., f_m(inv_1(rs), ..., inv_n(rs)) */
@@ -1614,14 +1642,15 @@ object quantifiedChunkSupporter extends QuantifiedChunkSupport {
16141642 condition.replace(qvars, ArraySeq .unsafeWrapArray(inversesOfCodomains))
16151643
16161644 /* c(xs) ==>
1617- * inv_1(f_1(xs), ..., f_m(xs)) == x_1
1645+ * inv_1(f_1(xs), ..., f_m(xs)) == x_1 && img_1(f_1(xs), ..., f_m(xs)) &&
16181646 * && ...
1619- * && inv_n(f_1(xs), ..., f_m(xs)) == x_n
1647+ * && inv_n(f_1(xs), ..., f_m(xs)) == x_n && img_n(f_1(xs), ..., f_m(xs))
16201648 */
16211649 val axInvsOfFctsBody =
16221650 Implies (
16231651 condition,
1624- And (qvarsWithIndices map { case (qvar, idx) => inversesOfFcts(idx) === qvar }))
1652+ And (And (qvarsWithIndices map { case (qvar, idx) => inversesOfFcts(idx) === qvar }),
1653+ And (qvarsWithIndices map { case (_, idx) => imagesOfFcts(idx) })))
16251654
16261655 val axInvsOfFct =
16271656 userProvidedTriggers match {
@@ -1644,12 +1673,12 @@ object quantifiedChunkSupporter extends QuantifiedChunkSupport {
16441673 s " $qidPrefix-invOfFct " )
16451674 }
16461675
1647- /* c(inv_1(rs), ..., inv_n(rs)) ==>
1676+ /* c(inv_1(rs), ..., inv_n(rs)) && img_1(rs) && ... && img_n(rs) ==>
16481677 * f_1(inv_1(rs), ..., inv_n(rs)) == r_1
16491678 */
16501679 val axFctsOfInvsBody =
16511680 Implies (
1652- conditionOfInverses,
1681+ And ( And (imagesOfCodomains), conditionOfInverses) ,
16531682 And (
16541683 fctsOfInversesOfCodomain
16551684 .zip(codomainQVars)
@@ -1669,13 +1698,16 @@ object quantifiedChunkSupporter extends QuantifiedChunkSupport {
16691698 isGlobal = true ,
16701699 v.axiomRewriter)
16711700
1672- InverseFunctions (
1701+ val res = InverseFunctions (
16731702 condition,
16741703 invertibles,
16751704 additionalInvArgs.toVector,
16761705 axInvsOfFct,
16771706 axFctsOfInvs,
1678- qvars.zip(inverseFunctions).to(Map ))
1707+ qvars.zip(inverseFunctions).to(Map ),
1708+ qvars.zip(imageFunctions).filter(_._2 != null ).to(Map )
1709+ )
1710+ (res, imagesOfCodomains)
16791711 }
16801712
16811713 def hintBasedChunkOrderHeuristic (hints : Seq [Term ])
0 commit comments