(* ========================================================================= *)
(* Set-theoretic hierarchy for modelling HOL inside itself.                  *)
(* ========================================================================= *)
let INJ_LEMMA = prove
 (`(!x y. (f x = f y) ==> (x = y)) <=> (!x y. (f x = f y) <=> (x = y))`,
  MESON_TAC[]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Useful to have a niceish "function update" notation.                      *)
(* ------------------------------------------------------------------------- *)
parse_as_infix("|->",(12,"right"));;
let VALMOD = prove
 (`!v x y a. ((x |-> y) v) a = if a = x then y else v(a)`,
  REWRITE_TAC[valmod]);;
 
 
let VALMOD_SWAP = prove
 (`!v x y a b.
     ~(x = y) ==> ((x |-> a) ((y |-> b) v) = (y |-> b) ((x |-> a) v))`,
  REWRITE_TAC[valmod; 
FUN_EQ_THM] THEN MESON_TAC[]);;
 
 
(* ------------------------------------------------------------------------- *)
(* A dummy finite type inadequately modelling ":ind".                        *)
(* ------------------------------------------------------------------------- *)
let ind_model_tybij =
  new_type_definition "ind_model" ("mk_ind","dest_ind") ind_model_tybij_th;;
(* ------------------------------------------------------------------------- *)
(* Introduce a type whose universe is "inaccessible" starting from           *)
(* "ind_model". Since "ind_model" is finite, we can just use any             *)
(* infinite set. In order to make "ind_model" infinite, we would need        *)
(* a new axiom. In order to keep things generic we try to deduce             *)
(* everything from this one uniform "axiom". Note that even in the           *)
(* infinite case, this can still be a small set in ZF terms, not a real      *)
(* inaccessible cardinal.                                                    *)
(* ------------------------------------------------------------------------- *)
(****** Here's what we'd do in the infinite case
 new_type("I",0);;
 let I_AXIOM = new_axiom
  `UNIV:ind_model->bool <_c UNIV:I->bool /\
   (!s:A->bool. s <_c UNIV:I->bool ==> {t | t SUBSET s} <_c UNIV:I->bool)`;;
 *******)
let inacc_tybij =
  new_type_definition "I" ("mk_I","dest_I") inacc_tybij_th;;
