(libload "nat.scm")

; variable names
(add-var-name "i" "j" "k" "l" "m" "n" (py "nat"))

; f(i,n) = 
;    a binary function, which has an index as a first argument
(add-var-name "f" (py "nat=>nat=>nat"))


; The set is encoded as a ternary predicate,
; taking as arguments the binary function above,
; an index and the element which belongs to the set ...
(add-pvar-name "R" 
   (make-arity (py "nat=>nat=>nat") (py "nat") (py "nat")))

; ... and is defined inductively as follows:
; R(f,1,m) =
;    all n. m<n -> f(1,n)<f(k,m) -> bot

; R(f,Succ k,m) =
;    R(f,k,m) ! 
;    all n. R(f,k,m) -> m<n -> f(k,n)<f(k,m) -> bot


; Base case
(aga "Rright0" 
 (pf "all f, m. 
        all n. m<n -> f 1 n < f 1 m -> bot
        -> R f 1 m"
     ))

(aga "Rleft0" 
 (pf "all f, m. 
        R f 1 m
        -> all n. m<n -> f 1 n < f 1 m -> bot"
     ))

; Step
(aga "Rright" 
 (pf "all f, m, k. 
       (R f k m ! 
        all n.R f k n -> m<n -> 
               f (Succ k) n<f (Succ k) m -> bot)
       -> R f (Succ k) m"))

(aga "Rleft" 
 (pf "all f, m, n, k. 
        R f (Succ k) m
        -> (R f k m ! 
           all n.R f k n -> m<n -> 
                  f (Succ k) n<f (Succ k) m -> bot)"))


; alternatively
; define the predicate R inductively

; (add-ids
;  (list (list "R" (make-arity (py "nat=>nat") (py "nat") (py "nat"))))
;  '("all m. 
;       (all n. m < n -> f 1 n < f 1 m -> bot) ->
;       R f 1 m")
;  '("all k,m.
;       (R f k m ! 
;         all n.R f k n -> m<n -> 
;                f (Succ k) n<f (Succ k) m -> bot)
;        -> R f (Succ k) m")
; )


; Convention:
; Let R f 0 m = Q f 
; i.e. the initial unbounded set Q

; Remark:
; Since in the lemmas k starts from 1,
; we will formulate them here as being valid for Succ k

(aga "unboundedQ" (pf "all f, n. excl l. n < l ! R f 0 l"))


; Lemma 6.1.

(set-goal 
 (pf "all n. excl l. 
        n < l ! 
        R f 1 l"))
; R(f 1 l) is the set of left f-minima w.r.t. Q, 
;                                 i.e. w.r.t. R( f 0 l)

(assume "f")
(assume "n")

(by-assume-minimal-wrt
 (pf "excl m. n < m ! R f 0 m") "l" 
 (pt "f 1") "min_H" "min_P1" "min_P2")

(use "unboundedQ")
(exc-intro (pt "l"))
(use "min_P1")
(use "Rright" (pt "0"))
(split)
(use "min_P2")
(assume "m" "R0m" "H" "negG")
(use "min_H" (pt "m"))
(use "negG")
(use "NatLtTrans" (pt "l"))
(use "min_P1")
(use "H")
(use "R0m")
(save "Lemma6.1")



; Lemma 6.2.

; I. R is unbounded

(set-goal 
 (pf "all k. all n. excl l.
         n < l !
         R f (Succ k) l"))

(assume "f")

; By induction on k
(ind)

; Base case
(use "Lemma6.1")

; Induction Step
(assume "k" "IH" "n")

(by-assume-minimal-wrt
 (pf "excl m. 
       n<m ! 
      R f (Succ k) m")
 "m" (pt "f (Succ (Succ k))") "min_H2" "min_P2_1" "min_P2_2")

(use "IH")
(exc-intro (pt "m"))
(use "min_P2_1")
(use "Rright" (pt "k"))
(split)
(use "min_P2_2")
(assume "l")
(assume "H1" "H2" "negG")
(use "min_H2" (pt "l"))
(use "negG")
(use "NatLtTrans" (pt "m"))
(use "min_P2_1")
(use "H2")
(use "H1")
(save "Lemma6.2I")



; II All f increase on R


(set-goal
  (pf "R f (Succ k) n -> R f (Succ k) m -> n<m -> 
       all i. i <= k -> f (Succ i) m < f (Succ i) n -> bot"))

(assume "f")

(ind) ; on k

; Base case: k=0
(assume "n" "m" "H1" "H2" "H")
(assume "i" "H3")

; Make a case distinction on i
(use "NatLtSuccCases" (pt "0") (pt "i"))

; applicable due to the Hyp: i<=0
(use  "NatLeToLtSucc") 
(use "H3")

; Case: i<0
(assume "Absurd") (strip) (use "Efq") (use "Absurd")

; Case: i=0
(assume "i0")
(simp-with "i0")
(use "Rleft0" (pt "m") (pt "k"))
(use "H1") 
(use "H") 

; Ind. step: k -> Succ k
(assume "k" "IHk")
(assume "n" "m" "Rkn" "Rkm" "H")
(assume "i" "Hi")

; Make, as above, a case distinction on i
(use "NatLtSuccCases" (pt "Succ k") (pt "i"))

; based on the Hyp: i <= Succ k
(use  "NatLeToLtSucc") 
(use "Hi")

; Case i < Succ k
(assume "H1i") 
(use "IHk")
(use "Rleft" (pt "m") (pt "k"))
(use "Rkn") 
(use "Rleft" (pt "m") (pt "k"))
(use "Rkm") 
(use "H")
(use  "NatLtSuccToLe") 
(use "H1i")


; Case i = Succ k
(assume "H2i") 
(simp-with "H2i")
(use "Rleft" (pt "m") (pt "k"))
(use "Rkn") 
(use "Rleft" (pt "m") (pt "k"))
(use "Rkm") 
(use "H")

(save "Lemma6.2II")


; One can unify I and II

(set-goal 
 (pf "all k. (all n. excl l. n < l ! R f (Succ k) l) !
             (R f (Succ k) n -> R f (Succ k) m -> n<m -> 
               all i. i <= k -> f (Succ i) m < f (Succ i) n -> bot)"))
(assume "f" "n" "m")

(ind) ; on k

; Base case: k=0
(split)

; I
(use "Lemma6.1")
; II
(use "Lemma6.2II")

; Ind. step: k -> k+1
(assume "k" "IHk")

(split)

; I
(use "Lemma6.2I")
; II
(use "Lemma6.2II")

(save "Lemma6.2")


; Corrollary 6.3 (Dickson's Lemma)


; for now: l=1 
;   i.e. the functions increase in two points

(set-goal 
  (pf "all k, f. 
           excl i0,i1.(i0 < i1) !
                      (all j. j <= k -> 
                         f (Succ j) i1 < f (Succ j) i0 -> bot)
  "))

; The actual goal here is to show that:
;    from Lemma 6.2 I one can derive:
;    excl i0,i1. i0<i1 ! R f k i0 ! R f k i1

(assume "k" "f")
(assert (pf "excl i0,i1. i0<i1 ! R f (Succ k) i0 ! R f (Succ k) i1"))
(assume "negG")
(use "Lemma6.2I" (pt "f") (pt "k") (pt "0"))
(assume "i0" "Hi0" "Ri0")
(use "Lemma6.2I" (pt "f") (pt "k") (pt "i0"))
(assume "i1" "rel_i0i1" "Ri1")
(use "negG" (pt "i0") (pt"i1"))
(use "rel_i0i1")
(use "Ri0")
(use "Ri1")

; Now the goal follows straightfoward
;  from this stronger assumption
;  and from the Lemma 6.2 II

(assume "strongerLemma6.1I")
(assume "negG")
(use "strongerLemma6.1I")
(assume "i0" "i1" "rel_i0i1" "Ri0" "Ri1")
(use "negG" (pt "i0") (pt"i1"))
(use "rel_i0i1")
(use "Lemma6.2II")
(use "Ri0")
(use "Ri1")
(use "rel_i0i1")

(save "DicksonGen")








