module FreshNom where

{-
This file develops the properties of the freshness relation.
-}

open import Basics
open import Atoms
open import Perms
open import PermProp
open import Nom
open import Nomfs
open import CatDef

-----------------------------------------------------------------------------------------
--Freshness relation
----------------------------------------------------------------------------------------

record # {X : Nominal}(a : Atom)(x : Aₛ X) : Set where
  constructor fresh
  field
    new : Atom
    notin : new ∉ (some_supp X) x
    fixed : (≈ₐ X) ((Act X) [ ( a , new ) ] x) x

open # public

---------------------------------------------------------------------------------------
--Separated Product
---------------------------------------------------------------------------------------

record SepPro (X : Nominal) : Set where
  constructor SP
  field
    Xelem : Aₛ X
    Aelem : Atom
    freshCon : # {X} Aelem Xelem

open SepPro public

-----------------------------------------------------------------------------------
--equivalence relation on Separated product
-----------------------------------------------------------------------------------

SepPro≈ : (X : Nominal) → Rel (SepPro X)
SepPro≈ X x₁a₁ x₂a₂ = ((≈ₐ X) (Xelem x₁a₁) (Xelem x₂a₂)) × ((Aelem x₁a₁) ≡ (Aelem x₂a₂))
 

------------------------------------------------------------------------------------
--Some/any theorem
-----------------------------------------------------------------------------------

Some/any : {X : Nominal} → (x : Aₛ X) → (a b : Atom) → b ∉ (some_supp X) x → (≈ₐ X) ((Act X) [ (a , b) ] x) x → (c : Atom) → (c ∉ (some_supp X) x) → (≈ₐ X) ((Act X) [ (a , c) ] x) x
Some/any {X} x a b b∉x abx≈x c c∉x with AtEqDec c a | AtEqDec c b
Some/any {X} x a b b∉x abx≈x .a c∉x | yes refl | _ = ((Act X) [ (a , a) ] x)
                                                                                                      ≣< ((Act X) ι x) and x by (≈ₐ X) as (eq≈ₐ X) on
                                                                                                                      ((res X) (aa≈ι a) (≈≡ (eq≈ₐ X) {x}{x} refl)) >
                                                                                           (((Act X) ι x)
                                                                                                      ≣< x and x by (≈ₐ X) as (eq≈ₐ X) on
                                                                                                                      ((ι↠ X) {x}) >
                                                                                           ((x by (≈ₐ X) as (eq≈ₐ X) ▴ )))
Some/any {X} x a b b∉x abx≈x .b c∉x | no _ | yes refl = abx≈x
Some/any {X} x a b b∉x abx≈x c c∉x | no c≠a | no c≠b = ((Act X) [ (a , c) ] x)  ≣< ((Act X) ([(a , b)] ++ ([(b , c)] ++ [(a , b)])) x) and x by (≈ₐ X) as (eq≈ₐ X) on 
                                                                                                                                      ((res X) (λ {x} → (ac≈ab+bc+ab a b c c≠a c≠b) {x}) (≈≡ (eq≈ₐ X) {x}{x} refl)) >
                                                                                              (((Act X) ([(a , b)] ++ ([(b , c)] ++ [(a , b)])) x) 
                                                                                                                               ≣< ((Act X) ([(b , c)] ++ [(a , b)]) ((Act X) [(a , b)] x)) and x by (≈ₐ X) as (eq≈ₐ X) on
                                                                                                                                      ((isEquivalence.Symm (eq≈ₐ X)) ((p₁p₂↠ X) ([(b , c)] ++ [(a , b)]) [(a , b)])) > 
                                                                                              (((Act X) ([(b , c)] ++ [(a , b)]) ((Act X) [(a , b)] x))
                                                                                                                               ≣< ((Act X) ([(b , c)] ++ [(a , b)]) x) and x by (≈ₐ X) as (eq≈ₐ X) on
                                                                                                                                      ((res X)  (λ {x} → P≡≈ ([(b , c)] ++ [(a , b)]) {x}) (abx≈x)) >
                                                                                              (((Act X) ([(b , c)] ++ [(a , b)]) x)
                                                                                                                               ≣< ((Act X) [(a , b)] ((Act X) [(b , c)] x)) and x by (≈ₐ X) as (eq≈ₐ X) on
                                                                                                                                       ((isEquivalence.Symm (eq≈ₐ X)) ((p₁p₂↠ X) [(a , b)] [(b , c)])) >
                                                                                             (((Act X) [(a , b)] ((Act X) [(b , c)] x))
                                                                                                                               ≣< ((Act X) [(a , b)] x) and x by (≈ₐ X) as (eq≈ₐ X) on
                                                                                                                                      ((res X) (λ {x} → P≡≈ [(a , b)] {x}) ((suppAx X) x b c b∉x c∉x)) >
                                                                                             (((Act X) [(a , b)] x)
                                                                                                                               ≣< x and x by (≈ₐ X) as (eq≈ₐ X) on abx≈x >
                                                                                             ((x by (≈ₐ X) as (eq≈ₐ X) ▴ )))))))


