1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
|
module SimplifyPostConds
( simplifyPostConditionsWithTheorems)
where
import Control.Monad ( unless, when )
import Data.List ( last, maximum )
import Data.Maybe ( maybeToList )
import AbstractCurry.Types
import AbstractCurry.Select
import AbstractCurry.Build
import Contract.Names
import Rewriting.Files
import Rewriting.Term
import Rewriting.Position
import Rewriting.Substitution
import Rewriting.Rules
simplifyPostConditionsWithTheorems :: Int -> [CFuncDecl] -> [CFuncDecl]
-> IO [CFuncDecl]
simplifyPostConditionsWithTheorems verb theofuncs postconds = do
theoTRS <- mapM safeFromFuncDecl theofuncs >>= return . concat
if null theoTRS
then return postconds
else do
let simprules = concatMap theoremToSimpRules theoTRS ++ standardSimpRules
when (verb>1) $ putStr $ unlines
[ "THEOREMS (with existing proof files):", showTRS snd theoTRS,
"SIMPLIFICATION RULES (for postcondition reduction):"
, showTRS snd simprules]
simppostconds <- mapM (safeSimplifyPostCondition verb simprules) postconds
return (concat simppostconds)
where
safeFromFuncDecl fd =
catch (return $!! (snd (fromFuncDecl fd)))
(\e -> do
putStrLn $ show e ++ "\nTheorem \"" ++
snd (funcName fd) ++
"\" not used for simplification (too complex)."
return [])
safeSimplifyPostCondition :: Int -> TRS QName -> CFuncDecl -> IO [CFuncDecl]
safeSimplifyPostCondition verb simprules fundecl =
catch (simplifyPostCondition verb simprules fundecl)
(\e -> do putStrLn $ show e ++ "\nPostcondition \"" ++
snd (funcName fundecl) ++
"\" not simplified (too complex)."
return [fundecl])
simplifyPostCondition :: Int -> TRS QName -> CFuncDecl -> IO [CFuncDecl]
simplifyPostCondition verb simprules (CFunc qn ar vis texp rs) =
simplifyPostCondition verb simprules (CmtFunc "" qn ar vis texp rs)
simplifyPostCondition verb simprules fdecl@(CmtFunc cmt qn ar vis texp rules) =
if isPostCondName (snd qn)
then do redrules <- mapM (simplifyRule verb simprules qn) rules
return $ if all isTrivial redrules
then []
else [CmtFunc cmt qn ar vis texp redrules]
else return [fdecl]
theoremToSimpRules :: Rule QName -> [Rule QName]
theoremToSimpRules (_, TermVar _) =
error $ "theoremToSimpRules: variable in rhs"
theoremToSimpRules rl@(_, TermCons qf args)
| qf == easyCheck "-=-" || qf == easyCheck "<~>"
= [(TermCons (pre "==") args, trueTerm),
(TermCons (pre "==") (reverse args), trueTerm)]
| qf == easyCheck "always" = [(head args, trueTerm)]
| otherwise = [rl]
where
easyCheck f = ("Test.EasyCheck",f)
isTrivial :: CRule -> Bool
isTrivial (CRule _ rhs) = case rhs of
CSimpleRhs exp [] -> exp == constF (pre "True")
_ -> False
maxSimpSteps :: Int
maxSimpSteps = 100
simplifyRule :: Int -> TRS QName -> QName -> CRule -> IO CRule
simplifyRule verb simprules qn crule@(CRule rpats _) = do
(id $!! (lhs,rhs)) `seq` return ()
unless (null trs) $
error $ "simplifyRule: cannot handle local TRS:\n" ++ showTRS snd trs
when (verb > 1 ) $ putStrLn $ unlines
["POSTCONDITION: " ++ showRule snd (lhs,rhs),
"POSTCONDEXP: " ++ showTerm snd postcondexp,
"SIMPLIFIEDEXP: " ++ showTerm snd simpterm,
"SIMPPOSTCOND: " ++ showRule snd simppostcond ]
return (simpleRule rpats (term2acy (concatMap varsOfPat rpats) simppostrhs))
where
((lhs,rhs),trs) = fromRule qn crule
postcondexp = postCondition2Term lhs rhs
simpterm = simplifyTerm maxSimpSteps simprules postcondexp
simppostrhs = postConditionTermToRule lhs simpterm
simppostcond = (lhs, simppostrhs)
postCondition2Term :: Term QName -> Term QName -> Term QName
postCondition2Term (TermVar _) _ =
error "postCondition2Term: variable term"
postCondition2Term (TermCons (mn,fn) args) rhs =
let TermVar i = last args
fcall = TermCons (mn, fromPostCondName fn)
(take (length args - 1) args)
fcallsubst = extendSubst emptySubst i fcall
in applySubst fcallsubst rhs
postConditionTermToRule :: Term QName -> Term QName -> Term QName
postConditionTermToRule (TermVar _) _ =
error "postConditionTermToRule: variable term"
postConditionTermToRule (TermCons (mn,fn) args) term =
let TermVar i = last args
fcall = TermCons (mn, fromPostCondName fn)
(take (length args - 1) args)
in replaceAllTerms (fcall, TermVar i) term
replaceAllTerms :: Rule QName -> Term QName -> Term QName
replaceAllTerms (lhs,rhs) term =
if null oneStep
then term
else replaceAllTerms (lhs,rhs) (head oneStep)
where
oneStep = [ replaceTerm term p rhs | p <- positions term, (term |> p) == lhs ]
simplifyTerm :: Int -> TRS QName -> Term QName -> Term QName
simplifyTerm maxsteps simprules term =
if null oneStep || maxsteps==0
then term
else simplifyTerm (maxsteps-1) simprules (head oneStep)
where
oneStep = [ replaceTerm term p (applySubst sub rhs)
| p <- positions term,
rule <- simprules,
let vMax = maximum (0: tVars term) + 1,
let (lhs,rhs) = renameRuleVars vMax rule,
sub <- maybeToList (match (term |> p) lhs) ]
match :: Term QName -> Term QName -> Maybe (Subst QName)
match = matchTerm emptySubst
where
matchTerm sub t1 (TermVar i) =
maybe (Just (extendSubst sub i t1))
(\t2 -> matchTerm sub t1 t2)
(lookupSubst sub i)
matchTerm sub (TermCons f1 args1) (TermCons f2 args2) =
if f1 /= f2 then Nothing else matchArgs sub args1 args2
matchTerm _ (TermVar _) (TermCons _ _) = Nothing
matchArgs _ (_:_) [] = Nothing
matchArgs _ [] (_:_) = Nothing
matchArgs sub [] [] = Just sub
matchArgs sub (x:xs) (y:ys) = maybe Nothing
(\s -> matchArgs s xs ys)
(matchTerm sub x y)
standardSimpRules :: TRS QName
standardSimpRules =
[ (TermCons (pre "&&") [trueTerm, x1], x1)
, (TermCons (pre "&&") [x1, trueTerm], x1)
]
where
x1 = TermVar 1
trueTerm :: Term QName
trueTerm = TermCons (pre "True") []
term2acy :: [CVarIName] -> Term QName -> CExpr
term2acy cvars (TermVar i) =
maybe (error "term2acy: cannot find variable")
(\s -> CVar (i,s))
(lookup i cvars)
term2acy cvars (TermCons (mn,fn) args)
| null args && head mn == '%' = CLit (const2literal (tail mn, fn))
| otherwise
= foldl CApply (CSymbol (mn,fn)) (map (term2acy cvars) args)
const2literal :: QName -> CLiteral
const2literal sl = case sl of
("i",s) -> CIntc (read s)
("f",s) -> CFloatc (read s)
("c",s) -> CCharc (head s)
("s",s) -> CStringc s
_ -> error "const2literal: unknown literal"
|