{-# OPTIONS --safe #-}

module Choose where

open import Prelude hiding (_⟨_⟩_)
open import Data.Vec
open import Path.Reasoning

private variable n m k : 

data Choose (A : Type) :     Type where
  ⟨_⟩  : A  Choose A zero m
  ⟨⟩   : Choose A (suc n) zero
  _**_ : Choose A (suc n) m  Choose A n m  Choose A (suc n) (suc m)

cmap : (A  B)  Choose A n m  Choose B n m
cmap f  x        =  f x 
cmap f ⟨⟩          = ⟨⟩
cmap f (xs ** ys) = cmap f xs ** cmap f ys

choose :  n  Vec A m  Choose (Vec A n) n m
choose zero    _        =  [] 
choose (suc n) []       = ⟨⟩ 
choose (suc n) (x  xs) = choose (suc n) xs ** cmap (x ∷_) (choose n xs)

sub : Vec A (suc n)  Vec (Vec A n) n
sub (x  []) = []
sub (x  xs@(_  _)) = xs  vmap (x ∷_) (sub xs)

zw : (A  B  C)  Choose A n m  Choose B n m  Choose C n m
zw f  x   y  =  f x y 
zw f ⟨⟩ ⟨⟩ = ⟨⟩
zw f (xsₗ ** xsᵣ) (ysₗ ** ysᵣ) = zw f xsₗ ysₗ ** zw f xsᵣ ysᵣ

fill :  n m  A  Choose A n m
fill zero    m       x =  x 
fill (suc n) zero    x = ⟨⟩
fill (suc n) (suc m) x = fill (suc n) m x ** fill n m x

up  : Choose A k m  Choose (Vec A k) (suc k) m
up  _        = fill _ _ []
up ⟨⟩          = ⟨⟩ 
up (xs ** ys) = up xs ** zw _∷_ xs (up ys)

private variable D E : Type

zw-cmap-cmap : (f : B  D  E) (g : A  B) (h : C  D) (xs : Choose A n m) (ys : Choose C n m)
              zw f (cmap g xs) (cmap h ys)  zw  x y  f (g x) (h y)) xs ys
zw-cmap-cmap f g h  x   y  = refl
zw-cmap-cmap f g h ⟨⟩ ⟨⟩ = refl
zw-cmap-cmap f g h (xl ** xr) (yl ** yr) =
  cong₂ _**_ (zw-cmap-cmap f g h xl yl) (zw-cmap-cmap f g h xr yr)

cmap-zw : (f : C  D) (g : A  B  C) (xs : Choose A n m) (ys : Choose B n m)
         cmap f (zw g xs ys)  zw  x y  f (g x y)) xs ys
cmap-zw f g  x   y  = refl
cmap-zw f g ⟨⟩ ⟨⟩ = refl
cmap-zw f g (xsₗ ** xsᵣ) (ysₗ ** ysᵣ) =
  cong₂ _**_ (cmap-zw f g xsₗ ysₗ) (cmap-zw f g xsᵣ ysᵣ)

choose-prop : isProp A  isProp (Choose A n m)
choose-prop prop  x   y  = cong ⟨_⟩ (prop x y)
choose-prop prop ⟨⟩ ⟨⟩ = refl
choose-prop prop (xsₗ ** xsᵣ) (ysₗ ** ysᵣ) =
  cong₂ _**_ (choose-prop prop xsₗ ysₗ) (choose-prop prop xsᵣ ysᵣ)

up-nat : (f : A  B) (xs : Choose A n m)  up (cmap f xs)  cmap (vmap f) (up xs)
up-nat f  x  = choose-prop isProp-[] _ _
up-nat f ⟨⟩ = refl
up-nat f (xs ** ys) =
  cong₂ _**_ (up-nat f xs) $

     zw _∷_ (cmap f xs) (up (cmap f ys))
                                                 ≡⟨ cong (zw _∷_ _) (up-nat f ys) 
     zw _∷_ (cmap f xs) (cmap (vmap f) (up ys))
                                                 ≡⟨ zw-cmap-cmap _∷_ f (vmap f) xs (up ys) 
     zw  z zs  vmap f (z  zs)) xs (up ys)
                                                 ≡˘⟨ cmap-zw (vmap f) _∷_ xs (up ys) 
     cmap (vmap f) (zw _∷_ xs (up ys))  

cmap-comp : (g : B  C) (f : A  B) (xs : Choose A n m)
           cmap g (cmap f xs)  cmap (g  f) xs
cmap-comp g f  x  = refl
cmap-comp g f ⟨⟩ = refl
cmap-comp g f (xsₗ ** xsᵣ) = cong₂ _**_ (cmap-comp g f xsₗ) (cmap-comp g f xsᵣ)

zw-sub :  x (xs : Choose (Vec A (suc k)) n m)
        cmap sub (cmap (x ∷_) xs)  zw _∷_ xs (cmap (vmap (x ∷_)  sub) xs)
zw-sub x  _  _  = refl
zw-sub x ⟨⟩ = refl
zw-sub x (xs ** ys) = cong₂ _**_ (zw-sub x xs) (zw-sub x ys)

up-sub :  n (xs : Vec A m)  up (choose n xs)  cmap sub (choose (suc n) xs)
up-sub zero    xs = choose-prop isProp-[] _ _
up-sub (suc n) [] = refl
up-sub (suc n) (x  xs) =
  cong₂ _**_ (up-sub (suc n) xs) $

    zw _∷_ (choose (suc n) xs) (up (cmap (x ∷_) (choose n xs)))
                                                                                     ≡⟨ cong (zw _∷_ _) (up-nat (x ∷_) (choose n xs)) 
    zw _∷_ (choose (suc n) xs) (cmap (vmap (x ∷_)) (up (choose n xs)))
                                                                                     ≡⟨ cong (zw _∷_ _) (cong (cmap (vmap (x ∷_))) (up-sub n xs)) 
    zw _∷_ (choose (suc n) xs) (cmap (vmap (x ∷_)) (cmap sub (choose (suc n) xs)))
                                                                                     ≡⟨ cong (zw _∷_ _) (cmap-comp _ _ _) 
    zw _∷_ (choose (suc n) xs) (cmap (vmap (x ∷_)  sub) (choose (suc n) xs))
                                                                                     ≡˘⟨ zw-sub x (choose (suc n) xs) 
    cmap sub (cmap (x ∷_) (choose (suc n) xs))