(* ========================================================================= *)
(*  Maximum of two nums and of a list of nums.                               *)
(*                                                                           *)
(*  Author: Marco Maggesi                                                    *)
(*          University of Florence, Italy                                    *)
(*          http://www.math.unifi.it/~maggesi/                               *)
(*                                                                           *)
(*          (c) Copyright, Marco Maggesi, 2005-2007                          *)
(* ========================================================================= *)

needs "Permutation/morelist.ml";;

(* ------------------------------------------------------------------------- *)
(*  Maximum of two nums.                                                     *)
(* ------------------------------------------------------------------------- *)

let MAX_LT = 
prove (`!m n p. MAX m n < p <=> m < p /\ n < p`,
REWRITE_TAC [MAX] THEN ARITH_TAC);;
let MAX_LE = 
prove (`!m n p. MAX m n <= p <=> m <= p /\ n <= p`,
REWRITE_TAC [MAX] THEN ARITH_TAC);;
let LT_MAX = 
prove (`!m n p. p < MAX m n <=> p < m \/ p < n`,
REWRITE_TAC [MAX] THEN ARITH_TAC);;
let LE_MAX = 
prove (`!m n p. p <= MAX m n <=> p <= m \/ p <= n`,
REWRITE_TAC [MAX] THEN ARITH_TAC);;
let MAX_SYM = 
prove (`!m n. MAX n m = MAX m n`,
MATCH_MP_TAC WLOG_LE THEN CONJ_TAC THEN REPEAT GEN_TAC THENL [EQ_TAC THEN SIMP_TAC []; SIMP_TAC [MAX] THEN ARITH_TAC]);;
let MAX_ASSOC = 
prove (`!m n p. MAX (MAX m n) p = MAX m (MAX n p)`,
REPEAT GEN_TAC THEN REWRITE_TAC [MAX] THEN ASM_CASES_TAC `m <= n` THEN ASM_REWRITE_TAC [] THEN ASM_CASES_TAC `n <= p` THEN ASM_REWRITE_TAC [] THENL [SUBGOAL_THEN `m <= p` (fun th -> REWRITE_TAC [th]) THEN MATCH_MP_TAC LE_TRANS THEN ASM_MESON_TAC []; SUBGOAL_THEN `~(m <= p)` (fun th -> REWRITE_TAC [th]) THEN FIRST_X_ASSUM MP_TAC THEN FIRST_X_ASSUM MP_TAC THEN ARITH_TAC]);;
let MAX_ACI = 
prove (`(!m n. MAX n m = MAX m n) /\ (!m n p. MAX (MAX m n) p = MAX m (MAX n p)) /\ (!m n p. MAX m (MAX n p) = MAX n (MAX m p)) /\ (!m. MAX m m = m) /\ (!m n. MAX m (MAX m n) = MAX m n)`,
SUBGOAL_THEN `!n. MAX n n = n` ASSUME_TAC THENL [REWRITE_TAC [MAX] THEN ARITH_TAC; ASM_MESON_TAC [MAX_SYM; MAX_ASSOC]]);;
let MAX_0 = 
prove (`(!n. MAX n 0 = n) /\ (!n. MAX 0 n = n)`,
REWRITE_TAC [MAX_SYM] THEN REWRITE_TAC [MAX] THEN ARITH_TAC);;
(* ------------------------------------------------------------------------- *) (* Maximum of a list of nums. *) (* ------------------------------------------------------------------------- *)
let MAXL = define
  `MAXL [] = 0 /\
   (!h t. MAXL (CONS h t) = MAX h (MAXL t))`;;
let MAXL_LE = 
prove (`!l n. MAXL l <= n <=> ALL (\m. m <= n) l`,
LIST_INDUCT_TAC THEN REWRITE_TAC [ALL; MAXL; LE_0] THEN ASM_SIMP_TAC [MAX_LE]);;
let LT_MAXL = 
prove (`!l n. n < MAXL l <=> EX (\m. n < m) l`,
LIST_INDUCT_TAC THEN ASM_SIMP_TAC [EX; MAXL; NOT_LT; LE_0; LT_MAX]);;
let LE_MAXL = 
prove (`!n l. MEM n l ==> n <= MAXL l`,
GEN_TAC THEN LIST_INDUCT_TAC THEN REWRITE_TAC [MEM; MAXL] THEN STRIP_TAC THEN ASM_SIMP_TAC [LE_REFL; LE_MAX]);;
let MEM_MAXL = 
prove (`!l. ~NULL l ==> MEM (MAXL l) l`,
REWRITE_TAC [NULL_EQ_NIL] THEN LIST_INDUCT_TAC THEN REWRITE_TAC [MEM; MAXL; NOT_CONS_NIL] THEN ASM_CASES_TAC `t:num list=[]` THEN ASM_REWRITE_TAC[MAXL; MAX_0] THEN ASM_MESON_TAC [MAX]);;