\import Arith.Nat
\import Data.Array
\import Data.Array.EPerm
\import Data.Array.Perm
\import Data.List(List, Sort, headDef, length)
\import Function.Meta
\import Order.LinearOrder
\import Order.PartialOrder
\import Paths
\import Paths.Meta
\func sort {A : LinearOrder.Dec} (l : Array A) : Array A l.len
=> transport (\lam n => Array A n) (inv (Sort.Perm.perm_length (Sort.Insertion.sort-perm _)) *> toList_length) $ fromList (Sort.Insertion.sort (toList l))
\where {
\func IsSorted {A : Preorder} (l : Array A) => \Pi {i j : Fin l.len} -> i NatOrder.< j -> l i <= l j
\lemma sorted_transport {A : Preorder} {n m : Nat} {l : Array A n} (p : n = m) (s : IsSorted l) : IsSorted (transport (\lam n => Array A n) p l) \elim p
| idp => s
\lemma list_sorted {A : Preorder} {l : List A} (s : Sort.Sorted l) : IsSorted (fromList l) \elim l, s
| List.nil, Sort.sorted-nil => \lam {i} => \case i
| x List.:: l, Sort.sorted-cons p s => \lam {i} {j} p => \case \elim i, \elim j, \elim p \with {
| 0, suc j, NatOrder.zero<suc => p <=∘ headDef_fromList s
| suc i, suc j, NatOrder.suc<suc p => list_sorted s p
}
\where {
\lemma headDef_fromList {a : A} {l : List A} {j : Fin (length l)} (s : Sort.Sorted l) : headDef a l <= fromList l j \elim l, j, s
| b List.:: l, 0, _ => <=-refl
| b List.:: l, suc j, Sort.sorted-cons p s => p <=∘ headDef_fromList s
}
\lemma sorted_list {A : Preorder} {l : Array A} (s : IsSorted l) : Sort.Sorted (toList l) \elim l
| nil => Sort.sorted-nil
| a :: {n} l => Sort.sorted-cons (\case \elim n, \elim l, \elim s \with {
| 0, nil, s => <=-refl
| suc n, b :: l, s => s {0} {1} NatOrder.zero<suc
}) $ sorted_list \lam p => s (NatOrder.suc<suc p)
\lemma sort-sorted {A : LinearOrder.Dec} {l : Array A} : IsSorted (sort l)
=> sorted_transport _ (list_sorted (Sort.Insertion.sort-sorted _))
\sfunc sort-perm {A : LinearOrder.Dec} {n : Nat} {l : Array A n} : Perm l (sort l)
=> Perm.perm-sym $ EPerm.EPerm_Perm_transport (EPerm.eperm-sym sort-eperm) _
\where {
\func list_perm {A : \Type} {l l' : List A} (p : Sort.Perm l l') : EPerm (fromList l) (fromList l') \elim l, l', p
| List.nil, List.nil, Sort.perm-nil => eperm-nil
| x List.:: l, y List.:: l', Sort.perm-:: p q => eperm-:: p (list_perm q)
| x List.:: (x' List.:: l), y List.:: (y' List.:: l'), Sort.perm-swap p1 p2 q => eperm-swap p1 p2 (pmap fromList q)
| l, l', Sort.perm-trans p1 p2 => eperm-trans (list_perm p1) (list_perm p2)
\func sort-eperm {A : LinearOrder.Dec} {l : Array A} : EPerm l (fromList (Sort.Insertion.sort (toList l)))
=> transport (EPerm __ _) fromList_toList $ list_perm (Sort.Insertion.sort-perm _)
}
\func perm_list {A : \Type} {n : Nat} {l l' : Array A n} (p : Perm l l') : Sort.Perm (toList l) (toList l') \elim n, l, l', p
| 0, nil, nil, perm-nil => Sort.perm-nil
| suc n, x :: l, y :: l', perm-:: p q => Sort.perm-:: p (perm_list q)
| suc (suc n), x :: (x' :: l), y :: (y' :: l'), perm-swap p1 p2 q => Sort.perm-swap p1 p2 (pmap toList q)
| n, l, l', perm-trans p1 p2 => Sort.perm-trans (perm_list p1) (perm_list p2)
\lemma perm_= {A : LinearOrder.Dec} {n : Nat} {l l' : Array A n} (p : Perm l l') (s : IsSorted l) (s' : IsSorted l') : l = l'
=> exts $ array-unext $ inv fromList_toList *> pmap fromList (inv (Sort.Insertion.sorted_sort (sorted_list s)) *> Sort.Insertion.perm_sort (perm_list p) *> Sort.Insertion.sorted_sort (sorted_list s')) *> fromList_toList
}