{-# OPTIONS --safe #-}
module Cubical.Data.Int.MoreInts.QuoInt.Properties where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Function
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Isomorphism

open import Cubical.Functions.FunExtEquiv

open import Cubical.Relation.Nullary

open import Cubical.Data.Nat as  using (; zero; suc)
open import Cubical.Data.Bool as Bool using (Bool; not; notnot)
open import Cubical.Data.Empty
open import Cubical.Data.Unit renaming (Unit to )

import Cubical.Data.Int as Int
open import Cubical.Data.Int.MoreInts.QuoInt.Base renaming (elim to ℤelim)

·S-comm :  x y  x ·S y  y ·S x
·S-comm = Bool.⊕-comm

·S-assoc :  x y z  x ·S (y ·S z)  (x ·S y) ·S z
·S-assoc = Bool.⊕-assoc

not-·Sˡ :  x y  not (x ·S y)  not x ·S y
not-·Sˡ = Bool.not-⊕ˡ


snotz :  s n s'  ¬ (signed s (suc n)  signed s' zero)
snotz s n s' eq = subst  { (signed s (suc n))  
                           ; _                    }) eq tt


+-zeroʳ :  s m  m + signed s zero  m
+-zeroʳ s (signed s' zero) = signed-zero s s'
+-zeroʳ s (pos (suc n)) = cong sucℤ  (+-zeroʳ s (pos n))
+-zeroʳ s (neg (suc n)) = cong predℤ (+-zeroʳ s (neg n))
+-zeroʳ spos (posneg i) j = posneg (i  j)
+-zeroʳ sneg (posneg i) j = posneg (i  ~ j)

+-identityʳ :  m  m + pos zero  m
+-identityʳ = +-zeroʳ spos

sucℤ-+ʳ :  m n  sucℤ (m + n)  m + sucℤ n
sucℤ-+ʳ (signed _ zero) _ = refl
sucℤ-+ʳ (posneg _) _ = refl
sucℤ-+ʳ (pos (suc m)) n = cong sucℤ (sucℤ-+ʳ (pos m) n)
sucℤ-+ʳ (neg (suc m)) n =
  sucPredℤ (neg m + n) ∙∙
  sym (predSucℤ (neg m + n)) ∙∙
  cong predℤ (sucℤ-+ʳ (neg m) n)

-- I wonder if we could somehow use negEq to get this for free from the above...
predℤ-+ʳ :  m n  predℤ (m + n)  m + predℤ n
predℤ-+ʳ (signed _ zero) _ = refl
predℤ-+ʳ (posneg _) _ = refl
predℤ-+ʳ (neg (suc m)) n = cong predℤ (predℤ-+ʳ (neg m) n)
predℤ-+ʳ (pos (suc m)) n =
  predSucℤ (pos m + n) ∙∙
  sym (sucPredℤ (pos m + n)) ∙∙
  cong sucℤ (predℤ-+ʳ (pos m) n)

+-comm :  m n  m + n  n + m
+-comm (signed s zero) n = sym (+-zeroʳ s n)
+-comm (pos (suc m)) n = cong sucℤ  (+-comm (pos m) n)  sucℤ-+ʳ  n (pos m)
+-comm (neg (suc m)) n = cong predℤ (+-comm (neg m) n)  predℤ-+ʳ n (neg m)
+-comm (posneg i) n = lemma n i
  where
  -- get some help from:
  -- https://www.codewars.com/kata/reviews/5c878e3ef1abb10001e32eb1/groups/5cca3f9e840f4b0001d8ac98
  lemma :  n   i  (posneg i + n)  (n + posneg i))
          [ sym (+-zeroʳ spos n)  sym (+-zeroʳ sneg n) ]
  lemma (pos zero) i j = posneg (i  j)
  lemma (pos (suc n)) i = cong sucℤ (lemma (pos n) i)
  lemma (neg zero) i j = posneg (i  ~ j)
  lemma (neg (suc n)) i = cong predℤ (lemma (neg n) i)
  lemma (posneg i) j k = posneg ((i  ~ k)  (i  j)  (j  k))

sucℤ-+ˡ :  m n  sucℤ (m + n)  sucℤ m + n
sucℤ-+ˡ (pos _) n = refl
sucℤ-+ˡ (neg zero) n = refl
sucℤ-+ˡ (neg (suc m)) n = sucPredℤ _
sucℤ-+ˡ (posneg _) n = refl

