module HoareLogic.Case {S V : Set} where
open import DynamicallyChecked.Utilities
open import DynamicallyChecked.Partiality
open import DynamicallyChecked.Lens
open import DynamicallyChecked.Case S V
open import HoareLogic.Semantics
open import Level
open import Function
open import Data.Bool
open import Data.Product as Product hiding (,_)
open import Data.Sum
open import Data.List as List
open import Relation.Binary.PropositionalEquality
DecCaseDomain : List (S → V → Bool) → ℙ (S × V)
DecCaseDomain [] = ∅
DecCaseDomain (c ∷ cs) = (True ∘ uncurry c) ∪ ((False ∘ uncurry c) ∩ DecCaseDomain cs)
CaseDomain : List (S → V → Bool) → ℙ (S × V)
CaseDomain [] = ∅
CaseDomain (c ∷ cs) = (True ∘ uncurry c) ∪ CaseDomain cs
toDecCaseDomain : (cs : List (S → V → Bool)) → CaseDomain cs ⊆ DecCaseDomain cs
toDecCaseDomain [] ()
toDecCaseDomain (c ∷ cs) (inj₁ c-true) = inj₁ c-true
toDecCaseDomain (c ∷ cs) {s , v} (inj₂ cs-dom) with c s v
toDecCaseDomain (c ∷ cs) (inj₂ cs-dom) | true = inj₁ refl
toDecCaseDomain (c ∷ cs) (inj₂ cs-dom) | false = inj₂ (refl , toDecCaseDomain cs cs-dom)
NormalDecCaseDomain : List ((S → V → Bool) × Bool) → ℙ (S × V)
NormalDecCaseDomain [] = ∅
NormalDecCaseDomain ((c , true ) ∷ bs) = (True ∘ uncurry c) ∪ ((False ∘ uncurry c) ∩ NormalDecCaseDomain bs)
NormalDecCaseDomain ((c , false) ∷ bs) = (False ∘ uncurry c) ∩ NormalDecCaseDomain bs
NormalCaseDomain : List ((S → V → Bool) × Bool) → ℙ (S × V)
NormalCaseDomain [] = ∅
NormalCaseDomain ((c , true ) ∷ bs) = (True ∘ uncurry c) ∪ NormalCaseDomain bs
NormalCaseDomain ((c , false) ∷ bs) = (False ∘ uncurry c) ∩ NormalCaseDomain bs
toNormalDecCaseDomain : (bs : List ((S → V → Bool) × Bool)) → NormalCaseDomain bs ⊆ NormalDecCaseDomain bs
toNormalDecCaseDomain [] ()
toNormalDecCaseDomain ((c , true ) ∷ bs) (inj₁ c-true) = inj₁ c-true
toNormalDecCaseDomain ((c , true ) ∷ bs) {s , v} (inj₂ bs-dom) with c s v
toNormalDecCaseDomain ((c , true ) ∷ bs) (inj₂ bs-dom) | true = inj₁ refl
toNormalDecCaseDomain ((c , true ) ∷ bs) (inj₂ bs-dom) | false = inj₂ (refl , toNormalDecCaseDomain bs bs-dom)
toNormalDecCaseDomain ((c , false) ∷ bs) (c-false , bs-dom) = c-false , toNormalDecCaseDomain bs bs-dom
OutOfDomain : List (S → V → Bool) → ℙ (S × V)
OutOfDomain [] = Π
OutOfDomain (p ∷ ps) = (False ∘ uncurry p) ∩ OutOfDomain ps
OutOfRange : List Branch → ℙ S
OutOfRange [] = Π
OutOfRange ((_ , normal _ q) ∷ bs) = (False ∘ q) ∩ OutOfRange bs
OutOfRange ((_ , adaptive _) ∷ bs) = OutOfRange bs
BranchSound : (R : ℙ (S × V)) (R' : ℙ (S × S × V)) → List Branch → List Branch → ℙ (S × V) → Set₁
BranchSound R R' [] bs' ReentryCond = ⊤
BranchSound R R' ((p , b) ∷ bs) bs' ReentryCond =
let Pre = R ∩ (True ∘ uncurry p) ∩ OutOfDomain (List.map proj₁ bs')
in elimBranchType
(λ l q → Sound Pre (Lens.put l)
(R' ∩ (((True ∘ uncurry p) ∩ OutOfDomain (List.map proj₁ bs')) ∘ Product.map id proj₂) ∩
(((True ∘ q) ∩ OutOfRange bs') ∘ proj₁)))
(λ f → Lift ((s : S) (v : V) → Pre (s , v) →
(R ∩ ReentryCond) (f s v , v) × ((s' : S) → R' (s' , f s v , v) → R' (s' , s , v)))) b ×
BranchSound R R' bs ((p , b) ∷ bs') ReentryCond
inCaseDomain : (bs bs' : List Branch) {s' s : S} {v : V} {cont : S → Par S} →
put-with-adaptation bs bs' s v cont ↦ s' → CaseDomain (List.map proj₁ bs) (s , v)
inCaseDomain [] bs' ()
inCaseDomain ((p , b) ∷ bs) bs' {s = s} {v} c with p s v
inCaseDomain ((p , b) ∷ bs) bs' {s = s} {v} c | false = inj₂ (inCaseDomain bs ((p , b) ∷ bs') c)
inCaseDomain ((p , b) ∷ bs) bs' {s = s} {v} c | true = inj₁ refl
inNormalCaseDomain : (bs bs' : List Branch) {s' s : S} {v : V} →
put-with-adaptation bs bs' s v (const fail) ↦ s' →
NormalCaseDomain (List.map (Product.map id isNormal) bs) (s , v)
inNormalCaseDomain [] bs' ()
inNormalCaseDomain ((p , b) ∷ bs) bs' {s = s} {v} c with p s v | inspect (p s) v
inNormalCaseDomain ((p , normal l q) ∷ bs) bs' {s = s} {v} c
| false | [ p-s-v≡false ] = inj₂ (inNormalCaseDomain bs ((p , normal l q) ∷ bs') c)
inNormalCaseDomain ((p , adaptive f) ∷ bs) bs' {s = s} {v} c
| false | [ p-s-v≡false ] = p-s-v≡false , inNormalCaseDomain bs ((p , adaptive f) ∷ bs') c
inNormalCaseDomain ((p , normal l q) ∷ bs) bs' {s = s} {v} c
| true | [ p-s-v≡true ] = inj₁ p-s-v≡true
inNormalCaseDomain ((p , adaptive f) ∷ bs) bs' {s = s} {v} ()
| true | [ p-s-v≡true ]
check-diversion-success : (bs : List Branch) (s : S) (v : V) →
OutOfDomain (List.map proj₁ bs) (s , v) → OutOfRange bs s → check-diversion bs s v ↦ tt
check-diversion-success [] s v outd outr = return refl
check-diversion-success ((p , normal l q) ∷ bs) s v (p-s-v≡false , outd) (q-s≡false , outr) =
assert-not p-s-v≡false then assert-not q-s≡false then (check-diversion-success bs s v outd outr)
check-diversion-success ((p , adaptive f) ∷ bs) s v (p-s-v≡false , outd) outr =
assert-not p-s-v≡false then check-diversion-success bs s v outd outr
check-diversion-inverse : (bs : List Branch) (s : S) (v : V) →
check-diversion bs s v ↦ tt → OutOfDomain (List.map proj₁ bs) (s , v) × OutOfRange bs s
check-diversion-inverse [] s v c = tt , tt
check-diversion-inverse ((p , normal l q) ∷ bs) s v (assert-not p-s-v≡false then assert-not q-s≡false then c) =
Product.map (p-s-v≡false ,_) (q-s≡false ,_) (check-diversion-inverse bs s v c)
check-diversion-inverse ((p , adaptive f) ∷ bs) s v (assert-not p-s-v≡false then c) =
Product.map (p-s-v≡false ,_) id (check-diversion-inverse bs s v c)
case-soundness-reentry :
(bs bs' : List Branch) (R : ℙ (S × V)) (R' : ℙ (S × S × V)) (cont : S → Par S) (ReentryCond : ℙ (S × V)) →
BranchSound R R' bs bs' ReentryCond →
(s : S) (v : V) → R (s , v) → NormalDecCaseDomain (List.map (Product.map id isNormal) bs) (s , v) →
OutOfDomain (List.map proj₁ bs') (s , v) →
Σ[ s' ∈ S ] ((put-with-adaptation bs bs' s v cont ↦ s') × R' (s' , s , v))
case-soundness-reentry [] bs' R R' cont ReentryCond sound s v Rsv () outd
case-soundness-reentry ((p , normal l q) ∷ bs) bs' R R' cont ReentryCond (b-sound , sound) s v Rsv
(inj₁ p-s-v≡true) outd rewrite p-s-v≡true
= let (s' , l-s-v↦s' , s'R'v , (p-s'-v≡true , outd-s'-v) , q-s'≡true , outr-s') = b-sound (s , v) (Rsv , p-s-v≡true , outd)
in s' , (l-s-v↦s' >>= assert p-s'-v≡true then assert q-s'≡true then
check-diversion-success bs' s' v outd-s'-v outr-s' >>= return refl) , s'R'v
case-soundness-reentry ((p , normal l q) ∷ bs) bs' R R' cont ReentryCond (b-sound , sound) s v Rsv
(inj₂ (p-s-v≡false , dom)) outd rewrite p-s-v≡false
= case-soundness-reentry bs ((p , normal l q) ∷ bs') R R' cont ReentryCond sound s v Rsv dom (p-s-v≡false , outd)
case-soundness-reentry ((p , adaptive f) ∷ bs) bs' R R' cont ReentryCond (_ , sound) s v Rsv (p-s-v≡false , dom) outd
rewrite p-s-v≡false
= case-soundness-reentry bs ((p , adaptive f) ∷ bs') R R' cont ReentryCond sound s v Rsv dom (p-s-v≡false , outd)
case-soundness-main :
(bs bs' : List Branch) (R : ℙ (S × V)) (R' : ℙ (S × S × V)) (cont : S → Par S) (ReentryCond : ℙ (S × V)) →
BranchSound R R' bs bs' ReentryCond →
(s : S) (v : V) → R (s , v) → DecCaseDomain (List.map proj₁ bs) (s , v) → OutOfDomain (List.map proj₁ bs') (s , v) →
((s'' : S) → R (s'' , v) → ReentryCond (s'' , v) → Σ[ s' ∈ S ] ((cont s'' ↦ s') × R' (s' , s'' , v))) →
Σ[ s' ∈ S ] ((put-with-adaptation bs bs' s v cont ↦ s') × R' (s' , s , v))
case-soundness-main [] bs' R R' cont ReentryCond sound s v sRv () out cont-sound
case-soundness-main ((p , normal l q) ∷ bs) bs' R R' cont ReentryCond (b-sound , sound) s v sRv (inj₁ p-s-v≡true) out cont-sound
rewrite p-s-v≡true =
let (s' , l-s-v↦s' , s'R'v , (p-s'-v≡true , outd-s'-v) , q-s'≡true , outr-s') = b-sound (s , v) (sRv , p-s-v≡true , out)
in s' , (l-s-v↦s' >>= assert p-s'-v≡true then assert q-s'≡true then
check-diversion-success bs' s' v outd-s'-v outr-s' >>= return refl) , s'R'v
case-soundness-main ((p , adaptive f) ∷ bs) bs' R R' cont ReentryCond (lift f-sound , sound) s v sRv (inj₁ p-s-v≡true) out cont-sound
rewrite p-s-v≡true = let (f-s-v-R-v , reentry) = proj₁ (f-sound _ _ (sRv , p-s-v≡true , out))
(s' , cont↦ , R'-s') = cont-sound (f s v) f-s-v-R-v reentry
in s' , cont↦ , proj₂ (f-sound _ _ (sRv , p-s-v≡true , out)) _ R'-s'
case-soundness-main ((p , normal l q) ∷ bs) bs' R R' cont ReentryCond (_ , sound) s v sRv (inj₂ (p-s-v≡false , dom)) out cont-sound
rewrite p-s-v≡false =
case-soundness-main bs ((p , normal l q) ∷ bs') R R' cont ReentryCond sound s v sRv dom (p-s-v≡false , out) cont-sound
case-soundness-main ((p , adaptive f) ∷ bs) bs' R R' cont ReentryCond (_ , sound) s v sRv (inj₂ (p-s-v≡false , dom)) out cont-sound
rewrite p-s-v≡false =
case-soundness-main bs ((p , adaptive f) ∷ bs') R R' cont ReentryCond sound s v sRv dom (p-s-v≡false , out) cont-sound
case-soundness : (bs : List Branch) (R : ℙ (S × V)) (R' : ℙ (S × S × V)) →
BranchSound R R' bs [] (NormalCaseDomain (List.map (Product.map id isNormal) bs)) →
R ⊆ CaseDomain (List.map proj₁ bs) → Sound R (Lens.put (case-lens bs)) R'
case-soundness bs R R' sound dom (s , v) sRv =
case-soundness-main bs [] R R'
(λ s' → put-with-adaptation bs [] s' v (const fail)) (NormalCaseDomain (List.map (Product.map id isNormal) bs))
sound s v sRv (toDecCaseDomain (List.map proj₁ bs) (dom sRv)) tt
(λ s' s'Rv dom' →
case-soundness-reentry bs [] R R' (const fail) (NormalCaseDomain (List.map (Product.map id isNormal) bs))
sound s' v s'Rv (toNormalDecCaseDomain (List.map (Product.map id isNormal) bs) dom') tt)
BranchSoundG : (R : ℙ (S × V)) → List Branch → List Branch → Set₁
BranchSoundG R [] bs' = ⊤
BranchSoundG R ((p , normal l q) ∷ bs) bs' =
(Σ[ P ∈ ℙ S ] SoundG P (Lens.get l) (R ∩ (True ∘ uncurry p) ∩ OutOfDomain (List.map proj₁ bs'))) ×
BranchSoundG R bs ((p , normal l q) ∷ bs')
BranchSoundG R ((p , adaptive f) ∷ bs) bs' = BranchSoundG R bs ((p , adaptive f) ∷ bs')
DecRange : (R : ℙ (S × V)) (bs bs' : List Branch) → BranchSoundG R bs bs' → ℙ S
DecRange R [] bs' _ = ∅
DecRange R ((p , normal l q) ∷ bs) bs' ((P , _) , soundG) = (P ∩ (True ∘ q)) ∪ ((False ∘ q) ∩ DecRange R bs ((p , normal l q) ∷ bs') soundG)
DecRange R ((p , adaptive f) ∷ bs) bs' soundG = DecRange R bs ((p , adaptive f) ∷ bs') soundG
Range : (R : ℙ (S × V)) (bs bs' : List Branch) → BranchSoundG R bs bs' → ℙ S
Range R [] bs' _ = ∅
Range R ((p , normal l q) ∷ bs) bs' ((P , _) , soundG) = (P ∩ (True ∘ q) ∩ OutOfRange bs') ∪ Range R bs ((p , normal l q) ∷ bs') soundG
Range R ((p , adaptive f) ∷ bs) bs' soundG = Range R bs ((p , adaptive f) ∷ bs') soundG
toDecRange : (R : ℙ (S × V)) (bs bs' : List Branch) (soundG : BranchSoundG R bs bs') →
Range R bs bs' soundG ⊆ DecRange R bs bs' soundG ∩ OutOfRange bs'
toDecRange R [] bs' soundG ()
toDecRange R ((p , normal l q) ∷ bs) bs' ((P , soundG) , soundGs) (inj₁ (ps , q-s≡true , out-bs'-s)) = inj₁ (ps , q-s≡true) , out-bs'-s
toDecRange R ((p , normal l q) ∷ bs) bs' ((P , soundG) , soundGs) {s} (inj₂ range)
with toDecRange R bs ((p , normal l q) ∷ bs') soundGs range
toDecRange R ((p , normal l q) ∷ bs) bs' ((P , soundG) , soundGs) {s} (inj₂ range)
| decRange , q-s≡false , out = (inj₂ (q-s≡false , decRange)) , out
toDecRange R ((p , adaptive f) ∷ bs) bs' soundG range = toDecRange R bs ((p , adaptive f) ∷ bs') soundG range
case-soundnessG-main : (bs bs' : List Branch) (R : ℙ (S × V)) (soundG : BranchSoundG R bs bs') →
(s : S) → DecRange R bs bs' soundG s →
Σ[ v ∈ V ] Lens.get (case-lens bs) s ↦ v × R (s , v) × OutOfDomain (List.map proj₁ bs') (s , v)
case-soundnessG-main [] bs' R soundG s ()
case-soundnessG-main ((p , normal l q) ∷ bs) bs' R ((P , soundG) , soundGs) s (inj₁ (ps , q-s≡true))
with soundG s ps
case-soundnessG-main ((p , normal l q) ∷ bs) bs' R ((P , soundG) , soundGs) s (inj₁ (ps , q-s≡true))
| v , get↦ , Rsv , p-s-v≡true , out rewrite q-s≡true =
v , (get↦ >>= assert p-s-v≡true then return refl) , Rsv , out
case-soundnessG-main ((p , normal l q) ∷ bs) bs' R ((P , soundG) , soundGs) s (inj₂ (q-s≡false , range-s))
with case-soundnessG-main bs ((p , normal l q) ∷ bs') R soundGs s range-s
case-soundnessG-main ((p , normal l q) ∷ bs) bs' R ((P , soundG) , soundGs) s (inj₂ (q-s≡false , range-s))
| v , get↦ , Rsv , p-s-v≡false , out rewrite q-s≡false =
v , (get↦ >>= assert-not p-s-v≡false then return refl) , Rsv , out
case-soundnessG-main ((p , adaptive f) ∷ bs) bs' R soundG s range-s
with case-soundnessG-main bs ((p , adaptive f) ∷ bs') R soundG s range-s
case-soundnessG-main ((p , adaptive f) ∷ bs) bs' R soundG s range-s | v , get↦ , Rsv , p-s-v≡false , out =
v , (get↦ >>= assert-not p-s-v≡false then return refl) , Rsv , out
case-soundnessG : (bs : List Branch) (R : ℙ (S × V)) (soundG : BranchSoundG R bs []) →
(P : ℙ S) → P ⊆ Range R bs [] soundG → SoundG P (Lens.get (case-lens bs)) R
case-soundnessG bs R soundG P P⊆ s Ps with case-soundnessG-main bs [] R soundG s (proj₁ (toDecRange R bs [] soundG (P⊆ Ps)))
case-soundnessG bs R soundG P P⊆ s Ps | v , get↦ , Rsv , _ = v , get↦ , Rsv