------------------------------------------------------------------------------
-- Conversion rules for the division
------------------------------------------------------------------------------

{-# OPTIONS --exact-split              #-}
{-# OPTIONS --no-sized-types           #-}
{-# OPTIONS --no-universe-polymorphism #-}
{-# OPTIONS --without-K                #-}

module LTC-PCF.Program.Division.ConversionRules where

open import Common.FOL.Relation.Binary.EqReasoning

open import LTC-PCF.Base
open import LTC-PCF.Data.Nat
open import LTC-PCF.Data.Nat.Inequalities
open import LTC-PCF.Program.Division.Division

------------------------------------------------------------------------------
-- Division properties

private
    -- Before to prove some properties for div it is convenient
    -- to have a proof for each possible execution step.

    -- Initially, we define the possible states (div-s₁, div-s₂,
    -- ...) and after that, we write down the proof for the execution
    -- step from the state p to the state q, e.g.
    --
    -- proof₂₋₃ : ∀ i j → div-s₂ i j ≡ div-s₃ i j.

    -- Initially, the conversion rule fix-eq is applied.
    div-s₁ : D  D  D
    div-s₁ i j = divh (fix divh) · i · j

    -- First argument application.
    div-s₂ : D  D  D
    div-s₂ i j = fun · j
      where
      fun : D
      fun = lam  j  if (lt i j)
                         then zero
                         else succ₁ (fix divh · (i  j) · j))

    -- Second argument application.
    div-s₃ : D  D  D
    div-s₃ i j = if (lt i j) then zero else succ₁ (fix divh · (i  j) · j)

    -- lt i j ≡ true.
    div-s₄ : D  D  D
    div-s₄ i j = if true then zero else succ₁ (fix divh · (i  j) · j)

    -- lt i j ≡ false.
    div-s₅ : D  D  D
    div-s₅ i j = if false then zero else succ₁ (fix divh · (i  j) · j)

    -- The conditional is true.
    div-s₆ : D
    div-s₆ = zero

    -- The conditional is false.
    div-s₇ : D  D  D
    div-s₇ i j = succ₁ (fix divh · (i  j) · j)

    {-

    To prove the execution steps, e.g.

    proof₃₋₄ : ∀ i j → div-s₃ i j → divh_s₄ i j,

    we usually need to prove that

                             ... m ... ≡ ... n ...    (1)

    given that
                                  m ≡ n,              (2)

    where (2) is a conversion rule usually.

    We prove (1) using

    subst : ∀ {x y} (A : D → Set) → x ≡ y → A x → A y

    where
      • P is given by \m → ... m ... ≡ ... n ...,
      • x ≡ y is given n ≡ m (actually, we use ≡-sym (m ≡ n)) and
      • P x is given by ... n ... ≡ ... n ... (i.e. ≡-refl)
    -}

    -- From div · i · j to div-s₁ using the conversion rule fix-eq.
    proof₀₋₁ :  i j  fix divh · i · j  div-s₁ i j
    proof₀₋₁ i j = subst  t  t · i · j  divh (fix divh) · i · j)
                         (sym (fix-eq divh))
                         refl

    -- From div-s₁ to div-s₂ using the conversion rule beta.
    proof₁₋₂ :  i j  div-s₁ i j  div-s₂ i j
    proof₁₋₂ i j =
      subst  t  t · j  fun i · j)
            (sym (beta fun i))
            refl
         where
         -- The function fun is the same that the fun part of div-s₂,
         -- except that we need a fresh variable y to avoid the
         -- clashing of the variable i in the application of the beta
         -- rule.
         fun : D  D
         fun y = lam  j  if (lt y j)
                              then zero
                              else succ₁ (fix divh · (y  j) · j))

    -- From div-s₂ to div-s₃ using the conversion rule beta.
    proof₂₋₃ :  i j  div-s₂ i j  div-s₃ i j
    proof₂₋₃ i j  = beta fun j
      where
      -- The function fun is the same that div-s₃, except that we
      -- need a fresh variable y to avoid the clashing of the
      -- variable j in the application of the beta rule.
      fun : D  D
      fun y = if (lt i y) then zero else succ₁ ((fix divh) · (i  y) · y)

    -- From div-s₃ to div-s₄ using the proof i<j.
    proof₃_₄ :  i j  i < j  div-s₃ i j  div-s₄ i j
    proof₃_₄ i j i<j =
      subst  t  (if t then zero else succ₁ ((fix divh) · (i  j) · j)) 
                   (if true then zero else succ₁ ((fix divh) · (i  j) · j)))
            (sym i<j)
            refl

    -- From div-s₃ to div-s₅ using the proof i≮j.
    proof₃₋₅ :  i j  i  j  div-s₃ i j  div-s₅ i j
    proof₃₋₅ i j i≮j =
      subst  t  (if t then zero else succ₁ ((fix divh) · (i  j) · j)) 
                   (if false then zero else succ₁ ((fix divh) · (i  j) · j)))
            (sym i≮j)
            refl

    -- From div-s₄ to div-s₆ using the conversion rule if-true.
    proof₄₋₆ :  i j  div-s₄ i j  div-s₆
    proof₄₋₆ i j = if-true zero

    -- From div-s₅ to div-s₇ using the conversion rule if-false.
    proof₅₋₇ :  i j  div-s₅ i j  div-s₇ i j
    proof₅₋₇ i j = if-false (succ₁ (fix divh · (i  j) · j))

----------------------------------------------------------------------
-- The division result when the dividend is minor than the
-- the divisor.
div-x<y :  {i j}  i < j  div i j  zero
div-x<y {i} {j} i<j =
  div i j    ≡⟨ proof₀₋₁ i j 
  div-s₁ i j ≡⟨ proof₁₋₂ i j 
  div-s₂ i j ≡⟨ proof₂₋₃ i j 
  div-s₃ i j ≡⟨ proof₃_₄ i j i<j 
  div-s₄ i j ≡⟨ proof₄₋₆ i j 
  div-s₆     

----------------------------------------------------------------------
-- The division result when the dividend is greater or equal than the
-- the divisor.
div-x≮y :  {i j}  i  j  div i j  succ₁ (div (i  j) j)
div-x≮y {i} {j} i≮j =
  div i j    ≡⟨ proof₀₋₁ i j 
  div-s₁ i j ≡⟨ proof₁₋₂ i j 
  div-s₂ i j ≡⟨ proof₂₋₃ i j 
  div-s₃ i j ≡⟨ proof₃₋₅ i j i≮j 
  div-s₅ i j ≡⟨ proof₅₋₇ i j 
  div-s₇ i j