-- I wonder if we could somehow use negEq to get this for free from the above...
predℤ-+ˡ :  m n  predℤ (m + n)  predℤ m + n
predℤ-+ˡ (pos zero) n = refl
predℤ-+ˡ (pos (suc m)) n = predSucℤ _
predℤ-+ˡ (neg _) n = refl
predℤ-+ˡ (posneg _) n = refl

+-assoc :  m n o  m + (n + o)  m + n + o
+-assoc (signed s zero) n o = refl
+-assoc (posneg i) n o = refl
+-assoc (pos (suc m)) n o = cong sucℤ  (+-assoc (pos m) n o)  sucℤ-+ˡ  (pos m + n) o
+-assoc (neg (suc m)) n o = cong predℤ (+-assoc (neg m) n o)  predℤ-+ˡ (neg m + n) o


sucℤ-inj :  m n  sucℤ m  sucℤ n  m  n
sucℤ-inj m n p = sym (predSucℤ m)  cong predℤ p  predSucℤ n

predℤ-inj :  m n  predℤ m  predℤ n  m  n
predℤ-inj m n p = sym (sucPredℤ m)  cong sucℤ p  sucPredℤ n

+-injˡ :  o m n  o + m  o + n  m  n
+-injˡ (signed _ zero) _ _ p = p
+-injˡ (posneg _)      _ _ p = p
+-injˡ (pos (suc o)) m n p = +-injˡ (pos o) m n (sucℤ-inj  _ _ p)
+-injˡ (neg (suc o)) m n p = +-injˡ (neg o) m n (predℤ-inj _ _ p)

+-injʳ :  m n o  m + o  n + o  m  n
+-injʳ m n o p = +-injˡ o m n (+-comm o m  p  +-comm n o)


·-comm :  m n  m · n  n · m
·-comm m n i = signed (·S-comm (sign m) (sign n) i) (ℕ.·-comm (abs m) (abs n) i)

·-identityˡ :  n  pos 1 · n  n
·-identityˡ n = cong (signed (sign n)) (ℕ.+-zero (abs n))  signed-inv n

·-identityʳ :  n  n · pos 1  n
·-identityʳ n = ·-comm n (pos 1)  ·-identityˡ n

·-zeroˡ :  {s} n  signed s zero · n  signed s zero
·-zeroˡ _ = signed-zero _ _

·-zeroʳ :  {s} n  n · signed s zero  signed s zero
·-zeroʳ n = cong (signed _) (sym (ℕ.0≡m·0 (abs n)))  signed-zero _ _

·-signed-pos :  {s} m n  signed s m · pos n  signed s (m ℕ.· n)
·-signed-pos {s} zero n = ·-zeroˡ {s} (pos n)
·-signed-pos {s} (suc m) n i = signed (·S-comm s (sign-pos n i) i) (suc m ℕ.· n)


-- this proof is why we defined ℤ using `signed` instead of `pos` and `neg`
-- based on that in: https://github.com/danr/Agda-Numerics
·-assoc :  m n o  m · (n · o)  m · n · o

·-assoc (signed s zero) n o =
  ·-zeroˡ (n · o)
·-assoc m@(signed _ (suc _)) (signed s zero) o =
  ·-zeroʳ {sign o} m  signed-zero _ _  cong ( o) (sym (·-zeroʳ {s} m))
·-assoc m@(signed _ (suc _)) n@(signed _ (suc _)) (signed s zero) =
  cong (m ·_) (·-zeroʳ {s} n)  ·-zeroʳ {s} m  sym (·-zeroʳ {s} (m · n))

·-assoc (signed sm (suc m)) (signed sn (suc n)) (signed so (suc o)) i =
  signed (·S-assoc sm sn so i) (ℕ.·-assoc (suc m) (suc n) (suc o) i)

·-assoc (posneg i) n o j =
  isSet→isSet' isSetℤ (·-assoc (pos zero) n o) (·-assoc (neg zero) n o)
                       i  posneg i · (n · o))  i  posneg i · n · o) i j
·-assoc m@(signed _ (suc _)) (posneg i) o j =
  isSet→isSet' isSetℤ (·-assoc m (pos zero) o) (·-assoc m (neg zero) o)
                       i  m · (posneg i · o))  i  m · posneg i · o) i j
