{-# OPTIONS --cubical-compatible --safe #-}
module Data.Nat.Combinatorics.Specification where
open import Data.Bool using (T; true; false)
open import Data.Nat.Base
open import Data.Nat.DivMod
open import Data.Nat.Divisibility
open import Data.Nat.Properties
open import Data.Nat.Combinatorics.Base
open import Data.Sum.Base using (inj₁; inj₂)
open import Relation.Binary.PropositionalEquality
  using (_≡_; trans; _≢_)
open import Relation.Nullary.Decidable using (yes; no; does)
open import Relation.Nullary.Negation using (contradiction)
open import Relation.Binary.PropositionalEquality
  using (subst; refl; sym; cong; cong₂)
import Algebra.Properties.CommutativeSemigroup *-commutativeSemigroup as *-CS
private
  ≤ᵇ⇒≤′ : ∀ {m n} → (m ≤ᵇ n) ≡ true → m ≤ n
  ≤ᵇ⇒≤′ {m} {n} eq = ≤ᵇ⇒≤ m n (subst T (sym eq) _)
nP′k≡n!/[n∸k]! : ∀ {n k} → k ≤ n → n P′ k ≡ (n ! / (n ∸ k) !) {{(n ∸ k) !≢0}}
nP′k≡n!/[n∸k]! {n} {zero}  z≤n = sym (n/n≡1 (n !) {{n !≢0}})
nP′k≡n!/[n∸k]! {n} {suc k} k<n = begin-equality
  (n ∸ k) * (n P′ k)             ≡⟨ cong ((n ∸ k) *_) (nP′k≡n!/[n∸k]! (<⇒≤ k<n)) ⟩
  (n ∸ k) * (n ! / (n ∸ k) !)    ≡⟨ *-/-assoc (n ∸ k) (m≤n⇒m!∣n! (m∸n≤m n k)) ⟨
  (((n ∸ k) * n !) / (n ∸ k) !)  ≡⟨ m*n/m!≡n/[m∸1]! (n ∸ k) (n !) ⟩
  (n ! / (pred (n ∸ k) !))       ≡⟨ /-congʳ (cong _! (pred[m∸n]≡m∸[1+n] n k)) ⟩
  (n ! / (n ∸ suc k) !)          ∎
  where
  open ≤-Reasoning
  instance
    _ = (n ∸ k) !≢0
    _ = (pred (n ∸ k)) !≢0
    _ = (n ∸ suc k) !≢0
    _ = >-nonZero (m<n⇒0<n∸m k<n)
nP′k≡n[n∸1P′k∸1] : ∀ n k → .{{NonZero n}} → .{{NonZero k}} →
                   n P′ k ≡ n * (pred n P′ pred k)
nP′k≡n[n∸1P′k∸1] n           (suc zero)            = refl
nP′k≡n[n∸1P′k∸1] n@(suc n-1) k@(suc k-1@(suc k-2)) = begin-equality
  n P′ k                        ≡⟨⟩
  (n ∸ k-1) * (n P′ k-1)        ≡⟨ cong ((n ∸ k-1) *_) (nP′k≡n[n∸1P′k∸1] n k-1) ⟩
  (n ∸ k-1) * (n * (n-1 P′ k-2))  ≡⟨ x∙yz≈y∙xz (n ∸ k-1) n (n-1 P′ k-2) ⟩
  n * ((n ∸ k-1) * (n-1 P′ k-2))  ≡⟨⟩
  n * (n-1 P′ k-1)              ∎
  where open ≤-Reasoning; open *-CS
P′-rec : ∀ {n k} → k ≤ n → .{{NonZero k}} →
        n P′ k ≡ k * (pred n P′ pred k) + pred n P′ k
P′-rec n@{suc n-1} k@{suc k-1} k≤n = begin-equality
  n P′ k                                        ≡⟨ nP′k≡n[n∸1P′k∸1] n k ⟩
  n * (n-1 P′ k-1)                              ≡⟨ cong (_* (n-1 P′ k-1)) (m+[n∸m]≡n {k} {n} k≤n) ⟨
  (k + (n ∸ k)) * (n-1 P′ k-1)                  ≡⟨ *-distribʳ-+ (n-1 P′ k-1) k (n ∸ k) ⟩
  k * (n-1 P′ k-1) + (n-1 ∸ k-1) * (n-1 P′ k-1) ≡⟨⟩
  k * (n-1 P′ k-1) + (n-1 P′ k)                 ∎
  where open ≤-Reasoning
nP′n≡n! : ∀ n → n P′ n ≡ n !
nP′n≡n! n = begin-equality
  n P′ n          ≡⟨ nP′k≡n!/[n∸k]! (≤-refl {n}) ⟩
  n ! / (n ∸ n) ! ≡⟨ /-congʳ (cong _! (n∸n≡0 n)) ⟩
  n ! / 0 !       ≡⟨⟩
  n ! / 1         ≡⟨ n/1≡n (n !) ⟩
  n !             ∎
  where open ≤-Reasoning; instance _ = (n ∸ n) !≢0
k!∣nP′k : ∀ {n k} → k ≤ n → k ! ∣ n P′ k
k!∣nP′k {n}         {zero}      k≤n = ∣-refl
k!∣nP′k n@{suc n-1} k@{suc k-1} k≤n@(s≤s k-1≤n-1) with k-1 ≟ n-1
... | yes refl = ∣-reflexive (sym (nP′n≡n! n))
... | no  k≢n  = begin
  k !                           ≡⟨⟩
  k * k-1 !                     ∣⟨ ∣m∣n⇒∣m+n (*-monoʳ-∣ k (k!∣nP′k k-1≤n-1)) ( k!∣nP′k (≤∧≢⇒< k-1≤n-1 k≢n)) ⟩
  k * (n-1 P′ k-1) + (n-1 P′ k) ≡⟨ P′-rec k≤n ⟨
  n P′ k                        ∎
  where open ∣-Reasoning
[n∸k]!k!∣n! : ∀ {n k} → k ≤ n → (n ∸ k) ! * k ! ∣ n !
[n∸k]!k!∣n! {n} {k} k≤n = m∣n/o⇒o*m∣n (m≤n⇒m!∣n! (m∸n≤m n k))
  (subst (k ! ∣_) (nP′k≡n!/[n∸k]! k≤n) (k!∣nP′k k≤n))
  where instance _ = (n ∸ k) !≢0
nPk≡n!/[n∸k]! : ∀ {n k} → k ≤ n → n P k ≡ (n ! / (n ∸ k) !) {{(n ∸ k) !≢0}}
nPk≡n!/[n∸k]! {n} {k} k≤n with k ≤ᵇ n in eq
... | true  = nP′k≡n!/[n∸k]! k≤n
... | false = contradiction (≤⇒≤ᵇ k≤n) (subst T eq)
k>n⇒nPk≡0 : ∀ {n k} → k > n → n P k ≡ 0
k>n⇒nPk≡0 {n} {k} k>n with k ≤ᵇ n in eq
... | true  = contradiction (≤ᵇ⇒≤′ eq) (<⇒≱ k>n)
... | false = refl
nC′k≡n!/k![n-k]! : ∀ {n k} → k ≤ n → n C′ k ≡ (n ! / (k ! * (n ∸ k) !)) {{k !* (n ∸ k) !≢0}}
nC′k≡n!/k![n-k]! {n} {k} k≤n = begin-equality
  n C′ k                  ≡⟨⟩
  (n P′ k) / k !          ≡⟨ /-congˡ (nP′k≡n!/[n∸k]! k≤n) ⟩
  (n ! / (n ∸ k) !) / k ! ≡⟨ m/n/o≡m/[n*o] (n !) ((n ∸ k) !) (k !) ⟩
  n ! / ((n ∸ k) ! * k !) ≡⟨ /-congʳ (*-comm ((n ∸ k)!) (k !)) ⟩
  n ! / (k ! * (n ∸ k) !) ∎
  where
  open ≤-Reasoning
  instance
    _ = k !≢0
    _ = (n ∸ k) !≢0
    _ = (n ∸ k) !* k !≢0
    _ = k !* (n ∸ k) !≢0
C′-sym : ∀ {n k} → k ≤ n → n C′ (n ∸ k) ≡ n C′ k
C′-sym {n} {k} k≤n = begin-equality
  n C′ (n ∸ k)                        ≡⟨ nC′k≡n!/k![n-k]! {n} {n ∸ k} (m≤n⇒n∸m≤n k≤n) ⟩
  n ! / ((n ∸ k) ! * (n ∸ (n ∸ k)) !) ≡⟨ /-congʳ (cong ((n ∸ k) ! *_) (cong _! (m∸[m∸n]≡n k≤n))) ⟩
  n ! / ((n ∸ k) ! * k !)             ≡⟨ /-congʳ (*-comm ((n ∸ k) !) (k !)) ⟩
  n ! / (k ! * (n ∸ k) !)             ≡⟨ nC′k≡n!/k![n-k]! k≤n ⟨
  n C′ k                              ∎
  where
  open ≤-Reasoning
  instance
    _ = (n ∸ k) !* k !≢0
    _ = k !* (n ∸ k) !≢0
    _ = (n ∸ k) !* (n ∸ (n ∸ k)) !≢0
nCk≡n!/k![n-k]! : ∀ {n k} → k ≤ n →
                  n C k ≡ (n ! / (k ! * (n ∸ k) !)) {{k !* (n ∸ k) !≢0}}
nCk≡n!/k![n-k]! {n} {k} k≤n with k ≤ᵇ n in eq2
... | false = contradiction (≤⇒≤ᵇ k≤n) (subst T eq2)
... | true  with ⊓-sel k (n ∸ k)
...   | inj₁ k⊓[n∸k]≡k   rewrite k⊓[n∸k]≡k   = nC′k≡n!/k![n-k]! k≤n
...   | inj₂ k⊓[n∸k]≡n∸k rewrite k⊓[n∸k]≡n∸k = trans (C′-sym k≤n) (nC′k≡n!/k![n-k]! k≤n)
k>n⇒nCk≡0 : ∀ {n k} → k > n → n C k ≡ 0
k>n⇒nCk≡0 {n} {k} k>n with k ≤ᵇ n in eq
... | true  = contradiction (≤ᵇ⇒≤′ eq) (<⇒≱ k>n)
... | false = refl