module Doubling where

open import Preliminaries
open import IntegerAlgebra

twist-alg : IntAlg ( + )
twist-alg .IntAlg.S = +-symm ∘ₑ +-congr id-iso ℤ.S
twist-alg .IntAlg.Z = inl ℤ.Z

double-alg : {X : Set}  IntAlg X  IntAlg X
double-alg X-alg .IntAlg.S = X-alg .IntAlg.S ∘ₑ X-alg .IntAlg.S
double-alg X-alg .IntAlg.Z = X-alg .IntAlg.Z

abstract
  halve :    + 
  halve = ℤ-rec twist-alg

  double :  +   
  double = +-ind (ℤ-rec (double-alg ℤ-alg)) (ℤ.S .fun  ℤ-rec (double-alg ℤ-alg))

  double-S : (x :  + )  ℤ.S .fun (double x)  double (twist-alg .IntAlg.S .fun x)
  double-S = +-ind  x  refl) λ x  symm (ℤ-rec-S (double-alg ℤ-alg) x)

  double-halve : (x : )  double (halve x)  x
  double-halve = ℤ-rec-uniq ℤ-alg
     x  ap double (ℤ-rec-S twist-alg x)  symm (double-S (halve x)))
    (ap double (ℤ-rec-Z _)  ℤ-rec-Z _)
     _  refl) refl

  halve-double : (x : )  halve (double (inl x))  inl x
  halve-double = ℤ-rec-uniq (double-alg twist-alg)
     x  ap halve (ℤ-rec-S _ _)  ℤ-rec-S _ _  ap (twist-alg .IntAlg.S .fun) (ℤ-rec-S twist-alg _))
    (ap halve (ℤ-rec-Z _)  ℤ-rec-Z _)  x  refl) refl

  halve-iso :    + 
  halve-iso .fun = halve
  halve-iso .inv = double
  halve-iso .inv-fun = double-halve
  halve-iso .fun-inv = +-ind halve-double λ x  ℤ-rec-S _ _  ap (twist-alg .IntAlg.S .fun) (halve-double x)