·-assoc m@(signed _ (suc _)) n@(signed _ (suc _)) (posneg i) j =
  isSet→isSet' isSetℤ (·-assoc m n (pos zero)) (·-assoc m n (neg zero))
                       i  m · (n · posneg i))  i  m · n · posneg i) i j


negateSuc :  n  - sucℤ n  predℤ (- n)
negateSuc n i = - sucℤ (negate-invol n (~ i))

negatePred :  n  - predℤ n  sucℤ (- n)
negatePred n i = negate-invol (sucℤ (- n)) i

negate-+ :  m n  - (m + n)   (- m) + (- n)
negate-+ (signed _ zero) n = refl
negate-+ (posneg _)      n = refl
negate-+ (pos (suc m))   n = negateSuc  (pos m + n)  cong predℤ (negate-+ (pos m) n)
negate-+ (neg (suc m))   n = negatePred (neg m + n)  cong sucℤ  (negate-+ (neg m) n)


negate-·ˡ :  m n  - (m · n)  (- m) · n
negate-·ˡ (signed _ zero) n = signed-zero (not (sign n)) (sign n)
negate-·ˡ (signed ss (suc m)) n i = signed (not-·Sˡ ss (sign n) i) (suc m ℕ.· abs n)
negate-·ˡ (posneg i) n j =
  isSet→isSet' isSetℤ (signed-zero (not (sign n)) _) (signed-zero _ _)
                      refl  i  posneg (~ i) · n) i j


signed-distrib :  s m n  signed s (m ℕ.+ n)  signed s m + signed s n
signed-distrib s zero n = refl
signed-distrib spos (suc m) n = cong sucℤ  (signed-distrib spos m n)
signed-distrib sneg (suc m) n = cong predℤ (signed-distrib sneg m n)

·-pos-suc :  m n  pos (suc m) · n  n + pos m · n
·-pos-suc m n = signed-distrib (sign n) (abs n) (m ℕ.· abs n)
                  i  signed-inv n i + signed (sign-pos m (~ i) ·S sign n) (m ℕ.· abs n))


-- the below is based on that in: https://github.com/danr/Agda-Numerics

·-distribˡ-pos :  o m n  (pos o · m) + (pos o · n)  pos o · (m + n)
·-distribˡ-pos zero m n = signed-zero (sign n) (sign (m + n))
·-distribˡ-pos (suc o) m n =
  pos (suc o) · m + pos (suc o) · n ≡[ i ]⟨ ·-pos-suc o m i + ·-pos-suc o n i 
  m + pos o · m + (n + pos o · n)   ≡⟨ +-assoc (m + pos o · m) n (pos o · n) 
  m + pos o · m + n + pos o · n     ≡[ i ]⟨ +-assoc m (pos o · m) n (~ i) + pos o · n 
  m + (pos o · m + n) + pos o · n   ≡[ i ]⟨ m + +-comm (pos o · m) n i + pos o · n 
  m + (n + pos o · m) + pos o · n   ≡[ i ]⟨ +-assoc m n (pos o · m) i + pos o · n 
  m + n + pos o · m + pos o · n     ≡⟨ sym (+-assoc (m + n) (pos o · m) (pos o · n)) 
  m + n + (pos o · m + pos o · n)   ≡⟨ cong ((m + n) +_) (·-distribˡ-pos o m n) 
  m + n + pos o · (m + n)           ≡⟨ sym (·-pos-suc o (m + n)) 
  pos (suc o) · (m + n) 

·-distribˡ-neg :  o m n  (neg o · m) + (neg o · n)  neg o · (m + n)
·-distribˡ-neg o m n =
     neg o · m  +    neg o · n  ≡[ i ]⟨ negate-·ˡ (pos o) m (~ i) + negate-·ˡ (pos o) n (~ i) 
  - (pos o · m) + - (pos o · n) ≡⟨ sym (negate-+ (pos o · m) (pos o · n)) 
  - (pos o · m + pos o · n)     ≡⟨ cong -_ (·-distribˡ-pos o m n) 
  - (pos o · (m + n))           ≡⟨ negate-·ˡ (pos o) (m + n) 
     neg o · (m + n)            