Some⇒any : {X : Nominal}{x : Aₛ X}{a : Atom} → (a#x : # {X} a x) → (c : Atom) → (c ∉ (some_supp X) x) → # {X} a x
Some⇒any {X}{x}{a} a#x c c∉x = fresh c c∉x (Some/any {X} x a (new a#x) (notin a#x) (fixed a#x) c c∉x) 

-----------------------------------------------------------------------------------------------------------------------------
--# is an equivariant relation
----------------------------------------------------------------------------------------------------------------------------

osup : {X : Nominal} → (π : Perm) → (x :  Aₛ X) → Atom
osup {X} π x = outside ((flatten π) ++ (((some_supp X) x) ++ ((some_supp X) ((Act X) π x))))                                                                                                                                      

esup : {X : Nominal} → (π : Perm) → (x :  Aₛ X) → List Atom
esup {X} π x = (flatten π) ++ (((some_supp X) x) ++ ((some_supp X) ((Act X) π x)))                                                                                                                                      

#eq : (X : Nominal) → EqCon (Prod NominalAtom X) (λ ax → # {X} (proj₁ ax) (proj₂ ax))
#eq X π (a , x) a#x = fresh (osup {X} π x) 
                                                                                          (∉⊆₂ {(some_supp X) x}{(some_supp X)((Act X) π x)}
                                                                                                   (osup {X} π x)
                                                                                                   (∉⊆₂ {flatten π}{((some_supp X) x) ++ ((some_supp X) ((Act X) π x))}
                                                                                                   (osup {X} π x)
                                                                                                   (outside∉ (esup {X} π x))))
                                                                                          (((Act X) [((PermAct π a) , (osup {X} π x))]
                                                                                           ((Act X) π x)
                                                                                                                ≣< ((Act X) (π ++ [((PermAct π a) , (osup {X} π x))]) x) and ((Act X) π x) by (≈ₐ X) as (eq≈ₐ X) on
                                                                                                                            ((p₁p₂↠ X) [((PermAct π a) , (osup {X} π x))] π) >
                                                                                          (((Act X) (π ++ [((PermAct π a) , (osup {X} π x))]) x)
                                                                                                               ≣< ((Act X) ([(a , (osup {X} π x))] ++ π) x) and ((Act X) π x) by (≈ₐ X) as (eq≈ₐ X) on
                                                                                                                           ((res X)(πabπ≈πab π a (osup {X} π x) 
                                                                                                                             (∉⊆₁ {flatten π}{((some_supp X) x) ++ ((some_supp X)((Act X) π x))}
                                                                                                                                  (osup {X} π x)(outside∉ (esup {X} π x)))) 
                                                                                                                           (≈≡ (eq≈ₐ X) {x}{x} refl)) >
                                                                                          (((Act X) ([(a , (osup {X} π x))] ++ π) x)
                                                                                                               ≣<  ((Act X) π ((Act X) [(a , (osup {X} π x))] x)) and ((Act X) π x) by (≈ₐ X) as (eq≈ₐ X) on 
                                                                                                                       ((isEquivalence.Symm (eq≈ₐ X))((p₁p₂↠ X) π [(a , (osup {X} π x))])) >
                                                                                          (((Act X) π ((Act X) [(a , (osup {X} π x))] x))
                                                                                                               ≣< ((Act X) π x) and ((Act X) π x) by (≈ₐ X) as (eq≈ₐ X) on
                                                                                                                        ((res X) (P≡≈ π)(fixed (Some⇒any {X = X} a#x (osup {X} π x)
                                                                                                                        (∉⊆₁ {(some_supp X) x}{(some_supp X) ((Act X) π x)}
                                                                                                                        (osup {X} π x)(∉⊆₂ {flatten π}{((some_supp X) x) ++ ((some_supp X) ((Act X) π x))}
                                                                                                                        (osup {X} π x) (outside∉ (esup {X} π x))))))) >
                                                                                          (((Act X) π x) by (≈ₐ X) as (eq≈ₐ X) ▴))))))   

a₁a₂#x : {X : Nominal}{x : Aₛ X} → (a₁ a₂ : Atom) → a₁ ≡ a₂ → # {X} a₁ x → # {X} a₂ x
a₁a₂#x a .a refl a#x = a#x

#feq : (X : Nominal) → EqCon (NomExp NominalAtom X) (λ F → ∀ (a : Atom) → # {X} a ((ffun F) a))
#feq X π F a#fa = λ a → let iπa = (PermAct (invPerm π) a) in let ππ⁻¹af = #eq X π (iπa , ((ffun F) iπa)) (a#fa iπa) in a₁a₂#x (PermAct π iπa) a (ππ⁻¹a≡a π a) ππ⁻¹af                         

ℝX : (X : Nominal) → Nominal
ℝX X = NomSubEq (NomExp NominalAtom X) (λ F → ∀ (a : Atom) → # {X} a ((ffun F) a)) (#feq X)

ActSepPro : (X : Nominal) → Perm → SepPro X → SepPro X
ActSepPro X π X₁ = record {Xelem = (Act X) π (Xelem X₁)
                                           ; Aelem = PermAct π (Aelem X₁)
                                           ; freshCon = #eq X π ((Aelem X₁) , (Xelem X₁)) (freshCon X₁) 
                                           }

--------------------------------------------------------------------------------------------------------------------------------------------
--Separated Product Functor
--------------------------------------------------------------------------------------------------------------------------------------------

_*A : (X : Nominal) → Nominal
X *A = record       { Aₛ = SepPro X
                              ; ≈ₐ = SepPro≈ X
                              ; eq≈ₐ = record { Reflex = λ {x₁} → ((Reflex (eq≈ₐ X)) {Xelem x₁} , ((Aelem x₁) ▪))
                                                         ; Symm = λ {x₁ x₂} → λ x₁≈x₂ → ((Symm (eq≈ₐ X)) (proj₁ x₁≈x₂) , sym (proj₂ x₁≈x₂))
                                                         ; Trans = λ {x₁ x₂ x₃} → λ x₁≈x₂ → λ x₂≈x₃ → ((Trans (eq≈ₐ X)) (proj₁ x₁≈x₂) (proj₁ x₂≈x₃) , ((Aelem x₁) ≡< proj₂ x₁≈x₂ > (proj₂ x₂≈x₃)))
                                                         }
                              ; Act = λ π → λ x → ActSepPro X π x 
                              ; res = λ {π₁ π₂ x₁ x₂} → λ π₁≈π₂ → λ x₁≈x₂ → ((res X) {π₁} {π₂} {Xelem x₁} {Xelem x₂} π₁≈π₂ (proj₁ x₁≈x₂) , 
                                                                                                (PermAct π₁ (Aelem x₁) ≡< cong (λ w → PermAct π₁ w) (proj₂ x₁≈x₂) > (PermAct π₁ (Aelem x₂) ≡< π₁≈π₂ {Aelem x₂} > (PermAct π₂ (Aelem x₂)) ▪)))
                              ; p₁p₂↠ = λ π π' → (λ {x} → (((p₁p₂↠ X) π π' {Xelem x}) , (sym (p₁++p₂≡p₂p₁ {Aelem x} π' π))))
                              ; ι↠ = λ {x} → ((ι↠ X) {Xelem x} , refl)
                              ; some_supp = λ x → ((some_supp X) (Xelem x)) ++ [ (Aelem x) ]
                              ; suppAx = λ x → λ b c → λ b∉x → λ c∉x → ((suppAx X) (Xelem x) b c (∉⊆₁ b b∉x) (∉⊆₁ c c∉x) , 
                                                    bc∉suppa (Aelem x) b c (∉⊆₂ {(some_supp X) (Xelem x)}{[ (Aelem x) ]} b b∉x) (∉⊆₂ {(some_supp X) (Xelem x)}{[ (Aelem x) ]} c c∉x))  
                              }

osupf : (X Y : Nominal) → (F : Equivar X Y) → (x : Aₛ X) → List Atom
osupf X Y F x = ((some_supp Y) ((ufun F) x)) ++ ((some_supp X) x)

X*A⟶Y*A : (X Y : Nominal) → (F : Equivar X Y) → Equivar (X *A) (Y *A)
X*A⟶Y*A X Y F = record {ufun = λ x₁ → record {Xelem = (ufun F)(Xelem x₁)
                                                                             ; Aelem = Aelem x₁
                                                                             ; freshCon =  fresh
                                                                                                    (outside (osupf X Y F (Xelem x₁)))
                                                                                                    (∉⊆₁ {(some_supp Y)((ufun F)(Xelem x₁))}{(some_supp X)(Xelem x₁)}
                                                                                                                           (outside (osupf X Y F (Xelem x₁))) 
                                                                                                                           (outside∉ (osupf X Y F (Xelem x₁))))
                                                                                                    ((Act Y) [(Aelem x₁ , (outside (osupf X Y F (Xelem x₁))))] ((ufun F)(Xelem x₁))
                                                                                                                           ≣< ((ufun F)((Act X) [(Aelem x₁ , (outside (osupf X Y F (Xelem x₁))))] (Xelem x₁))) and ((ufun F)(Xelem x₁)) by (≈ₐ Y) as (eq≈ₐ Y) on
                                                                                                                                 ((equiv F) [(Aelem x₁ , (outside (osupf X Y F (Xelem x₁))))] (Xelem x₁)) >
                                                                                                    (((ufun F)((Act X) [(Aelem x₁ , (outside (osupf X Y F (Xelem x₁))))] (Xelem x₁)))
                                                                                                                           ≣< ((ufun F)(Xelem x₁)) and ((ufun F)(Xelem x₁)) by (≈ₐ Y) as (eq≈ₐ Y) on
                                                                                                                                             ((eqi≈ F) (fixed (Some⇒any {X = X} (freshCon x₁)(outside (osupf X Y F (Xelem x₁)))
                                                                                                                                             (∉⊆₂ {(some_supp Y)((ufun F)(Xelem x₁))}{(some_supp X)(Xelem x₁)}
                                                                                                                                                       (outside (osupf X Y F (Xelem x₁))) 
                                                                                                                                                       (outside∉ (osupf X Y F (Xelem x₁))))))) >
                                                                                                    (((ufun F)(Xelem x₁)) by (≈ₐ Y) as (eq≈ₐ Y) ▴)))
                                                                                    }
                                         ; eqi≈ = λ {x₁}{x₂} → λ x₁≈x₂ → (((eqi≈ F){Xelem x₁}{Xelem x₂}(proj₁ x₁≈x₂)) , (proj₂ x₁≈x₂))
                                         ; equiv = λ π → λ x → (((equiv F) π (Xelem x)) , ((PermAct π (Aelem x)) ▪))
                                         }

NomSep : Functor NomCat NomCat
NomSep = record { onObj = λ X → X *A
                              ;  onMor = λ X Y → λ F → X*A⟶Y*A X Y F
                              ;  res≈ = λ X Y → λ F G → λ F≈G → λ x → ((F≈G (Xelem x)) , ((Aelem x) ▪))
                              ;  onId = λ X → λ x → (((isEquivalence.Reflex (eq≈ₐ X)) {Xelem x}) , ((Aelem x) ▪))
                              ;  onComp = λ X Y Z → λ F G → λ x → (((isEquivalence.Reflex (eq≈ₐ Z)) {((ufun G) ∘ (ufun F))(Xelem x)}) , ((Aelem x) ▪))
                              } 

-------------------------------------------------------------------------------------------------------------------------------------------
--Properties of Freshness
------------------------------------------------------------------------------------------------------------------------------------------

a#fx : {X Y : Nominal}{f : (Aₛ (NomExp X Y))}{x : (Aₛ X)}{a : Atom} → # {NomExp X Y} a f → # {X} a x → # {Y} a ((ffun f) x)
a#fx {X}{Y}{f}{x}{a} a#f a#x = let y = (ffun f) x in let fₛ = (some_supp (NomExp X Y)) f in let xₛ = (some_supp X) x in let yₛ = (some_supp Y) y in
                                                        let bₛ = xₛ ++ yₛ in let cₛ = fₛ ++ bₛ in let b = outside cₛ in let b∉fxy = outside∉ cₛ in let b∉f = ∉⊆₁ {fₛ}{bₛ} b b∉fxy in
                                                        let b∉xy = ∉⊆₂ {fₛ}{bₛ} b b∉fxy in let b∉x = ∉⊆₁ {xₛ}{yₛ} b b∉xy in let b∉y = ∉⊆₂ {xₛ}{yₛ} b b∉xy in
                                                        let abf≈f = fixed (Some⇒any {X = NomExp X Y} a#f b b∉f) in let abx≈x = fixed (Some⇒any {X = X} a#x b b∉x) in
                                                        let abfx≈fx = ((Act Y) [(a , b)] y)
                                                                                                     ≣< ((Act Y) [(a , b)] ((ffun f) ((Act X) [(a , b)] x))) and y by (≈ₐ Y) as (eq≈ₐ Y) on
                                                                                                                     ((res Y) (λ {w} → P≡≈ [(a , b)] {w}) ((feqi≈ f) ((Symm (eq≈ₐ X)) abx≈x))) >
                                                                             (((Act Y) [(a , b)] ((ffun f) ((Act X) [(a , b)] x)))
                                                                                                    ≣< y and y by (≈ₐ Y) as (eq≈ₐ Y) on (abf≈f x) >
                                                                             (y by (≈ₐ Y) as (eq≈ₐ Y) ▴)) in fresh b b∉y abfx≈fx


ffs : {X Y : Nominal}{f : Funfs X Y}{a : Atom} → (a ∉ (fsupp f)) → (∀ (x : Aₛ X) → ((≈ₐ Y) ((Act Y) [(a , a)] ((ffun f) ((Act X) [(a , a)] x))) ((ffun f) x))) → # {NomExp X Y} a f
ffs {X}{Y}{f}{a} a∉f aafx = fresh a a∉f (λ x → aafx x)
 
a#fxEq : {X Y : Nominal}{f : Equivar X Y}{x : (Aₛ X)}{a : Atom} → # {X} a x → # {Y} a ((ufun f) x)
a#fxEq {X}{Y}{f}{x}{a} a#x = let fₛ = Eq2fs f in let a#f = ffs {X}{Y}{fₛ}{a} a∉[] (λ x → aax≈x fₛ x a) in a#fx a#f a#x where
                                                                            aax≈x : {X Y : Nominal}(f : Funfs X Y)(x : Aₛ X)(a : Atom) → (≈ₐ Y) ((Act Y) [(a , a)] ((ffun f) ((Act X) [(a , a)] x))) ((ffun f) x)
                                                                            aax≈x {X}{Y} f x a = let afx = (Act Y) [(a , a)] ((ffun f) ((Act X) [(a , a)] x)) in let fx = (ffun f) x in
                                                                                      let afx≈fx = afx ≣< ((Act Y) ι ((ffun f) ((Act X) [(a , a)] x))) and fx by (≈ₐ Y) as (eq≈ₐ Y) on
                                                                                                                               ((res Y) (λ {w} → aa≈ι a) (≈≡ (eq≈ₐ Y) {(ffun f) ((Act X) [(a , a)] x)}{(ffun f) ((Act X) [(a , a)] x)} refl)) >
                                                                                                          (((Act Y) ι ((ffun f) ((Act X) [(a , a)] x)))
                                                                                                                ≣< ((ffun f) ((Act X) [(a , a)] x)) and fx by (≈ₐ Y) as (eq≈ₐ Y) on
                                                                                                                                ((ι↠ Y) {(ffun f) ((Act X) [(a , a)] x)}) >
                                                                                                          (((ffun f) ((Act X) [(a , a)] x))
                                                                                                                ≣< ((ffun f) ((Act X) ι x)) and fx by (≈ₐ Y) as (eq≈ₐ Y) on
                                                                                                                                 ((feqi≈ f) ((res X) (λ {w} → aa≈ι a {w}) (≈≡ (eq≈ₐ X) {x}{x} refl))) >
                                                                                                          (((ffun f) ((Act X) ι x)) 
                                                                                                                ≣< fx and fx by (≈ₐ Y) as (eq≈ₐ Y) on
                                                                                                                              ((feqi≈ f) ((ι↠ X) {x})) >
                                                                                                           (fx by (≈ₐ Y) as (eq≈ₐ Y) ▴)))) in afx≈fx


Freshness : {X : Nominal}{b c : Atom} → (f : (Aₛ (NomExp NominalAtom X))) → (∀ {a : Atom} → (a ∉ (fsupp f)) → (a ∉ ((some_supp X) ((ffun f) a)))) → b ∉ (fsupp f) → c ∉ (fsupp f) → (≈ₐ X)((ffun f) b)((ffun f) c)
Freshness {X}{b}{c} f a∉f⇒a∉fa b∉f c∉f = let fb = (ffun f) b in let fc = (ffun f) c in let fₛ = (fsupp f) in let bₛ = (some_supp X) fb in let cₛ = (some_supp X) fc in
                                                                        let uₛ = bₛ ++ cₛ in let vₛ = fₛ ++ uₛ in let a = outside vₛ in let a∉fbc = outside∉ vₛ in let a∉f = ∉⊆₁ {fₛ}{uₛ} a a∉fbc in
                                                                        let a∉bc = ∉⊆₂ {fₛ}{uₛ} a a∉fbc in let a∉fb = ∉⊆₁ {bₛ}{cₛ} a a∉bc in let a∉fc = ∉⊆₂ {bₛ}{cₛ} a a∉bc in let fa = (ffun f) a in
                                                                        let b∉fb = a∉f⇒a∉fa b∉f in let c∉fc = a∉f⇒a∉fa c∉f in let abf≈fa = (fsuppAx f) a b a∉f b∉f a in let acf≈fa = (fsuppAx f) a c a∉f c∉f a in
                                                                        let fb≈fa = fb ≣< ((Act X) [(a , b)] fb) and fa by (≈ₐ X) as (eq≈ₐ X) on ((Symm (eq≈ₐ X)) ((suppAx X) fb a b a∉fb b∉fb)) >
                                                                                          (((Act X) [(a , b)] fb) ≣< ((Act X) [(a , b)] ((ffun f) (PermAct [(a , b)] a))) and fa by (≈ₐ X) as (eq≈ₐ X) on 
                                                                                                                                 ((res X) (λ {w} → P≡≈ [(a , b)] {w}) ((feqi≈ f) (sym (swapaba≡b a b)))) >
                                                                                         (((Act X) [(a , b)] ((ffun f) (PermAct [(a , b)] a)))
                                                                                                                         ≣< fa and fa by (≈ₐ X) as (eq≈ₐ X) on abf≈fa >
                                                                                         (fa by (≈ₐ X) as (eq≈ₐ X) ▴))) in
                                                                        let fc≈fa = fc ≣< ((Act X) [(a , c)] fc) and fa by (≈ₐ X) as (eq≈ₐ X) on ((Symm (eq≈ₐ X)) ((suppAx X) fc a c a∉fc c∉fc)) >
                                                                                          (((Act X) [(a , c)] fc) ≣< ((Act X) [(a , c)] ((ffun f) (PermAct [(a , c)] a))) and fa by (≈ₐ X) as (eq≈ₐ X) on 
                                                                                                                                 ((res X) (λ {w} → P≡≈ [(a , c)] {w}) ((feqi≈ f) (sym (swapaba≡b a c)))) >
                                                                                         (((Act X) [(a , c)] ((ffun f) (PermAct [(a , c)] a)))
                                                                                                                         ≣< fa and fa by (≈ₐ X) as (eq≈ₐ X) on acf≈fa >
                                                                                         (fa by (≈ₐ X) as (eq≈ₐ X) ▴))) in (Trans (eq≈ₐ X)) fb≈fa ((Symm (eq≈ₐ X)) fc≈fa)

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------