Skip to content

Commit 68c549b

Browse files
Refresh existential claim variables (#1910)
* Add test/issue-1909 * deriveWith: Refresh existential variables * removeDestination: refresh claim at beginning Modifying the right-hand side of the claim at the end of deriveWith does not have the intended effect because the right-hand side of the claim is eventually replaced by the transition rule, which assumes that the right-hand side never changes. Co-authored-by: ana-pantilie <[email protected]>
1 parent 4066d2c commit 68c549b

File tree

7 files changed

+127
-29
lines changed

7 files changed

+127
-29
lines changed

kore/src/Kore/Step/RulePattern.hs

+53-19
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,30 @@ rhsSubstitute subst RHS { existentials, right, ensures } =
407407
where
408408
subst' = foldr (Map.delete . inject . variableName) subst existentials
409409

410+
renameExistentials
411+
:: forall variable
412+
. HasCallStack
413+
=> InternalVariable variable
414+
=> Map (SomeVariableName variable) (SomeVariable variable)
415+
-> RHS variable
416+
-> RHS variable
417+
renameExistentials rename RHS { existentials, right, ensures } =
418+
RHS
419+
{ existentials =
420+
renameVariable <$> existentials
421+
, right = TermLike.substitute subst right
422+
, ensures = Predicate.substitute subst ensures
423+
}
424+
where
425+
renameVariable
426+
:: ElementVariable variable
427+
-> ElementVariable variable
428+
renameVariable var =
429+
let name = SomeVariableNameElement . variableName $ var
430+
in maybe var expectElementVariable
431+
$ Map.lookup name rename
432+
subst = TermLike.mkVar <$> rename
433+
410434
rhsForgetSimplified :: InternalVariable variable => RHS variable -> RHS variable
411435
rhsForgetSimplified RHS { existentials, right, ensures } =
412436
RHS
@@ -871,26 +895,36 @@ instance UnifyingRule RulePattern where
871895

872896
precondition = requires
873897

874-
refreshRule avoid' rule1@(RulePattern _ _ _ _ _) =
875-
let avoid = FreeVariables.toNames avoid'
876-
rename = refreshVariables (avoid <> exVars) originalFreeVariables
877-
subst = TermLike.mkVar <$> rename
878-
left' = TermLike.substitute subst left
879-
antiLeft' = TermLike.substitute subst <$> antiLeft
880-
requires' = Predicate.substitute subst requires
881-
rhs' = rhsSubstitute subst rhs
882-
rule2 =
883-
rule1
884-
{ left = left'
885-
, antiLeft = antiLeft'
886-
, requires = requires'
887-
, rhs = rhs'
888-
}
889-
in (rename, rule2)
898+
refreshRule stale0' rule0@(RulePattern _ _ _ _ _) =
899+
let stale0 = FreeVariables.toNames stale0'
900+
freeVariables0 = freeVariables rule0
901+
renaming1 =
902+
refreshVariables stale0
903+
$ FreeVariables.toSet freeVariables0
904+
freeVariables1 =
905+
FreeVariables.toSet freeVariables0
906+
& Set.map (renameVariable renaming1)
907+
& foldMap FreeVariables.freeVariable
908+
existentials0 = Set.fromList . map inject $ existentials $ rhs rule0
909+
stale1 = FreeVariables.toNames freeVariables1 <> stale0
910+
renamingExists = refreshVariables stale1 existentials0
911+
subst = TermLike.mkVar <$> renaming1
912+
rule1 =
913+
RulePattern
914+
{ left = left rule0 & TermLike.substitute subst
915+
, antiLeft = antiLeft rule0 & fmap (TermLike.substitute subst)
916+
, requires = requires rule0 & Predicate.substitute subst
917+
, rhs =
918+
rhs rule0
919+
& renameExistentials renamingExists
920+
& rhsSubstitute subst
921+
, attributes = attributes rule0
922+
}
923+
in (renaming1, rule1)
890924
where
891-
RulePattern { left, antiLeft, requires, rhs } = rule1
892-
exVars = Set.fromList $ inject . variableName <$> existentials rhs
893-
originalFreeVariables = freeVariables rule1 & FreeVariables.toSet
925+
renameVariable map' var =
926+
Map.lookup (variableName var) map'
927+
& fromMaybe var
894928

895929
mapRuleVariables adj rule1@(RulePattern _ _ _ _ _) =
896930
rule1

kore/src/Kore/Strategies/Goal.hs

+9-6
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,7 @@ removeDestination lensRulePattern mkState goal =
808808
removeDestinationWorker
809809
:: RulePattern VariableName
810810
-> m (ProofState goal (RulePattern VariableName))
811-
removeDestinationWorker rulePattern =
811+
removeDestinationWorker (snd . Step.refreshRule mempty -> rulePattern) =
812812
do
813813
removal <- removalPatterns destination configuration existentials
814814
when (isTop removal) (succeed . mkState $ rulePattern)
@@ -902,11 +902,14 @@ deriveWith
902902
-> goal
903903
-> Strategy.TransitionT (Rule goal) m (ProofState goal goal)
904904
deriveWith lensRulePattern mkRule takeStep rewrites goal =
905-
(\x -> getCompose $ x goal)
906-
$ Lens.traverseOf (lensRulePattern . RulePattern.leftPattern)
907-
$ \config -> Compose $ withConfiguration config $ do
908-
results <- takeStep rewrites config & lift
909-
deriveResults mkRule results
905+
getCompose
906+
$ Lens.forOf lensRulePattern goal
907+
$ \rulePattern ->
908+
fmap (snd . Step.refreshRule mempty)
909+
$ Lens.forOf RulePattern.leftPattern rulePattern
910+
$ \config -> Compose $ withConfiguration config $ do
911+
results <- takeStep rewrites config & lift
912+
deriveResults mkRule results
910913

911914
-- | Apply 'Rule's to the goal in sequence.
912915
deriveSeq

kore/test/Test/Kore/Step/RulePattern.hs

+24-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module Test.Kore.Step.RulePattern
22
( test_freeVariables
3-
, test_refreshRulePattern
3+
, test_refreshRule
44
) where
55

66
import Prelude.Kore
@@ -32,9 +32,9 @@ test_freeVariables =
3232
actual = freeVariables testRulePattern
3333
assertEqual "Expected free variables" expect actual
3434

35-
test_refreshRulePattern :: TestTree
36-
test_refreshRulePattern =
37-
testCase "Rename target variables" $ do
35+
test_refreshRule :: [TestTree]
36+
test_refreshRule =
37+
[ testCase "Rename target variables" $ do
3838
let avoiding :: FreeVariables VariableName
3939
avoiding = freeVariables testRulePattern
4040
(renaming, rulePattern') =
@@ -54,6 +54,26 @@ test_refreshRulePattern =
5454
assertBool
5555
"Expected no free variables in common with original RulePattern"
5656
(all notAvoided (FreeVariables.toList free'))
57+
, testCase "no stale variables" $ do
58+
let (renaming, _) = refreshRule mempty testRulePattern
59+
assertBool "expected not to rename variables" (null renaming)
60+
, testGroup "stale existentials" $
61+
let assertions (renaming, RulePattern { rhs }) = do
62+
assertBool "expected to refresh existentials"
63+
(notElem Mock.y $ existentials rhs)
64+
assertBool "expected to substitute fresh variables"
65+
((/=) (mkElemVar Mock.y) $ right rhs)
66+
assertBool "expected not to rename free variables"
67+
(null renaming)
68+
in
69+
[ testCase "from outside" $ do
70+
let stale = freeVariable (inject Mock.y)
71+
assertions $ refreshRule stale testRulePattern
72+
, testCase "from left-hand side" $ do
73+
let input = testRulePattern { left = mkElemVar Mock.y }
74+
assertions $ refreshRule mempty input
75+
]
76+
]
5777

5878
testRulePattern :: RulePattern VariableName
5979
testRulePattern =

test/issue-1909/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include $(CURDIR)/../include.mk

test/issue-1909/sum-spec.k

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module VERIFICATION
2+
imports TEST
3+
endmodule
4+
5+
module SUM-SPEC
6+
import VERIFICATION
7+
8+
rule <k> loop(N:Int) => . ...</k>
9+
<counter> C:Int => ?_ </counter>
10+
<sum> S:Int => ?S:Int </sum>
11+
requires
12+
N >=Int 0
13+
ensures
14+
?S ==Int S +Int N *Int C +Int (N -Int 1) *Int N /Int 2
15+
endmodule

test/issue-1909/sum-spec.k.out.golden

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#True

test/issue-1909/test.k

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright (c) 2020 K Team. All Rights Reserved.
2+
3+
module TEST-SYNTAX
4+
imports INT
5+
6+
syntax Pgm ::= loop ( Int )
7+
endmodule
8+
9+
module TEST
10+
imports TEST-SYNTAX
11+
12+
configuration
13+
<k> $PGM:Pgm </k>
14+
<counter> 1 </counter>
15+
<sum> 0 </sum>
16+
17+
rule
18+
<k> loop(0) => . ... </k>
19+
rule
20+
<k> loop(Times:Int => Times -Int 1) ...</k>
21+
<counter> C:Int => C +Int 1 </counter>
22+
<sum> S:Int => S +Int C </sum>
23+
requires Times >Int 0
24+
endmodule

0 commit comments

Comments
 (0)