·-distribˡ :  o m n  (o · m) + (o · n)  o · (m + n)
·-distribˡ (pos o) m n = ·-distribˡ-pos o m n
·-distribˡ (neg o) m n = ·-distribˡ-neg o m n
·-distribˡ (posneg i) m n j =
  isSet→isSet' isSetℤ (·-distribˡ-pos zero m n) (·-distribˡ-neg zero m n)
                       i  posneg i · n)  i  posneg i · (m + n)) i j

·-distribʳ :  m n o  (m · o) + (n · o)  (m + n) · o
·-distribʳ m n o =  i  ·-comm m o i + ·-comm n o i)  ·-distribˡ o m n  ·-comm o (m + n)


sign-pos-suc-· :  m n  sign (pos (suc m) · n)  sign n
sign-pos-suc-· m (signed s zero) = sign-pos (suc m ℕ.· zero)
sign-pos-suc-· m (posneg i)      = sign-pos (suc m ℕ.· zero)
sign-pos-suc-· m (signed s (suc n)) = refl

·-injˡ :  o m n  pos (suc o) · m  pos (suc o) · n  m  n
·-injˡ o m n p = sym (signed-inv m)   i  signed (sign-eq i) (abs-eq i))  signed-inv n
  where sign-eq = sym (sign-pos-suc-· o m)  cong sign p  sign-pos-suc-· o n
        abs-eq = ℕ.inj-sm· {o} (cong abs p)

·-injʳ :  m n o  m · pos (suc o)  n · pos (suc o)  m  n
·-injʳ m n o p = ·-injˡ o m n (·-comm (pos (suc o)) m  p  ·-comm n (pos (suc o)))

private
  _+'_ :     
  _+'_ = Iso.fun (binaryOpIso isoIntℤ) Int._+_

  sucℤ→Int :  (n : )  ℤ→Int (sucℤ n)  Int.sucℤ (ℤ→Int n)
  sucℤ→Int (pos n) = refl
  sucℤ→Int (neg zero) = refl
  sucℤ→Int (neg (suc zero)) = refl
  sucℤ→Int (neg (suc (suc n))) = refl
  sucℤ→Int (posneg i) = refl

  predℤ→Int :  (n : )  ℤ→Int (predℤ n)  Int.predℤ (ℤ→Int n)
  predℤ→Int (pos zero) = refl
  predℤ→Int (pos (suc n)) = refl
  predℤ→Int (neg zero) = refl
  predℤ→Int (neg (suc n)) = refl
  predℤ→Int (posneg i) = refl

ℤ→IntIsHom+ :  (n m : )  ℤ→Int (n + m)  (ℤ→Int n) Int.+ (ℤ→Int m)
ℤ→IntIsHom+ n m = (ℤelim  n   (m : )  ℤ→Int (n + m)  (ℤ→Int n) Int.+ (ℤ→Int m)) posℤ→Int+Int≡+ negsucℤ→Int+Int≡+ n) m
  where
  posℤ→Int+Int≡+ :  (n : ) (m : )  ℤ→Int ((pos n) + m)  (ℤ→Int (pos n)) Int.+ (ℤ→Int m)
  posℤ→Int+Int≡+ zero m =
    ℤ→Int (pos zero + m)
      ≡⟨ cong ℤ→Int (+-comm (pos zero) m) 
    ℤ→Int (m + pos zero)
      ≡⟨ cong ℤ→Int (+-zeroʳ spos m) 
    ℤ→Int m
      ≡⟨ Int.pos0+ (ℤ→Int m) 
    (ℤ→Int (pos zero)) Int.+ (ℤ→Int m) 
  posℤ→Int+Int≡+ (suc n) m =
    ℤ→Int ((pos (suc n)) + m)
      ≡⟨ cong ℤ→Int (sym (sucℤ-+ˡ (pos n) m)) 
    ℤ→Int (sucℤ ((pos n) + m))
      ≡⟨ sucℤ→Int ((pos n) + m) 
    Int.sucℤ (ℤ→Int ((pos n) + m))
      ≡⟨ cong Int.sucℤ (posℤ→Int+Int≡+ n m) 
    Int.sucℤ ((Int.pos n) Int.+ (ℤ→Int m))
      ≡⟨ Int.sucℤ+ (Int.pos n) (ℤ→Int m) 
    (ℤ→Int (pos (suc n))) Int.+ (ℤ→Int m) 

  negsucℤ→Int+Int≡+ :  (n : ) (m : )  ℤ→Int ((neg (suc n)) + m)  (ℤ→Int (neg (suc n))) Int.+ (ℤ→Int m)
  negsucℤ→Int+Int≡+ zero m =
    ℤ→Int ((neg (suc zero)) +  m)
      ≡⟨ cong ℤ→Int (predℤ-+ˡ (neg zero) m) 
    ℤ→Int (predℤ ((neg zero) + m))
      ≡⟨ predℤ→Int ((neg zero) + m) 
    Int.predℤ (ℤ→Int ((neg zero) + m))
      ≡⟨ cong Int.predℤ (posℤ→Int+Int≡+ zero m) 
    Int.predℤ ((Int.pos zero) Int.+ (ℤ→Int m))
      ≡⟨ Int.predℤ+ (Int.pos zero) (ℤ→Int m) 
    Int.negsuc zero Int.+ ℤ→Int m 
  negsucℤ→Int+Int≡+ (suc n) m =
    ℤ→Int ((neg (suc (suc n))) + m)
      ≡⟨ cong ℤ→Int (predℤ-+ˡ (neg (suc n)) m) 
    ℤ→Int (predℤ ((neg (suc n)) + m))
      ≡⟨ predℤ→Int ((neg (suc n)) + m) 
    Int.predℤ (ℤ→Int ((neg (suc n)) + m))
      ≡⟨ cong Int.predℤ (negsucℤ→Int+Int≡+ n m) 
    Int.predℤ ((Int.negsuc n) Int.+ ℤ→Int m)
      ≡⟨ Int.predℤ+ (Int.negsuc n) (ℤ→Int m) 
    Int.negsuc (suc n) Int.+ ℤ→Int m 

