agda-spa/Analysis/Constant.agda

224 lines
9.7 KiB
Agda
Raw Normal View History

module Analysis.Constant where
open import Data.Integer as Int using (; +_; -[1+_]; _≟_)
open import Data.Integer.Show as IntShow using ()
open import Data.Nat as Nat using (; suc; zero)
open import Data.Product using (Σ; proj₁; proj₂; _,_)
open import Data.Sum using (inj₁; inj₂)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.Unit using (; tt)
open import Data.List.Membership.Propositional as MemProp using () renaming (_∈_ to _∈ˡ_)
open import Relation.Binary.PropositionalEquality using (_≡_; refl; sym; trans; subst)
open import Relation.Nullary using (¬_; yes; no)
open import Equivalence
open import Language
open import Lattice
open import Showable using (Showable; show)
open import Utils using (_⇒_; _∧_; __)
open import Analysis.Utils using (eval-combine₂)
import Analysis.Forward
instance
showable : Showable
showable = record
{ show = IntShow.show
}
instance
≡-equiv : IsEquivalence _≡_
≡-equiv = record
{ ≈-refl = refl
; ≈-sym = sym
; ≈-trans = trans
}
≡-Decidable- : IsDecidable {_} {} _≡_
≡-Decidable- = record { R-dec = _≟_ }
-- embelish '' with a top and bottom element.
open import Lattice.AboveBelow _ as AB
using ()
renaming
( AboveBelow to ConstLattice
; ≈-dec to ≈ᶜ-dec
; to ⊥ᶜ
; to ⊤ᶜ
; [_] to [_]ᶜ
; _≈_ to _≈ᶜ_
; ≈-⊥-⊥ to ≈ᶜ-⊥ᶜ-⊥ᶜ
; ≈-- to ≈ᶜ-⊤ᶜ-⊤ᶜ
; ≈-lift to ≈ᶜ-lift
; ≈-refl to ≈ᶜ-refl
)
-- '''s structure is not finite, so just use a 'plain' above-below Lattice.
open AB.Plain (+ 0) using ()
renaming
( isLattice to isLatticeᶜ
; isFiniteHeightLattice to isFiniteHeightLatticeᵍ
; _≼_ to _≼ᶜ_
; _⊔_ to _⊔ᶜ_
; _⊓_ to _⊓ᶜ_
; ≼-trans to ≼ᶜ-trans
; ≼-refl to ≼ᶜ-refl
)
plus : ConstLattice ConstLattice ConstLattice
plus ⊥ᶜ _ = ⊥ᶜ
plus _ ⊥ᶜ = ⊥ᶜ
plus ⊤ᶜ _ = ⊤ᶜ
plus _ ⊤ᶜ = ⊤ᶜ
plus [ z₁ ]ᶜ [ z₂ ]ᶜ = [ z₁ Int.+ z₂ ]ᶜ
-- this is incredibly tedious: 125 cases per monotonicity proof, and tactics
-- are hard. postulate for now.
postulate plus-Monoˡ : (s₂ : ConstLattice) Monotonic _≼ᶜ_ _≼ᶜ_ (λ s₁ plus s₁ s₂)
postulate plus-Monoʳ : (s₁ : ConstLattice) Monotonic _≼ᶜ_ _≼ᶜ_ (plus s₁)
plus-Mono₂ : Monotonic₂ _≼ᶜ_ _≼ᶜ_ _≼ᶜ_ plus
plus-Mono₂ = (plus-Monoˡ , plus-Monoʳ)
minus : ConstLattice ConstLattice ConstLattice
minus ⊥ᶜ _ = ⊥ᶜ
minus _ ⊥ᶜ = ⊥ᶜ
minus ⊤ᶜ _ = ⊤ᶜ
minus _ ⊤ᶜ = ⊤ᶜ
minus [ z₁ ]ᶜ [ z₂ ]ᶜ = [ z₁ Int.- z₂ ]ᶜ
postulate minus-Monoˡ : (s₂ : ConstLattice) Monotonic _≼ᶜ_ _≼ᶜ_ (λ s₁ minus s₁ s₂)
postulate minus-Monoʳ : (s₁ : ConstLattice) Monotonic _≼ᶜ_ _≼ᶜ_ (minus s₁)
minus-Mono₂ : Monotonic₂ _≼ᶜ_ _≼ᶜ_ _≼ᶜ_ minus
minus-Mono₂ = (minus-Monoˡ , minus-Monoʳ)
⟦_⟧ᶜ : ConstLattice Value Set
⟦_⟧ᶜ ⊥ᶜ _ =
⟦_⟧ᶜ ⊤ᶜ _ =
⟦_⟧ᶜ [ z ]ᶜ v = v ↑ᶻ z
⟦⟧ᶜ-respects-≈ᶜ : {s₁ s₂ : ConstLattice} s₁ ≈ᶜ s₂ s₁ ⟧ᶜ s₂ ⟧ᶜ
⟦⟧ᶜ-respects-≈ᶜ ≈ᶜ-⊥ᶜ-⊥ᶜ v bot = bot
⟦⟧ᶜ-respects-≈ᶜ ≈ᶜ-⊤ᶜ-⊤ᶜ v top = top
⟦⟧ᶜ-respects-≈ᶜ (≈ᶜ-lift { z } { z } refl) v proof = proof
⟦⟧ᶜ-⊔ᶜ- : {s₁ s₂ : ConstLattice} ( s₁ ⟧ᶜ s₂ ⟧ᶜ) s₁ ⊔ᶜ s₂ ⟧ᶜ
⟦⟧ᶜ-⊔ᶜ- {⊥ᶜ} x (inj₂ px₂) = px₂
⟦⟧ᶜ-⊔ᶜ- {⊤ᶜ} x _ = tt
⟦⟧ᶜ-⊔ᶜ- {[ s₁ ]ᶜ} {[ s₂ ]ᶜ} x px
with s₁ s₂
... | no _ = tt
... | yes refl
with px
... | inj₁ px₁ = px₁
... | inj₂ px₂ = px₂
⟦⟧ᶜ-⊔ᶜ- {[ s₁ ]ᶜ} {⊥ᶜ} x (inj₁ px₁) = px₁
⟦⟧ᶜ-⊔ᶜ- {[ s₁ ]ᶜ} {⊤ᶜ} x _ = tt
s₁≢s₂⇒¬s₁∧s₂ : {z₁ z₂ : } ¬ z₁ z₂ {v} ¬ (( [ z₁ ]ᶜ ⟧ᶜ [ z₂ ]ᶜ ⟧ᶜ) v)
s₁≢s₂⇒¬s₁∧s₂ { z₁ } { z₂ } z₁≢z₂ {v} (v≡z₁ , v≡z₂)
with refl trans (sym v≡z₁) v≡z₂ = z₁≢z₂ refl
⟦⟧ᶜ-⊓ᶜ-∧ : {s₁ s₂ : ConstLattice} ( s₁ ⟧ᶜ s₂ ⟧ᶜ) s₁ ⊓ᶜ s₂ ⟧ᶜ
⟦⟧ᶜ-⊓ᶜ-∧ {⊥ᶜ} x (bot , _) = bot
⟦⟧ᶜ-⊓ᶜ-∧ {⊤ᶜ} x (_ , px₂) = px₂
⟦⟧ᶜ-⊓ᶜ-∧ {[ s₁ ]ᶜ} {[ s₂ ]ᶜ} x (px₁ , px₂)
with s₁ s₂
... | no s₁≢s₂ = s₁≢s₂⇒¬s₁∧s₂ s₁≢s₂ (px₁ , px₂)
... | yes refl = px₁
⟦⟧ᶜ-⊓ᶜ-∧ {[ g₁ ]ᶜ} {⊥ᶜ} x (_ , bot) = bot
⟦⟧ᶜ-⊓ᶜ-∧ {[ g₁ ]ᶜ} {⊤ᶜ} x (px₁ , _) = px₁
instance
latticeInterpretationᶜ : LatticeInterpretation isLatticeᶜ
latticeInterpretationᶜ = record
{ ⟦_⟧ = ⟦_⟧ᶜ
; ⟦⟧-respects-≈ = ⟦⟧ᶜ-respects-≈ᶜ
; ⟦⟧-⊔- = ⟦⟧ᶜ-⊔ᶜ-
; ⟦⟧-⊓-∧ = ⟦⟧ᶜ-⊓ᶜ-∧
}
module WithProg (prog : Program) where
open Program prog
open import Analysis.Forward.Lattices ConstLattice prog
open import Analysis.Forward.Evaluation ConstLattice prog
open import Analysis.Forward.Adapters ConstLattice prog
eval : (e : Expr) VariableValues ConstLattice
eval (e₁ + e₂) vs = plus (eval e₁ vs) (eval e₂ vs)
eval (e₁ - e₂) vs = minus (eval e₁ vs) (eval e₂ vs)
eval (` k) vs
with ∈k-decᵛ k (proj₁ (proj₁ vs))
... | yes k∈vs = proj₁ (locateᵛ {k} {vs} k∈vs)
... | no _ = ⊤ᶜ
eval (# n) _ = [ + n ]ᶜ
eval-Monoʳ : (e : Expr) Monotonic _≼ᵛ_ _≼ᶜ_ (eval e)
eval-Monoʳ (e₁ + e₂) {vs₁} {vs₂} vs₁≼vs₂ =
eval-combine₂ (λ {x} {y} {z} ≼ᶜ-trans {x} {y} {z})
plus plus-Mono₂ {o₁ = eval e₁ vs₁}
(eval-Monoʳ e₁ vs₁≼vs₂) (eval-Monoʳ e₂ vs₁≼vs₂)
eval-Monoʳ (e₁ - e₂) {vs₁} {vs₂} vs₁≼vs₂ =
eval-combine₂ (λ {x} {y} {z} ≼ᶜ-trans {x} {y} {z})
minus minus-Mono₂ {o₁ = eval e₁ vs₁}
(eval-Monoʳ e₁ vs₁≼vs₂) (eval-Monoʳ e₂ vs₁≼vs₂)
eval-Monoʳ (` k) {vs₁@((kvs₁ , _) , _)} {vs₂@((kvs₂ , _), _)} vs₁≼vs₂
with ∈k-decᵛ k kvs₁ | ∈k-decᵛ k kvs₂
... | yes k∈kvs₁ | yes k∈kvs₂ =
let
(v₁ , k,v₁∈vs₁) = locateᵛ {k} {vs₁} k∈kvs₁
(v₂ , k,v₂∈vs₂) = locateᵛ {k} {vs₂} k∈kvs₂
in
m₁≼m₂⇒m₁[k]ᵛ≼m₂[k]ᵛ vs₁ vs₂ vs₁≼vs₂ k,v₁∈vs₁ k,v₂∈vs₂
... | yes k∈kvs₁ | no k∉kvs₂ = ⊥-elim (k∉kvs₂ (subst (λ l k ∈ˡ l) (all-equal-keysᵛ vs₁ vs₂) k∈kvs₁))
... | no k∉kvs₁ | yes k∈kvs₂ = ⊥-elim (k∉kvs₁ (subst (λ l k ∈ˡ l) (all-equal-keysᵛ vs₂ vs₁) k∈kvs₂))
... | no k∉kvs₁ | no k∉kvs₂ = IsLattice.≈-refl isLatticeᶜ
eval-Monoʳ (# n) _ = ≼ᶜ-refl ([ + n ]ᶜ)
instance
ConstEval : ExprEvaluator
ConstEval = record { eval = eval; eval-Monoʳ = eval-Monoʳ }
-- For debugging purposes, print out the result.
output = show (Analysis.Forward.WithProg.result ConstLattice prog)
-- This should have fewer cases -- the same number as the actual 'plus' above.
-- But agda only simplifies on first argument, apparently, so we are stuck
-- listing them all.
plus-valid : {g₁ g₂} {z₁ z₂} g₁ ⟧ᶜ (↑ᶻ z₁) g₂ ⟧ᶜ (↑ᶻ z₂) plus g₁ g₂ ⟧ᶜ (↑ᶻ (z₁ Int.+ z₂))
plus-valid {⊥ᶜ} {_} _ =
plus-valid {[ z ]ᶜ} {⊥ᶜ} _ =
plus-valid {⊤ᶜ} {⊥ᶜ} _ =
plus-valid {⊤ᶜ} {[ z ]ᶜ} _ _ = tt
plus-valid {⊤ᶜ} {⊤ᶜ} _ _ = tt
plus-valid {[ z₁ ]ᶜ} {[ z₂ ]ᶜ} refl refl = refl
plus-valid {[ z ]ᶜ} {⊤ᶜ} _ _ = tt
--
-- Same for this one. It should be easier, but Agda won't simplify.
minus-valid : {g₁ g₂} {z₁ z₂} g₁ ⟧ᶜ (↑ᶻ z₁) g₂ ⟧ᶜ (↑ᶻ z₂) minus g₁ g₂ ⟧ᶜ (↑ᶻ (z₁ Int.- z₂))
minus-valid {⊥ᶜ} {_} _ =
minus-valid {[ z ]ᶜ} {⊥ᶜ} _ =
minus-valid {⊤ᶜ} {⊥ᶜ} _ =
minus-valid {⊤ᶜ} {[ z ]ᶜ} _ _ = tt
minus-valid {⊤ᶜ} {⊤ᶜ} _ _ = tt
minus-valid {[ z₁ ]ᶜ} {[ z₂ ]ᶜ} refl refl = refl
minus-valid {[ z ]ᶜ} {⊤ᶜ} _ _ = tt
eval-valid : IsValidExprEvaluator
eval-valid (⇒ᵉ-+ ρ e₁ e₂ z₁ z₂ ρ,e₁⇒z₁ ρ,e₂⇒z₂) ⟦vs⟧ρ =
plus-valid (eval-valid ρ,e₁⇒z₁ ⟦vs⟧ρ) (eval-valid ρ,e₂⇒z₂ ⟦vs⟧ρ)
eval-valid (⇒ᵉ-- ρ e₁ e₂ z₁ z₂ ρ,e₁⇒z₁ ρ,e₂⇒z₂) ⟦vs⟧ρ =
minus-valid (eval-valid ρ,e₁⇒z₁ ⟦vs⟧ρ) (eval-valid ρ,e₂⇒z₂ ⟦vs⟧ρ)
eval-valid {vs} (⇒ᵉ-Var ρ x v x,v∈ρ) ⟦vs⟧ρ
with ∈k-decᵛ x (proj₁ (proj₁ vs))
... | yes x∈kvs = ⟦vs⟧ρ (proj₂ (locateᵛ {x} {vs} x∈kvs)) x,v∈ρ
... | no x∉kvs = tt
eval-valid (⇒ᵉ- ρ n) _ = refl
instance
ConstEvalValid : ValidExprEvaluator ConstEval latticeInterpretationᶜ
ConstEvalValid = record { valid = eval-valid }
analyze-correct = Analysis.Forward.WithProg.analyze-correct ConstLattice prog tt