{-# OPTIONS --prop --rewriting #-}

open import Examples.Sorting.Sequential.Comparable

module Examples.Sorting.Sequential.MergeSort.Split (M : Comparable) where

open Comparable M
open import Examples.Sorting.Sequential.Core M

open import Calf costMonoid
open import Calf.Types.Nat
open import Calf.Types.List
open import Calf.Types.Bounded costMonoid

open import Relation.Binary.PropositionalEquality as Eq using (_≡_; refl)
open import Data.Product using (_×_; _,_; ; proj₁; proj₂)
open import Data.Nat as Nat using (; zero; suc; _+_; _*_; ⌊_/2⌋; ⌈_/2⌉)
open import Data.Nat.Properties as N using (module ≤-Reasoning)


pair = Σ++ (list A) λ _  (list A)

split/clocked : cmp (Π nat λ _  Π (list A) λ _  F pair)
split/clocked zero    l        = ret ([] , l)
split/clocked (suc k) []       = ret ([] , [])
split/clocked (suc k) (x  xs) = bind (F pair) (split/clocked k xs) λ (l₁ , l₂)  ret (x  l₁ , l₂)

split/clocked/correct :  k k' l  k + k'  length l 
   ( λ l₁   λ l₂  split/clocked k l  ret (l₁ , l₂) × length l₁  k × length l₂  k' × l  (l₁ ++ l₂))
split/clocked/correct zero    k' l        refl u = [] , l , refl , refl , refl , refl
split/clocked/correct (suc k) k' (x  xs) h    u =
  let (l₁ , l₂ ,  , h₁ , h₂ , ) = split/clocked/correct k k' xs (N.suc-injective h) u in
  x  l₁ , l₂ , Eq.cong  e  bind (F pair) e _)  , Eq.cong suc h₁ , h₂ , prep x 

split/clocked/cost : cmp (Π nat λ _  Π (list A) λ _  cost)
split/clocked/cost _ _ = zero

split/clocked≤split/clocked/cost :  k l  IsBounded pair (split/clocked k l) (split/clocked/cost k l)
split/clocked≤split/clocked/cost zero    l        = bound/ret
split/clocked≤split/clocked/cost (suc k) []       = bound/ret
split/clocked≤split/clocked/cost (suc k) (x  xs) = bound/bind/const zero zero (split/clocked≤split/clocked/cost k xs) λ _  bound/ret

split : cmp (Π (list A) λ _  F pair)
split l = split/clocked  length l /2⌋ l

split/correct :  l 
   ( λ l₁   λ l₂  split l  ret (l₁ , l₂) × length l₁   length l /2⌋ × length l₂   length l /2⌉ × l  (l₁ ++ l₂))
split/correct l = split/clocked/correct  length l /2⌋  length l /2⌉ l (N.⌊n/2⌋+⌈n/2⌉≡n (length l))

split/cost : cmp (Π (list A) λ _  cost)
split/cost l = split/clocked/cost  length l /2⌋ l

split≤split/cost :  l  IsBounded pair (split l) (split/cost l)
split≤split/cost l = split/clocked≤split/clocked/cost  length l /2⌋ l