private
  +'≡+ : _+'_  _+_
  +'≡+ =
    _+'_
      ≡⟨ sym (cong (_∘_ (_∘_ Int→ℤ)) (funExt₂ ℤ→IntIsHom+)) 
     n   m  (Int→ℤ (ℤ→Int (n + m)))))
      ≡⟨ funExt₂  n m  (Iso.rightInv isoIntℤ (n + m))) 
    _+_ 

  op≡Intℤ : (Int.ℤ  Int.ℤ  Int.ℤ)  (    )
  op≡Intℤ = isoToPath (binaryOpIso isoIntℤ)

  +Int≡+' :  i  op≡Intℤ i) [ Int._+_  _+'_ ]
  +Int≡+' = transport-filler op≡Intℤ Int._+_

+Int≡+ :  i  (op≡Intℤ  refl) i) [ Int._+_  _+_ ]
+Int≡+ = compPathP +Int≡+' +'≡+

ℤ→IntIsHom- :  (n : )  ℤ→Int (- n)  Int.- (ℤ→Int n)
ℤ→IntIsHom- n = ℤelim  n  ℤ→Int (- n)  Int.- (ℤ→Int n)) posℤ→Int-Int≡- negsucℤ→Int-Int≡- n
  where
  posℤ→Int-Int≡- :  (n : )  ℤ→Int (- (pos n))  Int.- (ℤ→Int (pos n))
  posℤ→Int-Int≡- zero = refl
  posℤ→Int-Int≡- (suc n) = refl

  negsucℤ→Int-Int≡- :  (n : )  ℤ→Int (- (neg (suc n)))  Int.- (ℤ→Int (neg (suc n)))
  negsucℤ→Int-Int≡- zero = refl
  negsucℤ→Int-Int≡- (suc n) = refl

private
  -'_ :   
  -'_ = Iso.fun (endoIso isoIntℤ) (Int.-_)

  -'≡- : -'_  -_
  -'≡- =
    -'_
      ≡⟨ sym (cong (_∘_ Int→ℤ) (funExt ℤ→IntIsHom-)) 
     n  (Int→ℤ (ℤ→Int (- n))))
      ≡⟨ funExt  n  (Iso.rightInv isoIntℤ (- n))) 
    -_ 

  endo≡Intℤ : (Int.ℤ  Int.ℤ)  (  )
  endo≡Intℤ = isoToPath (endoIso isoIntℤ)

  -Int≡-' :  i  endo≡Intℤ i) [ Int.-_  -'_ ]
  -Int≡-' = transport-filler endo≡Intℤ (Int.-_)