let I_AXIOM = prove
 (`UNIV:ind_model->bool <_c UNIV:I->bool /\
   (!s:A->bool. s <_c UNIV:I->bool ==> {t | t 
SUBSET s} <_c UNIV:I->bool)`,
 
 
(* ------------------------------------------------------------------------- *)
(* I is infinite and therefore admits an injective pairing.                  *)
(* ------------------------------------------------------------------------- *)
let I_PAIR = REWRITE_RULE[INJ_LEMMA]
 (new_specification ["I_PAIR"] I_PAIR_EXISTS);;
(* ------------------------------------------------------------------------- *)
(* It also admits injections from "bool" and "ind_model".                    *)
(* ------------------------------------------------------------------------- *)
let I_BOOL = REWRITE_RULE[INJ_LEMMA]
 (new_specification ["I_BOOL"] I_BOOL_EXISTS);;
let I_IND = REWRITE_RULE[INJ_LEMMA]
 (new_specification ["I_IND"] I_IND_EXISTS);;
(* ------------------------------------------------------------------------- *)
(* And the injection from powerset of any accessible set.                    *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Define a type for "levels" of our set theory.                             *)
(* ------------------------------------------------------------------------- *)
;
let setlevel_DISTINCT = distinctness "setlevel";;
let setlevel_INJ = injectivity "setlevel";;
(* ------------------------------------------------------------------------- *)
(* Now define a subset of I corresponding to each.                           *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Show they all satisfy the cardinal limits.                                *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Hence the injectivity of the mapping from powerset.                       *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Now our universe of sets and (ur)elements.                                *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Define an actual type V.                                                  *)
(*                                                                           *)
(* This satisfies a suitable number of the ZF axioms. It isn't extensional   *)
(* but we could then construct a quotient structure if desired. Anyway it's  *)
(* only empty sets that aren't. A more significant difference is that we     *)
(* have urelements and the hierarchy levels are all distinct rather than     *)
(* being cumulative.                                                         *)
(* ------------------------------------------------------------------------- *)
let v_tybij =
  new_type_definition "V" ("mk_V","dest_V") v_tybij_th;;
(* ------------------------------------------------------------------------- *)
(* Drop a level; test if something is a set.                                 *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Define some useful inversions.                                            *)
(* ------------------------------------------------------------------------- *)
let SET = prove
 (`!x. mk_V(level x,element x) = x`,
 REWRITE_TAC[level; element; 
PAIR; v_tybij]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Now all the critical relations.                                           *)
(* ------------------------------------------------------------------------- *)
parse_as_infix("<:",(11,"right"));;
parse_as_infix("<=:",(12,"right"));;
let subset_def = new_definition
 `s <=: t <=> (level s = level t) /\ !x. x <: s ==> x <: t`;;
 
(* ------------------------------------------------------------------------- *)
(* If something has members, it's a set.                                     *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Each level is nonempty.                                                   *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Empty sets (or non-sets, of course) exist at all set levels.              *)
(* ------------------------------------------------------------------------- *)
let MK_V_SET = prove
 (`s 
SUBSET setlevel l
   ==> (set(mk_V(Powerset l,
I_SET (setlevel l) s)) = s) /\
       (level(mk_V(Powerset l,
I_SET (setlevel l) s)) = Powerset l) /\
       (element(mk_V(Powerset l,
I_SET (setlevel l) s)) = 
I_SET (setlevel l) s)`,
  REPEAT GEN_TAC THEN DISCH_TAC THEN
  SUBGOAL_THEN `
I_SET (setlevel l) s 
IN setlevel(Powerset l)` ASSUME_TAC THENL
   [REWRITE_TAC[setlevel; 
IN_IMAGE; 
IN_ELIM_THM] THEN ASM_MESON_TAC[];
    ALL_TAC] THEN
  ASM_SIMP_TAC[
MK_V_CLAUSES; set] THEN
  SUBGOAL_THEN `
I_SET (setlevel l) s 
IN setlevel(Powerset l)` ASSUME_TAC THENL
   [REWRITE_TAC[setlevel; 
IN_IMAGE; 
IN_ELIM_THM] THEN ASM_MESON_TAC[];
    ALL_TAC] THEN
  ASM_SIMP_TAC[
MK_V_CLAUSES; droplevel] THEN
  MATCH_MP_TAC 
SELECT_UNIQUE THEN REWRITE_TAC[] THEN
  ASM_MESON_TAC[
I_SET_SETLEVEL]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Comprehension principle, with no change of levels.                        *)
(* ------------------------------------------------------------------------- *)
let COMPREHENSION_EXISTS = prove
 (`!s p. ?t. (level t = level s) /\ !x. x <: t <=> x <: s /\ p x`,
  REPEAT GEN_TAC THEN ASM_CASES_TAC `isaset s` THENL
   [ALL_TAC; ASM_MESON_TAC[
MEMBERS_ISASET]] THEN
  POP_ASSUM(X_CHOOSE_TAC `l:setlevel` o REWRITE_RULE[isaset]) THEN
  MP_TAC(SPEC `s:V` 
ELEMENT_IN_LEVEL) THEN
  ASM_REWRITE_TAC[setlevel; 
IN_IMAGE; 
IN_ELIM_THM] THEN
  DISCH_THEN(X_CHOOSE_THEN `u:I->bool` STRIP_ASSUME_TAC) THEN
  EXISTS_TAC `mk_V(Powerset l,
                   
I_SET(setlevel l)
                   {i | i 
IN u /\ p(mk_V(l,i))})` THEN
  SUBGOAL_THEN `{i | i 
IN u /\ p (mk_V (l,i))} 
SUBSET (setlevel l)`
  ASSUME_TAC THENL
   [REWRITE_TAC[
SUBSET; 
IN_ELIM_THM] THEN ASM_MESON_TAC[
SUBSET];
    ALL_TAC] THEN
  ASM_SIMP_TAC[
MK_V_SET; inset] THEN X_GEN_TAC `x:V` THEN
  REWRITE_TAC[setlevel_INJ] THEN
  REWRITE_TAC[
IN_ELIM_THM] THEN ASM_MESON_TAC[
SET; 
MK_V_SET]);;
 
 
parse_as_infix("suchthat",(21,"left"));;
(* ------------------------------------------------------------------------- *)
(* Each setlevel exists as a set.                                            *)
(* ------------------------------------------------------------------------- *)
let SETLEVEL_EXISTS = prove
 (`!l. ?s. (level s = Powerset l) /\
           !x. x <: s <=> (level x = l) /\ element(x) 
IN setlevel l`,
  GEN_TAC THEN
  EXISTS_TAC `mk_V(Powerset l,
I_SET (setlevel l) (setlevel l))` THEN
  SIMP_TAC[
MK_V_SET; 
SUBSET_REFL; inset; setlevel_INJ] THEN MESON_TAC[]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Conversely, set(s) belongs in the appropriate level.                      *)
(* ------------------------------------------------------------------------- *)
let SET_DECOMP = prove
 (`!s. isaset s
       ==> (set s) 
SUBSET (setlevel(droplevel(level s))) /\
           (
I_SET (setlevel(droplevel(level s))) (set s) = element s)`,
  REPEAT GEN_TAC THEN REWRITE_TAC[isaset] THEN
  DISCH_THEN(X_CHOOSE_TAC `l:setlevel`) THEN
  REWRITE_TAC[set] THEN CONV_TAC SELECT_CONV THEN
  ASM_REWRITE_TAC[setlevel; droplevel] THEN
  MP_TAC(SPEC `s:V` 
ELEMENT_IN_LEVEL) THEN
  ASM_REWRITE_TAC[setlevel; 
IN_IMAGE; 
IN_ELIM_THM] THEN
  MESON_TAC[]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Power set exists.                                                         *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Pairing operation.                                                        *)
(* ------------------------------------------------------------------------- *)
let DEST_MK_PAIR = prove
 (`dest_V(mk_V(Cartprod (level x) (level y),I_PAIR(element x,element y))) =
        Cartprod (level x) (level y),I_PAIR(element x,element y)`,
 
 
let PAIR_INJ = prove
 (`!x1 y1 x2 y2. (pair x1 y1 = pair x2 y2) <=> (x1 = x2) /\ (y1 = y2)`,
  REPEAT GEN_TAC THEN EQ_TAC THENL [ALL_TAC; SIMP_TAC[]] THEN
  REWRITE_TAC[pair] THEN
  DISCH_THEN(MP_TAC o AP_TERM `dest_V`) THEN REWRITE_TAC[
DEST_MK_PAIR] THEN
  REWRITE_TAC[setlevel_INJ; 
PAIR_EQ; I_PAIR] THEN
  REWRITE_TAC[level; element] THEN MESON_TAC[
PAIR; CONJUNCT1 v_tybij]);;
 
 
let LEVEL_PAIR = prove
 (`!x y. level(pair x y) = Cartprod (level x) (level y)`,
  REWRITE_TAC[level;
              REWRITE_RULE[
DEST_MK_PAIR] (AP_TERM `dest_V` (SPEC_ALL pair))]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Decomposition functions.                                                  *)
(* ------------------------------------------------------------------------- *)
let fst_def = new_definition
  `fst p = @x. ?y. p = pair x y`;;
 
let snd_def = new_definition
  `snd p = @y. ?x. p = pair x y`;;
 
(* ------------------------------------------------------------------------- *)
(* And the Cartesian product space.                                          *)
(* ------------------------------------------------------------------------- *)
let CARTESIAN_EXISTS = prove
 (`!s t. ?u. (level u =
                  Powerset(Cartprod (droplevel(level s))
                                    (droplevel(level t)))) /\
                 !z. z <: u <=> ?x y. (z = pair x y) /\ x <: s /\ y <: t`,
  REPEAT GEN_TAC THEN
  ASM_CASES_TAC `isaset s` THENL
   [ALL_TAC; ASM_MESON_TAC[
EMPTY_EXISTS; 
MEMBERS_ISASET]] THEN
  SUBGOAL_THEN `?l. (level s = Powerset l)` CHOOSE_TAC THENL
   [ASM_MESON_TAC[isaset]; ALL_TAC] THEN
  ASM_CASES_TAC `isaset t` THENL
   [ALL_TAC; ASM_MESON_TAC[
EMPTY_EXISTS; 
MEMBERS_ISASET]] THEN
  SUBGOAL_THEN `?m. (level t = Powerset m)` CHOOSE_TAC THENL
   [ASM_MESON_TAC[isaset]; ALL_TAC] THEN
  MP_TAC(SPEC `Cartprod l m` 
SETLEVEL_EXISTS) THEN
  ASM_REWRITE_TAC[droplevel] THEN
  DISCH_THEN(X_CHOOSE_THEN `u:V` STRIP_ASSUME_TAC) THEN
  MP_TAC(SPECL [`u:V`; `\z. ?x y. (z = pair x y) /\ x <: s /\ y <: t`]
               
COMPREHENSION_EXISTS) THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `w:V` THEN
  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
  X_GEN_TAC `z:V` THEN
  MATCH_MP_TAC(TAUT `(a ==> b) /\ (c ==> a) ==> ((a /\ b) /\ c <=> c)`) THEN
  CONJ_TAC THENL [MESON_TAC[
ELEMENT_IN_LEVEL]; ALL_TAC] THEN
  STRIP_TAC THEN ASM_REWRITE_TAC[
LEVEL_PAIR] THEN BINOP_TAC THEN
  ASM_MESON_TAC[inset; setlevel_INJ]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Extensionality for sets at the same level.                                *)
(* ------------------------------------------------------------------------- *)
let IN_SET_ELEMENT = prove
 (`!s. isaset s /\ e 
IN set(s)
       ==> ?x. (e = element x) /\ (level s = Powerset(level x)) /\ x <: s`,
  REPEAT STRIP_TAC THEN
  FIRST_ASSUM(X_CHOOSE_TAC `l:setlevel` o REWRITE_RULE[isaset]) THEN
  EXISTS_TAC `mk_V(l,e)` THEN REWRITE_TAC[inset] THEN
  SUBGOAL_THEN `e 
IN setlevel l` (fun t -> ASM_SIMP_TAC[t; 
MK_V_CLAUSES]) THEN
  ASM_MESON_TAC[
SET_SUBSET_SETLEVEL; 
SUBSET; droplevel]);;
 
 
let SUBSET_ALT = prove
 (`isaset s /\ isaset t
   ==> (s <=: t <=> (level s = level t) /\ set(s) 
SUBSET set(t))`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
subset_def; inset] THEN
  ASM_CASES_TAC `level s = level t` THEN ASM_REWRITE_TAC[
SUBSET] THEN
  STRIP_TAC THEN EQ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
  ASM_MESON_TAC[
IN_SET_ELEMENT]);;
 
 
let SUBSET_ANTISYM_LEVEL = prove
 (`!s t. isaset s /\ isaset t /\ s <=: t /\ t <=: s ==> (s = t)`,
  REPEAT GEN_TAC THEN
  REPLICATE_TAC 2 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
  ASM_SIMP_TAC[
SUBSET_ALT]  THEN
  EVERY_ASSUM(MP_TAC o GSYM o MATCH_MP 
SET_DECOMP) THEN
  REPEAT STRIP_TAC THEN
  MP_TAC(SPEC `s:V` 
SET) THEN MP_TAC(SPEC `t:V` 
SET) THEN
  REPEAT(DISCH_THEN(SUBST1_TAC o SYM)) THEN
  AP_TERM_TAC THEN BINOP_TAC THEN ASM_MESON_TAC[
SUBSET_ANTISYM]);;
 
 
(* ------------------------------------------------------------------------- *)
(* And hence for any nonempty sets.                                          *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Union set exists. I don't need this but if might be a sanity check.       *)
(* ------------------------------------------------------------------------- *)
let UNION_EXISTS = prove
 (`!s. ?t. (level t = droplevel(level s)) /\
           !x. x <: t <=> ?u. x <: u /\ u <: s`,
  GEN_TAC THEN ASM_CASES_TAC `isaset s` THENL
   [ALL_TAC;
    MP_TAC(SPEC `droplevel(level s)` 
EMPTY_EXISTS) THEN
    MATCH_MP_TAC 
MONO_EXISTS THEN ASM_MESON_TAC[
MEMBERS_ISASET]] THEN
  FIRST_ASSUM(X_CHOOSE_TAC `l:setlevel` o REWRITE_RULE[isaset]) THEN
  ASM_REWRITE_TAC[droplevel] THEN ASM_CASES_TAC `?m. l = Powerset m` THENL
   [ALL_TAC;
    MP_TAC(SPEC `l:setlevel` 
EMPTY_EXISTS) THEN MATCH_MP_TAC 
MONO_EXISTS THEN
    REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN REWRITE_TAC[inset] THEN
    ASM_MESON_TAC[setlevel_INJ]] THEN
  FIRST_X_ASSUM(X_CHOOSE_THEN `m:setlevel` SUBST_ALL_TAC) THEN
  MP_TAC(SPEC `m:setlevel` 
SETLEVEL_EXISTS) THEN
  ASM_REWRITE_TAC[droplevel] THEN
  DISCH_THEN(X_CHOOSE_THEN `t:V` STRIP_ASSUME_TAC) THEN
  MP_TAC(SPECL [`t:V`; `\x. ?u. x <: u /\ u <: s`]
      
COMPREHENSION_EXISTS) THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN
  GEN_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
  ASM_MESON_TAC[inset; 
ELEMENT_IN_LEVEL; setlevel_INJ]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Boolean stuff.                                                            *)
(* ------------------------------------------------------------------------- *)
let true_def = new_definition
 `true = mk_V(Ur_bool,I_BOOL T)`;;
 
let false_def = new_definition
 `false = mk_V(Ur_bool,I_BOOL F)`;;
 
let BOOLEAN_EQ = prove
 (`!x y. x <: boolset /\ y <: boolset /\
         ((x = true) <=> (y = true))
         ==> (x = y)`,
 
 
(* ------------------------------------------------------------------------- *)
(* Ind stuff.                                                                *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Axiom of choice (this is trivially so in HOL anyway, but...)              *)
(* ------------------------------------------------------------------------- *)
let ch =
  let th = prove
   (`?ch. !s. (?x. x <: s) ==> ch(s) <: s`,
    REWRITE_TAC[GSYM 
SKOLEM_THM] THEN MESON_TAC[]) in
  new_specification ["ch"] th;;
 
 
(* ------------------------------------------------------------------------- *)
(* Sanity check lemmas.                                                      *)
(* ------------------------------------------------------------------------- *)
let IN_PRODUCT = prove
 (`!z s t. z <: product s t <=> ?x y. (z = pair x y) /\ x <: s /\ y <: t`,
 
 
(* ------------------------------------------------------------------------- *)
(* Definition of function space.                                             *)
(* ------------------------------------------------------------------------- *)
let apply_def = new_definition
  `apply f x = @y. pair x y <: f`;;
 
let ABSTRACT_EQ = prove
 (`!s t1 t2 f g.
        (?x. x <: s) /\
        (!x. x <: s ==> f(x) <: t1 /\ g(x) <: t2 /\ (f x = g x))
        ==> (abstract s t1 f = abstract s t2 g)`,
 
 
(* ------------------------------------------------------------------------- *)
(* Special case of treating a Boolean function as a set.                     *)
(* ------------------------------------------------------------------------- *)