|
| 1 | +{-@ LIQUID "--reflection" @-} |
| 2 | +{-@ LIQUID "--ple" @-} |
| 3 | +{-@ LIQUID "--diff" @-} |
| 4 | +{- LIQUID "--short-names" @-} |
| 5 | +{-@ infixr ++ @-} -- TODO: Silly to have to rewrite this annotation! |
| 6 | +{-@ infixr <~ @-} -- TODO: Silly to have to rewrite this annotation! |
| 7 | + |
| 8 | +-------------------------------------------------------------------------------- |
| 9 | +-- | Inspired by |
| 10 | +-- http://flint.cs.yale.edu/cs428/coq/sf/Hoare.html |
| 11 | +-- http://flint.cs.yale.edu/cs428/coq/sf/Hoare2.html |
| 12 | +-------------------------------------------------------------------------------- |
| 13 | + |
| 14 | +{-# LANGUAGE GADTs #-} |
| 15 | + |
| 16 | +module Axiomatic where |
| 17 | + |
| 18 | +import Prelude hiding ((++)) |
| 19 | +import ProofCombinators |
| 20 | +import qualified State as S |
| 21 | +import Expressions |
| 22 | +import Imp |
| 23 | +import BigStep hiding (And) |
| 24 | + |
| 25 | +-------------------------------------------------------------------------------- |
| 26 | +{- | A Floyd-Hoare triple is of the form |
| 27 | +
|
| 28 | + { P } c { Q } |
| 29 | +
|
| 30 | + where |
| 31 | + |
| 32 | + - `P` and `Q` are assertions (think `BExp`) and |
| 33 | + - `c` is a command (think `Com`) |
| 34 | + |
| 35 | + A Floyd-Hoare triple states that |
| 36 | +
|
| 37 | + IF |
| 38 | +
|
| 39 | + * The program `c` is starts at a state where the *precondition* `P` is True, and |
| 40 | + * The program finishes execution |
| 41 | +
|
| 42 | + THEN |
| 43 | +
|
| 44 | + * At the final state, the *postcondition* `Q` will also evaluate to True. |
| 45 | +
|
| 46 | + -} |
| 47 | + |
| 48 | +{- | Lets paraphrase the following Hoare triples in English. |
| 49 | +
|
| 50 | + 1) {True} c {X = 5} |
| 51 | +
|
| 52 | + 2) {X = m} c {X = m + 5} |
| 53 | +
|
| 54 | + 3) {X <= Y} c {Y <= X} |
| 55 | +
|
| 56 | + 4) {True} c {False} |
| 57 | +
|
| 58 | +-} |
| 59 | + |
| 60 | + |
| 61 | +-------------------------------------------------------------------------------- |
| 62 | +-- | The type `Assertion` formalizes the type for the |
| 63 | +-- assertions (i.e. pre- and post-conditions) `P`, `Q` |
| 64 | +-- appearing in the triples {P} c {Q} |
| 65 | + |
| 66 | +type Assertion = BExp |
| 67 | + |
| 68 | +-------------------------------------------------------------------------------- |
| 69 | + |
| 70 | +-------------------------------------------------------------------------------- |
| 71 | +{- | Legitimate Triples |
| 72 | +-------------------------------------------------------------------------------- |
| 73 | +
|
| 74 | +Which of the following triples are "legit" i.e., the claimed relation between |
| 75 | +`pre`condition` `P`, `com`mand `C`, and `post`condition `Q` is true? |
| 76 | +
|
| 77 | + 1) {True} |
| 78 | + X <~ 5 |
| 79 | + {X = 5} |
| 80 | +
|
| 81 | + 2) {X = 2} |
| 82 | + X <~ X + 1 |
| 83 | + {X = 3} |
| 84 | +
|
| 85 | + 3) {True} |
| 86 | + X <~ 5; |
| 87 | + Y <~ 0 |
| 88 | + {X = 5} |
| 89 | +
|
| 90 | + 4) {True} |
| 91 | + X <~ 5; |
| 92 | + Y <~ X |
| 93 | + {Y = 5} |
| 94 | +
|
| 95 | + 5) {X = 2 && X = 3} |
| 96 | + X <~ 5 |
| 97 | + {X = 0} |
| 98 | +
|
| 99 | + 6) {True} |
| 100 | + SKIP |
| 101 | + {False} |
| 102 | +
|
| 103 | + 7) {False} |
| 104 | + SKIP |
| 105 | + {True} |
| 106 | +
|
| 107 | + 8) {True} |
| 108 | + WHILE True DO |
| 109 | + SKIP |
| 110 | + {False} |
| 111 | +
|
| 112 | + 9) {X = 0} |
| 113 | + WHILE X <= 0 DO |
| 114 | + X <~ X + 1 |
| 115 | + {X = 1} |
| 116 | +
|
| 117 | + 10) {X = 1} |
| 118 | + WHILE not (X <= 0) DO |
| 119 | + X <~ X + 1 |
| 120 | + {X = 100} |
| 121 | + -} |
| 122 | + |
| 123 | +-------------------------------------------------------------------------------- |
| 124 | +-- | `Legit` formalizes the notion of when a Floyd-Hoare triple is legitimate |
| 125 | +-------------------------------------------------------------------------------- |
| 126 | +{-@ type Legit P C Q = s:{State | bval P s} |
| 127 | + -> s':_ -> Prop (BStep C s s') |
| 128 | + -> {bval Q s'} |
| 129 | + @-} |
| 130 | +type Legit = State -> State -> BStep -> Proof |
| 131 | + |
| 132 | +-- | {True} X <~ 5 {X = 5} --------------------------------------------------- |
| 133 | + |
| 134 | +{-@ leg1 :: Legit tt (Assign {"x"} (N 5)) (Equal (V {"x"}) (N 5)) @-} |
| 135 | +leg1 :: Legit |
| 136 | +leg1 s s' (BAssign {}) |
| 137 | + = S.lemma_get_set "x" 5 s |
| 138 | + |
| 139 | + |
| 140 | +-- | {True} X <~ 5; y <- X {X = 5} ------------------------------------------- |
| 141 | + |
| 142 | +{-@ leg3 :: Legit tt (Seq (Assign {"x"} (N 5)) (Assign {"y"} (V {"x"}))) (Equal (V {"y"}) (N 5)) @-} |
| 143 | +leg3 :: Legit |
| 144 | +leg3 s s' (BSeq _ _ _ smid _ (BAssign {}) (BAssign {})) |
| 145 | + = S.lemma_get_set "x" 5 s &&& S.lemma_get_set "y" 5 smid |
| 146 | + |
| 147 | + |
| 148 | +-- | {False} X <~ 5 {X = 0} -------------------------------------------------- |
| 149 | + |
| 150 | +{-@ leg5 :: Legit ff (Assign {"x"} (N 5)) (Equal (V {"x"}) (N 22)) @-} |
| 151 | +leg5 :: Legit |
| 152 | +leg5 s s' _ = () |
| 153 | + |
| 154 | + |
| 155 | +-------------------------------------------------------------------------------- |
| 156 | +-- | Two simple facts about Floyd-Hoare Triples -------------------------------- |
| 157 | +-------------------------------------------------------------------------------- |
| 158 | + |
| 159 | +{-@ lem_post_true :: p:_ -> c:_ -> Legit p c tt @-} |
| 160 | +lem_post_true :: Assertion -> Com -> Legit |
| 161 | +lem_post_true p c = \s s' c_s_s' -> () |
| 162 | + |
| 163 | +{-@ lem_pre_false :: c:_ -> q:_ -> Legit ff c q @-} |
| 164 | +lem_pre_false :: Com -> Assertion -> Legit |
| 165 | +lem_pre_false c q = \s s' c_s_s' -> () |
| 166 | + |
| 167 | + |
| 168 | +-- | Assignment |
| 169 | + |
| 170 | +-- { Y = 1 } X <~ Y { X = 1 } |
| 171 | + |
| 172 | +-- { X + Y = 1 } X <~ X + Y { X = 1 } |
| 173 | + |
| 174 | +-- { a = 1 } X <~ a { X = 1 } |
| 175 | + |
| 176 | + |
| 177 | +{- | Lets fill in the blanks |
| 178 | +
|
| 179 | + { ??? } |
| 180 | + x <~ 3 |
| 181 | + { x == 3 } |
| 182 | +
|
| 183 | + { ??? } |
| 184 | + x <~ x + 1 |
| 185 | + { x <= 5 } |
| 186 | +
|
| 187 | + { ??? } |
| 188 | + x <~ y + 1 |
| 189 | + { 0 <= x && x <= 5 } |
| 190 | +
|
| 191 | + -} |
| 192 | + |
| 193 | + |
| 194 | +{- | To conclude that an arbitrary postcondition `Q` holds after |
| 195 | + `x <~ a`, we need to assume that Q holds before `x <~ a` |
| 196 | + but with all occurrences of `x` replaced by `a` in `Q` |
| 197 | +
|
| 198 | + Lets revisit the example above: |
| 199 | +
|
| 200 | + { ??? } |
| 201 | + x <~ 3 |
| 202 | + { x == 3 } |
| 203 | +
|
| 204 | + { ??? } |
| 205 | + x <~ x + 1 |
| 206 | + { x <= 5 } |
| 207 | +
|
| 208 | + { ??? } |
| 209 | + x <~ y + 1 |
| 210 | + { 0 <= x && x <= 5 } |
| 211 | +
|
| 212 | + -} |
| 213 | + |
| 214 | +-------------------------------------------------------------------------------- |
| 215 | +-- | `Valid`ity of an assertion |
| 216 | +-------------------------------------------------------------------------------- |
| 217 | + |
| 218 | + |
| 219 | +-- forall s. bval P s == True |
| 220 | +{-@ type Valid P = s:State -> { v: Proof | bval P s } @-} |
| 221 | +type Valid = State -> Proof |
| 222 | + |
| 223 | +-- x >= 0 || x < 0 |
| 224 | + |
| 225 | +{-@ checkValid :: p:_ -> Valid p -> () @-} |
| 226 | +checkValid :: Assertion -> Valid -> () |
| 227 | +checkValid p v = () |
| 228 | + |
| 229 | +-- x <= 0 |
| 230 | +ex0 = checkValid (e0 `bImp` e1) (\_ -> ()) |
| 231 | + where |
| 232 | + e0 = (V "x") `Leq` (N 0) |
| 233 | + e1 = ((V "x") `Minus` (N 1)) `Leq` (N 0) |
| 234 | + |
| 235 | +-- x <= 0 => x - 1 <= 0 |
| 236 | +-- e1 = e0 `bImp` ((V "x" `Minus` N 1) `Leq` (N 0)) |
| 237 | + |
| 238 | +-------------------------------------------------------------------------------- |
| 239 | +-- | When does an assertion `Imply` another |
| 240 | +-------------------------------------------------------------------------------- |
| 241 | + |
| 242 | +{-@ type Imply P Q = Valid (bImp P Q) @-} |
| 243 | + |
| 244 | +-- 10 <= x => 5 <= x |
| 245 | +{-@ v1 :: _ -> Imply (Leq (N 10) (V {"x"})) (Leq (N 5) (V {"x"})) @-} |
| 246 | +v1 :: a -> Valid |
| 247 | +v1 _ = \_ -> () |
| 248 | + |
| 249 | +-- (0 < x && 0 < y) ===> (0 < x + y) |
| 250 | +{-@ v2 :: _ -> Imply (bAnd (Leq (N 0) (V {"x"})) (Leq (N 0) (V {"y"}))) |
| 251 | + (Leq (N 0) (Plus (V {"x"}) (V {"y"}))) |
| 252 | + @-} |
| 253 | +v2 :: a -> Valid |
| 254 | +v2 _ = \_ -> () |
| 255 | + |
| 256 | +-------------------------------------------------------------------------------- |
| 257 | +-- | The Floyd-Hoare proof system |
| 258 | +-------------------------------------------------------------------------------- |
| 259 | + |
| 260 | +data FHP where |
| 261 | + FH :: Assertion -> Com -> Assertion -> FHP |
| 262 | + |
| 263 | +data FH where |
| 264 | + FHSkip :: Assertion -> FH |
| 265 | + FHAssign :: Assertion -> Vname -> AExp -> FH |
| 266 | + FHSeq :: Assertion -> Com -> Assertion -> Com -> Assertion -> FH -> FH -> FH |
| 267 | + FHIf :: Assertion -> Assertion -> BExp -> Com -> Com -> FH -> FH -> FH |
| 268 | + FHWhile :: Assertion -> BExp -> Com -> FH -> FH |
| 269 | + FHConPre :: Assertion -> Assertion -> Assertion -> Com -> Valid -> FH -> FH |
| 270 | + FHConPost :: Assertion -> Assertion -> Assertion -> Com -> FH -> Valid -> FH |
| 271 | + |
| 272 | +{-@ data FH where |
| 273 | + FHSkip :: p:_ |
| 274 | + -> Prop (FH p Skip p) |
| 275 | + | FHAssign :: q:_ -> x:_ -> a:_ |
| 276 | + -> Prop (FH (bsubst x a q) (Assign x a) q) |
| 277 | + | FHSeq :: p:_ -> c1:_ -> q:_ -> c2:_ -> r:_ |
| 278 | + -> Prop (FH p c1 q) |
| 279 | + -> Prop (FH q c2 r) |
| 280 | + -> Prop (FH p (Seq c1 c2) r) |
| 281 | + | FHIf :: p:_ -> q:_ -> b:_ -> c1:_ -> c2:_ |
| 282 | + -> Prop (FH (bAnd p b) c1 q) |
| 283 | + -> Prop (FH (bAnd p (Not b)) c2 q) |
| 284 | + -> Prop (FH p (If b c1 c2) q) |
| 285 | + | FHWhile :: inv:_ -> b:_ -> c:_ |
| 286 | + -> Prop (FH (bAnd inv b) c inv) |
| 287 | + -> Prop (FH inv (While b c) (bAnd inv (Not b))) |
| 288 | + | FHConPre :: p':_ -> p:_ -> q:_ -> c:_ |
| 289 | + -> Imply p' p |
| 290 | + -> Prop (FH p c q) |
| 291 | + -> Prop (FH p' c q) |
| 292 | + | FHConPost :: p:_ -> q:_ -> q':_ -> c:_ |
| 293 | + -> Prop (FH p c q) |
| 294 | + -> Imply q q' |
| 295 | + -> Prop (FH p c q') |
| 296 | + @-} |
| 297 | + |
| 298 | +-------------------------------------------------------------------------------- |
| 299 | +-- | THEOREM: Soundness of Floyd-Hoare Logic |
| 300 | +-------------------------------------------------------------------------------- |
| 301 | +-- thm_fh_legit :: p:_ -> c:_ -> q:_ -> Prop (FH p c q) -> Legit p c q |
| 302 | + |
| 303 | +-- thm_legit_fh :: p:_ -> c:_ -> q:_ -> Legit p c q -> Prop (FH p c q) |
| 304 | + |
| 305 | + |
| 306 | +-------------------------------------------------------------------------------- |
| 307 | +-- | Making FH Algorithmic: Verification Conditions |
| 308 | +-------------------------------------------------------------------------------- |
| 309 | +data ICom |
| 310 | + = ISkip -- skip |
| 311 | + | IAssign Vname AExp -- x := a |
| 312 | + | ISeq ICom ICom -- c1; c2 |
| 313 | + | IIf BExp ICom ICom -- if b then c1 else c2 |
| 314 | + | IWhile Assertion BExp ICom -- while {I} b c |
| 315 | + deriving (Show) |
| 316 | + |
| 317 | +{-@ reflect pre @-} |
| 318 | +pre :: ICom -> Assertion -> Assertion |
| 319 | +pre ISkip q = q |
| 320 | +pre (IAssign x a) q = bsubst x a q |
| 321 | +pre (ISeq c1 c2) q = pre c1 (pre c2 q) |
| 322 | +pre (IIf b c1 c2) q = bIte b (pre c1 q) (pre c2 q) |
| 323 | +pre (IWhile i _ _) _ = i |
| 324 | + |
| 325 | + |
| 326 | + |
| 327 | + |
| 328 | +{-@ reflect vc @-} |
| 329 | +vc :: ICom -> Assertion -> Assertion |
| 330 | +vc ISkip _ = tt |
| 331 | +vc (IAssign {}) _ = tt |
| 332 | +vc (ISeq c1 c2) q = (vc c1 (pre c2 q)) `bAnd` (vc c2 q) |
| 333 | +vc (IIf _ c1 c2) q = (vc c1 q) `bAnd` (vc c2 q) |
| 334 | +vc (IWhile i b c) q = ((bAnd i b) `bImp` (pre c i)) `bAnd` -- { i && b} c { i } |
| 335 | + ((bAnd i (Not b)) `bImp` q ) `bAnd` -- { i & ~b} => Q |
| 336 | + vc c i |
| 337 | + |
| 338 | +{-@ reflect erase @-} |
| 339 | +erase :: ICom -> Com |
| 340 | +erase ISkip = Skip |
| 341 | +erase (IAssign x a) = Assign x a |
| 342 | +erase (ISeq c1 c2) = Seq (erase c1) (erase c2) |
| 343 | +erase (IIf b c1 c2) = If b (erase c1) (erase c2) |
| 344 | +erase (IWhile _ b c) = While b (erase c) |
| 345 | + |
| 346 | +----------------------------------------------------------------------------------- |
| 347 | +-- | THEOREM: Soundness of VC |
| 348 | +----------------------------------------------------------------------------------- |
| 349 | +-- thm_vc :: c:_ -> q:_ -> Valid (vc c q) -> Legit (pre c q) (erase c) q |
| 350 | + |
| 351 | +----------------------------------------------------------------------------------- |
| 352 | +-- | Extending the above to triples [HW] |
| 353 | +----------------------------------------------------------------------------------- |
| 354 | + |
| 355 | +{-@ reflect vc' @-} |
| 356 | +vc' :: Assertion -> ICom -> Assertion -> Assertion |
| 357 | +vc' p c q = bAnd (bImp p (pre c q)) (vc c q) |
| 358 | + |
| 359 | +----------------------------------------------------------------------------------- |
| 360 | +-- | THEOREM: Soundness of VC' |
| 361 | +----------------------------------------------------------------------------------- |
| 362 | +-- thm_vc' :: p:_ -> c:_ -> q:_ -> Valid (vc' p c q) -> Legit p (erase c) q |
| 363 | + |
| 364 | + |
0 commit comments