-Int≡- :  i  (endo≡Intℤ  refl) i) [ Int.-_  -_ ]
-Int≡- = compPathP -Int≡-' -'≡-

ℤ→IntIsHom· :  (n m : )  ℤ→Int (n · m)  (ℤ→Int n) Int.· (ℤ→Int m)
ℤ→IntIsHom· n m = (ℤelim  n   (m : )  ℤ→Int (n · m)  (ℤ→Int n) Int.· (ℤ→Int m)) posℤ→Int·Int≡· negsucℤ→Int·Int≡· n) m
  where
  posℤ→Int·Int≡· :  (n : ) (m : )  ℤ→Int ((pos n) · m)  (ℤ→Int (pos n)) Int.· (ℤ→Int m)
  posℤ→Int·Int≡· zero m =
    ℤ→Int ((pos zero) · m)
      ≡⟨ sym (cong ℤ→Int (sym (·-zeroˡ {s = spos} m))) 
    (ℤ→Int (pos zero)) Int.· (ℤ→Int m) 
  posℤ→Int·Int≡· (suc n) m =
    ℤ→Int ((pos (suc n)) · m)
      ≡⟨ cong ℤ→Int (·-pos-suc n m) 
    ℤ→Int (m + ((pos n) · m))
      ≡⟨ ℤ→IntIsHom+ m ((pos n) · m) 
    (ℤ→Int m) Int.+ ℤ→Int ((pos n) · m)
      ≡⟨ cong  k  (ℤ→Int m) Int.+ k) (posℤ→Int·Int≡· n m) 
    (ℤ→Int (pos (suc n))) Int.· (ℤ→Int m) 

  negsucℤ→Int·Int≡· :  (n : ) (m : )  ℤ→Int ((neg (suc n)) · m)  (ℤ→Int (neg (suc n))) Int.· (ℤ→Int m)
  negsucℤ→Int·Int≡· zero m =
    ℤ→Int (neg (suc zero) · m)
      ≡⟨ cong  k  ℤ→Int (- k)) (·-identityˡ m) 
    ℤ→Int (- m)
      ≡⟨ ℤ→IntIsHom- m 
    (ℤ→Int (neg (suc zero))) Int.· (ℤ→Int m) 
  negsucℤ→Int·Int≡· (suc n) m =
    ℤ→Int ((neg (suc (suc n))) · m)
      ≡⟨ cong ℤ→Int (sym (·-distribʳ (neg (suc zero)) (neg (suc n)) m)) 
    ℤ→Int (((neg (suc zero)) · m) + ((neg (suc n)) · m))
      ≡⟨ cong (  k  ℤ→Int ((- k) + ((neg (suc n)) · m)))) (·-identityˡ m) 
    ℤ→Int ((- m) + ((neg (suc n)) · m))
      ≡⟨ ℤ→IntIsHom+ (- m) ((neg (suc n)) · m) 
    (ℤ→Int (- m)) Int.+ (ℤ→Int ((neg (suc n)) · m))
      ≡⟨ cong  k  k Int.+ (ℤ→Int ((neg (suc n)) · m))) (ℤ→IntIsHom- m) 
    Int.- (ℤ→Int m) Int.+ (ℤ→Int ((neg (suc n)) · m))
      ≡⟨ cong  k  Int.- (ℤ→Int m) Int.+ k) (negsucℤ→Int·Int≡· n m) 
    (ℤ→Int (neg (suc (suc n)))) Int.· (ℤ→Int m) 

private
  _·'_ :     
  _·'_ = Iso.fun (binaryOpIso isoIntℤ) Int._·_

  ·'≡· : _·'_  _·_
  ·'≡· =
    _·'_
      ≡⟨ sym (cong (_∘_ (_∘_ Int→ℤ)) (funExt₂ ℤ→IntIsHom·)) 
     n   m  (Int→ℤ (ℤ→Int (n · m)))))
      ≡⟨ funExt₂  n m  (Iso.rightInv isoIntℤ (n · m))) 
    _·_ 

  ·Int≡·' :  i  op≡Intℤ i) [ Int._·_  _·'_ ]
  ·Int≡·' = transport-filler op≡Intℤ Int._·_

·Int≡· :  i  (op≡Intℤ  refl) i) [ Int._·_  _·_ ]
·Int≡· = compPathP ·Int≡·' ·'≡·