------------------------------------------------------------------------
-- Examples
------------------------------------------------------------------------

open import Graded.Modality
open import Graded.Usage.Restrictions
open import Graded.Heap.Assumptions
open import Definition.Typed.Restrictions

module Graded.Heap.Examples
  {a} {M : Set a} {𝕄 : Modality M}
  (UR : Usage-restrictions 𝕄)
  (TR : Type-restrictions 𝕄)
  (As : Assumptions UR TR)
  where

open Modality 𝕄
open Type-restrictions TR
open Assumptions As

open import Tools.Fin
open import Tools.Nat using (Nat)
open import Tools.Product
open import Tools.PropositionalEquality as PE

open import Graded.Context 𝕄
open import Graded.Modality.Properties.Subtraction semiring-with-meet
open import Graded.Mode 𝕄
open import Graded.Usage 𝕄 UR

open import Graded.Heap.Untyped type-variant UR factoring-nr
open import Graded.Heap.Usage type-variant UR factoring-nr
open import Graded.Heap.Usage.Properties type-variant UR factoring-nr
open import Graded.Heap.Reduction type-variant UR factoring-nr
open import Graded.Heap.Reduction.Inversion type-variant UR factoring-nr
open import Graded.Heap.Reduction.Properties type-variant UR factoring-nr
open import Graded.Heap.Soundness UR TR As

open import Definition.Untyped M
open import Definition.Untyped.Sigma 𝕄 hiding (fstʷ)
open import Definition.Typed TR

private variable
  k n : Nat
  t t′ : Term _
  γ : Conₘ _
  m : Mode
  H H′ : Heap _ _
  ρ ρ′ : Wk _ _
  S S′ : Stack _

-- First projection for weak Σ-types, specialized to pairs of natural
-- numbers with grade 𝟙 for the first component.

fstʷ : Term n  Term n
fstʷ = Fstʷ-sndʷ.fstʷ 𝟙 𝟘 𝟙 

opaque

  -- Evaluating fstʷ (prodʷ 𝟙 zero zero) in the heap yields the state
  -- ⟨ ε ∙ (𝟙 , zero , id) ∙ (𝟙 , zero , step id) , var x1 , stepn id 2 , ε ⟩

  fstʷ⟨0,0⟩↠*′ :
    initial {k = 0} (fstʷ (prodʷ 𝟙 zero zero)) ↠*
     ε  (𝟙 , zero , id)  (𝟙 , zero , step id) , var x1 , liftn id 2 , ε 
  fstʷ⟨0,0⟩↠*′ =
    ⇾ₑ (⇒ₑ prodrecₕ) 
    ⇒ᵥ prodʷₕ ε 
    subst₂  p q   ε  (p , zero , id)  (q , zero , step id) , _ , _ , _  ↠*
                  ε  (𝟙 , zero , id)  (𝟙 , zero , step id) , _ , _ , _ )
      (PE.sym (PE.trans (·-identityˡ _) (·-identityʳ _))) (PE.sym (·-identityʳ _)) id

opaque

  -- Evaluating fstʷ (prodʷ 𝟙 zero zero) in the heap yields the state
  -- ⟨ ε ∙ (𝟘 , zero , id) ∙ (𝟙 , zero , step id) , zero , stepn id 2 , ε ⟩
  -- if 𝟙 - 𝟙 ≡ 𝟘.

  fstʷ⟨0,0⟩↠* :
    𝟙 - 𝟙  𝟘 
    initial {k = 0} (fstʷ (prodʷ 𝟙 zero zero)) ↠*
     ε  (𝟘 , zero , id)  (𝟙 , zero , step id) , zero , stepn id 2 , ε 
  fstʷ⟨0,0⟩↠* 𝟙-𝟙≡𝟘 =
    ⇾ₑ (⇒ₑ prodrecₕ) 
    ⇒ᵥ prodʷₕ ε 
    ⇾ₑ var ε (there (here (subst (_- 𝟙  𝟘)
         (PE.sym (PE.trans (·-identityˡ _) (·-identityˡ _))) 𝟙-𝟙≡𝟘))) 
    subst  p   ε  (𝟘 , zero , id)  (p , zero , step id) , _ , _ , _  ↠*
                  ε  (𝟘 , zero , id)  (𝟙 , zero , step id) , _ , _ , _ )
      (PE.sym (·-identityʳ 𝟙)) id

opaque

  -- If fstʷ has a usage rule then 𝟙 ≤ 𝟘 (given some assumptions).

  fstʷ-has-usage→𝟙≤𝟘 :
    Σʷ-allowed 𝟙 𝟘 
    𝟙 - 𝟙  𝟘 
    (∀ {n} {γ : Conₘ n} {t m}  γ ▸[ m ] t 
       λ δ  δ ▸[ m ] fstʷ t) 
    𝟙  𝟘
  fstʷ-has-usage→𝟙≤𝟘 ok 𝟙-𝟙≡𝟘 ▸fstʷ =
    let s = initial {k = 0} (fstʷ (prodʷ 𝟙 zero zero))
        ⊢ℕ = ℕⱼ ( ℕⱼ ε)
        ⊢s = prodrecⱼ (ℕⱼ ( ΠΣⱼ ⊢ℕ ok))
              (prodⱼ ⊢ℕ (zeroⱼ ε) (zeroⱼ ε) ok)
              (var ( ⊢ℕ) (there here)) ok
        ▸s = sub (▸fstʷ (prodʷₘ zeroₘ zeroₘ) .proj₂) (ε≤ _)
        _ , _ , H , _ , _ , d , _ , H≤𝟘 = soundness-closed ⊢s ▸s
        m≡ , n≡ , s≡ = ↠*-det d (fstʷ⟨0,0⟩↠* 𝟙-𝟙≡𝟘)
                         _  ↠-inv-sucᵏ)  _  ↠-inv-sucᵏ)
    in  lemma m≡ n≡ s≡ H≤𝟘
    where
    ε≤ :  δ  ε ≤ᶜ δ
    ε≤ ε = ε
    lemma :
      (x : k  2) (y : n  0) 
      subst₂ (State 0) x y ( H , t , ρ , S ) 
         ε  (𝟘 , zero , id)  (𝟙 , zero , step id) , t′ , ρ′ , S′  
      H ≤ʰ 𝟘  𝟙  𝟘
    lemma refl refl refl (H≤  𝟙≤𝟘) = 𝟙≤𝟘