File BiAbstr.ML


(*
      File: BiAbstr.thy
    Author: Simon Ambler (sja4@mcs.le.ac.uk)
 Copyright: Leicester University, 2001.
Time-stamp: <2002-04-08 17:03:24 sja4>

	Abstraction of two variables

*)

Addsimps (ext_simps);

val abstSet_Es =
  let
	val rbt = rule_by_tactic (ALLGOALS Full_simp_tac);
  in
	map (rbt o abstSet.mk_cases) [
		"abst i (% x. BND j)",
		"abst i (% x. f x $$ g x)",
		"abst i (% x. ABS (e x))"
	 ]
  end;

Delsimps (ext_simps);


val prems = Goalw [abstr_def]
  "[| abstr (% x. e x $$ f x); \
	\ [| abstr (% x. e x); abstr (% x. f x) |] ==> P |] ==> P";
by (cut_facts_tac prems 1);
bes abstSet_Es 1;
brs prems 1;
ba 1;
ba 1;
qed "abstr_APP_E";


Goalw [abstr_def] "abstr (% x. BND j) ==> P";
bes abstSet_Es 1;
be less_zeroE 1;
qed "abstr_BND_E";


Goal "abst i e ==> ordinary e";
be abstSet.induct 1;
by (ALLGOALS (fast_tac (claset() addIs ordinaryIs
	addss simpset())));
qed "abst_ordinary";


Goalw [abstr_def] "abstr e ==> ordinary e";
br abst_ordinary 1;
ba 1;
qed "abstr_ordinary";


Goal "! i. insts i [s] t = inst i s t";
by (induct_tac "t" 1);
by Auto_tac;
qed_spec_mp "insts_inst";


Goalw [lambda_def]
  "abst 1 f ==> (% x. ABS (f x)) = (% x. LAM y. insts 0 [y,x] (lbind 1 f))";
br ext 1;
by (simp_tac (simpset() addsimps [insts_lbind RS sym]) 1);
by (asm_simp_tac (simpset() addsimps [insts_inst, abst_inst_lbind RS cong]) 1);
qed "ABS_LAM_insts";


Goalw [rank_def] "abst i e \
	\ ==> !j. rank (% x. inst j (VAR n) (e x)) = rank e";
be abstSet.induct 1;
by Auto_tac;
qed_spec_mp "rank_inst";


Goalw [rank_def] "level i s \
	\ ==> !j. rank (% x. insts j [VAR n, x] s) = size s";
be levelSet.induct 1;
by Auto_tac;
be less_SucE 1;
be less_SucE 1;
by (ALLGOALS Asm_simp_tac);
qed_spec_mp "rank_insts1";


Goalw [rank_def] "level i s \
	\ ==> !j. rank (% x. insts j [x, VAR n] s) = size s";
be levelSet.induct 1;
by Auto_tac;
be less_SucE 1;
be less_SucE 1;
by (ALLGOALS Asm_simp_tac);
qed_spec_mp "rank_insts2";


Goal "level i s ==> ! j. i = Suc (Suc j) \
	\ --> abst j (% x. insts j [VAR n, x] s)";
be levelSet.induct 1;
by (ALLGOALS (fast_tac (claset()
	addIs abstSet.intrs
	addEs [less_SucE] addss simpset())));
val lemma = result();

Goal "level (Suc (Suc j)) s ==> abst j (% x. insts j [VAR n, x] s)";
bd lemma 1;
by Auto_tac;
qed "level_abst_insts1";


Goal "level i s ==> ! j. i = Suc (Suc j) \
	\ --> abst j (% x. insts j [x, VAR n] s)";
be levelSet.induct 1;
by (ALLGOALS (fast_tac (claset()
	addIs abstSet.intrs
	addEs [less_SucE] addss simpset())));
val lemma = result();

Goal "level (Suc (Suc j)) s ==> abst j (% x. insts j [x, VAR n] s)";
bd lemma 1;
by Auto_tac;
qed "level_abst_insts2";


Goalw [rank_def] "abst i e ==> ! j. size (lbind j e) = rank e";
be abstSet.induct 1;
by (ALLGOALS (asm_simp_tac (simpset() addsimps lbind_simps)));
qed_spec_mp "size_lbind";


Goal "biAbst j e ==> biAbst j (% x y. e y x)";
be biAbstSet.induct 1;
by (ALLGOALS (fast_tac (claset()
	addIs biAbstSet.intrs)));
qed "biAbst_swap";


Goalw [biAbstr_def] "biAbstr f ==> biAbstr (% x y. f y x)";
br biAbst_swap 1;
ba 1;
qed "biAbstr_swap";


Goalw [proper_def] "biAbst i e ==> ! s. proper s --> abst i (e s)";
be biAbstSet.induct 1;
by (ALLGOALS (fast_tac (claset()
	addIs abstSet.intrs @ [level_abst_const]
	addss simpset())));
qed_spec_mp "biAbst_proper_abst";


Goalw [biAbstr_def, abstr_def]
 "[| biAbstr e; proper s |] ==> abstr (e s)";
br biAbst_proper_abst 1;
ba 1;
ba 1;
qed "biAbstr_proper_abstr1";


Goalw [biAbstr_def, abstr_def]
 "[| biAbstr e; proper s |] ==> abstr (% x. e x s)";
br (biAbst_swap RS biAbst_proper_abst) 1;
ba 1;
ba 1;
qed "biAbstr_proper_abstr2";


Goalw [biAbstr_def, abstr_def, lambda_def]
  "biAbstr f ==> abstr (% x. LAM y. f x y)";
be biAbstSet.induct 1;
by (ALLGOALS (fast_tac (claset()
	addIs abstSet.intrs
	addEs abstSet_Es
	addss (simpset() addsimps lbind_simps))));
qed "biAbstr_abstr_LAM1";


Goal "biAbstr f ==> abstr (% y. LAM x. f x y)";
br (biAbstr_swap RS biAbstr_abstr_LAM1) 1;
ba 1;
qed "biAbstr_abstr_LAM2";


val abstrIs = [abstr_VAR, abstr_id, abstr_APP, biAbstr_abstr_LAM1];


Goal "level i s ==> ! j. i = Suc (Suc j) \
	\ --> biAbst j (% x y. insts j [x, y] s)";
be levelSet.induct 1;
by (ALLGOALS (fast_tac (claset()
	addIs biAbstSet.intrs
	addEs [less_SucE] addss simpset())));
val lemma = result();

Goal "level (Suc (Suc j)) s ==> biAbst j (% x y. insts j [x, y] s)";
bd lemma 1;
by Auto_tac;
qed "level_biAbst_insts";


val prems = Goalw [abstr_def, biAbstr_def]
	"[| abstr e; \
	\     !! a. P (% x. CON a); \
	\     !! j. P (% x. VAR j); \
	\           P (% x. x); \
	\   !! f g. [| abstr f; P f; abstr g; P g |] ==> P (% x. f x $$ g x); \
	\     !! f. [| biAbstr f; ! n. P (% x. f x (VAR n)); \
				\ ! n. P (% x. f (VAR n) x) |] \
			\ ==> P (% x. LAM y. f x y) \
	\ |] ==> P e";

by (res_inst_tac [("P","abst 0 e"), ("Q", "P e")] mp  1);
brs prems 2;
by (res_inst_tac [("P","% e. abst 0 e --> P e"), ("f","rank")]
	measure_induct 1);
by (case_tac "ordinary x" 1);
by (fast_tac (claset() addIs prems @ [abst_ordinary]
	addss simpset()) 2);

bw ordinary_def;
by Safe_tac;

(* ABS case *)

bes abstSet_Es 6;
by (asm_simp_tac (simpset() addsimps [ABS_LAM_insts]) 6);
brs prems 6;
br (abst_level_lbind RS level_biAbst_insts RS biAbst_swap) 6;
ba 6;
br allI 6;
by (eres_inst_tac [("x","% x. insts 0 [VAR n, x] (lbind 1 f)")] allE 6);
bd mp 6;
be mp 7;
br (abst_level_lbind RS rank_insts1 RS ssubst) 6;
ba 6;
br (size_lbind RS ssubst) 6;
ba 6;
brs expr_ranks 6;
br (abst_level_lbind RS level_abst_insts1) 6;
ba 6;

(* 23 *)

br allI 6;
by (eres_inst_tac [("x","% x. insts 0 [x, VAR n] (lbind 1 f)")] allE 6);
bd mp 6;
be mp 7;
br (abst_level_lbind RS rank_insts2 RS ssubst) 6;
ba 6;
br (size_lbind RS ssubst) 6;
ba 6;
brs expr_ranks 6;
br (abst_level_lbind RS level_abst_insts2) 6;
ba 6;

(* ABS case --- End *)

by (ALLGOALS (fast_tac (claset() addIs prems @ expr_ranks
	addEs abstSet_Es
	addss simpset())));

qed "abstr_VAR_induct";


val prems = Goal "[| abstr e; \
	\   !! a.    e = (% x. CON a) ==> P; \
	\            e = (% x. x) ==> P; \
	\   !! n.    e = (% x. VAR n) ==> P; \
	\ !! f g. [| e = (% x. f x $$ g x); abstr f; abstr g |] ==> P; \
	\   !! f. [| e = (% x. LAM y. f x y); biAbstr f |] ==> P |] \
		\ ==> P";
by (cut_facts_tac prems 1);
by (subgoal_tac "e = e --> P" 1);
be impE 1;
br refl 1;
ba 1;
by (eres_inst_tac [("P","% x. (e=x --> P)")] abstr_VAR_induct 1);
by (ALLGOALS (strip_tac THEN' eresolve_tac prems));
by (ALLGOALS atac);
qed "abstrE";


(*

Goal "abstr e ==> proper t --> proper (e t)";
be abstr_VAR_induct 1;
by (ALLGOALS (fast_tac (claset() addIs properIs @ [biAbstr_proper_abstr1])));
qed_spec_mp "abstr_proper_proper";

*)

Goalw [biRank_def] "biRank f < biRank (% x y. f x y $$ g x y)";
by (Simp_tac 1);
qed "biRank_APP1";

Goalw [biRank_def] "biRank g < biRank (% x y. f x y $$ g x y)";
by (Simp_tac 1);
qed "biRank_APP2";

Goalw [biRank_def] "biRank e < biRank (% x y. ABS (e x y))";
by (Simp_tac 1);
qed "biRank_ABS";


val expr_biRanks = [biRank_APP1, biRank_APP2, biRank_ABS];


val prems = Goal "[| !! a. P (% x y. CON a); \
	\     !! j. P (% x y. VAR j); \
	\           P (% x y. x); \
	\           P (% x y. y); \
	\     !! j. P (% x y. BND j); \
	\   !! f g. [| P f; P g |] ==> P (% x y. f x y $$ g x y); \
	\     !! f. P f ==> P (% x y. ABS (f x y)); \
	\     !! f. ~ biOrdinary f ==> P f |] \
			\ ==> P e";
by (res_inst_tac [("P","P"), ("f", "biRank")]
	measure_induct 1);
by (case_tac "biOrdinary x" 1);
brs prems 2;
ba 2;
bw biOrdinary_def;
by Safe_tac;
by (ALLGOALS (blast_tac (claset()
	addIs prems @ expr_biRanks
	addss simpset())));
qed "biAbstraction_induct";


val ext2_expr_inject = 
  let
	fun prv form = prove_goal thy form
		(fn prs => [fast_tac (claset()
			addss (simpset() addsimps [ext_simp])) 1]);
  in
	map prv [
		"((% x y. CON a) = (% x y. CON b)) = (a = b)",
		"((% x y. VAR j) = (% x y. VAR k)) = (j = k)",
		"((% x y. BND j) = (% x y. BND k)) = (j = k)",
		"((% x y. e x y $$ g x y) = (% x y. f x y $$ h x y)) \
			\ = (e = f & g = h)",
		"((% x y. ABS (e x y)) = (% x y. ABS (f x y))) = (e = f)"
		]
  end;


Goal "(% (x :: 'a expr) (y :: 'a expr). x) ~= (% x y. s)";
by (simp_tac (simpset() addsimps [ext_simp]) 1);
by (res_inst_tac [("x","if VAR 0 = s then VAR 1 else VAR 0")] exI 1);
by (fast_tac (claset()
	addss (simpset() addsplits [split_if_asm])) 1);
qed "proj1_neq_const";


Goal "(% (x :: 'a expr) (y :: 'a expr). y) ~= (% x y. s)";
by (simp_tac (simpset() addsimps [ext_simp]) 1);
by (res_inst_tac [("x","if VAR 0 = s then VAR 1 else VAR 0")] exI 1);
by (fast_tac (claset()
	addss (simpset() addsplits [split_if_asm])) 1);
qed "proj2_neq_const";


Goal "(% (x :: 'a expr) (y :: 'a expr). x) ~= (% x y. y)";
by (simp_tac (simpset() addsimps [ext_simp]) 1);
by (res_inst_tac [("x","VAR 0")] exI 1);
by (res_inst_tac [("x","VAR 1")] exI 1);
by (Simp_tac 1);
qed "proj1_neq_proj2";


Goal "(% (x :: 'a expr) (y :: 'a expr). x) ~= (% x y. f x y $$ g x y)";
by (simp_tac (simpset() addsimps [ext_simp]) 1);
by (res_inst_tac [("x","VAR 0")] exI 1);
by (res_inst_tac [("x","VAR 0")] exI 1);
by (Simp_tac 1);
qed "proj1_neq_APP";


Goal "(% (x :: 'a expr) (y :: 'a expr). y) ~= (% x y. f x y $$ g x y)";
by (simp_tac (simpset() addsimps [ext_simp]) 1);
by (res_inst_tac [("x","VAR 0")] exI 1);
by (res_inst_tac [("x","VAR 0")] exI 1);
by (Simp_tac 1);
qed "proj2_neq_APP";


Goal "(% (x :: 'a expr) (y :: 'a expr). x) ~= (% x y. ABS (e x y))";
by (simp_tac (simpset() addsimps [ext_simp]) 1);
by (res_inst_tac [("x","VAR 0")] exI 1);
by (res_inst_tac [("x","VAR 0")] exI 1);
by (Simp_tac 1);
qed "proj1_neq_ABS";


Goal "(% (x :: 'a expr) (y :: 'a expr). y) ~= (% x y. ABS (e x y))";
by (simp_tac (simpset() addsimps [ext_simp]) 1);
by (res_inst_tac [("x","VAR 0")] exI 1);
by (res_inst_tac [("x","VAR 0")] exI 1);
by (Simp_tac 1);
qed "proj2_neq_ABS";



val ext2_expr_distinct =
  let
	fun prv form = prove_goal thy form
		(fn prs => [simp_tac (simpset() addsimps [ext_simp]) 1]);

	val expr_distinct = [proj1_neq_const, proj1_neq_APP, proj1_neq_ABS,
				proj1_neq_proj2,
				proj2_neq_const, proj2_neq_APP, proj2_neq_ABS]
		@
		map prv [
		"(% x y. CON a) ~= (% x y. VAR n)",
		"(% x y. CON a) ~= (% x y. BND j)",
		"(% x y. CON a) ~= (% x y. f x y $$ g x y)",
		"(% x y. CON a) ~= (% x y. ABS (e x y))",
		"(% x y. VAR n) ~= (% x y. BND j)",
		"(% x y. VAR n) ~= (% x y. f x y $$ g x y)",
		"(% x y. VAR n) ~= (% x y. ABS (e x y))",
		"(% x y. BND j) ~= (% x y. f x y $$ g x y)",
		"(% x y. BND j) ~= (% x y. ABS (e x y))",
		"(% x y. f x y $$ g x y) ~= (% x y. ABS (e x y))"
		]
 
  in
	expr_distinct @ (expr_distinct RL [not_sym])

  end;


val ext2_simps = ext2_expr_inject @ ext2_expr_distinct;


(* BiAbstraction solver --- for goals of the form "biAbstr (% x y. e x y)" *)


local

  (* Will only resolve against goals of the right form *)
  val biAbstr_filter_thm =
	prove_goal thy "biAbstr (% x y. e x y) ==> biAbstr (% x y. e x y)"
		(fn prems => [resolve_tac prems 1]);
in

  fun biAbstr_tac defs prems =
	rtac biAbstr_filter_thm
	THEN'
	 (resolve_tac prems
	  ORELSE'
	  fast_tac (claset()
		addIs biAbstSet.intrs
		addss (simpset()
			addsimps defs @ [biAbstr_def, lambda_def]
					@ lbind_simps)))
end;


fun biAbstr_solver defs = mk_solver "biAbstr"
		(fn prems => biAbstr_tac defs prems);


Goalw [biAbstr_def]
  "biAbstr f ==> ! g n. biAbstr g --> newFor n (f dflt dflt) \
	\ --> newFor n (g dflt dflt) \
	\ --> f (VAR n) = g (VAR n) --> f = g";
be biAbstSet.induct 1;
by (ALLGOALS strip_tac);
by (ALLGOALS (eres_inst_tac [("aa","(i,g)")] biAbstSet.elim));
by (ALLGOALS (fast_tac (claset()
	addss (simpset() addsimps ext_simps @ ext2_simps))));
qed_spec_mp "biAbstr_extensionality";


Goalw [biSubst_def]
  "[| f (VAR n) = e; biAbstr f; newFor n (f dflt dflt) |] \
	\ ==> biSubst e n = f";
br some_equality 1;
by (Fast_tac 1);
by (REPEAT (etac conjE 1));
br biAbstr_extensionality 1;
by Auto_tac;
qed_spec_mp "biAbstr_biSubst";


Goalw [abstr_def, biAbstr_def]
  "abstr e ==> ? f. biAbstr f & newFor n (f dflt dflt) & f (VAR n) = e";
be abstSet.induct 1;
by (case_tac "n=na" 3);
by (res_inst_tac [("x","% x y. CON a")] exI 1);
by (res_inst_tac [("x","% x y. y")] exI 2);
by (res_inst_tac [("x","% x y. x")] exI 3);
by (res_inst_tac [("x","% x y. VAR na")] exI 4);
by (REPEAT (eresolve_tac [exE, conjE] 6));
by (res_inst_tac [("x","% x y. fa x y $$ fb x y")] exI 6);
by (REPEAT (eresolve_tac [exE, conjE] 7));
by (res_inst_tac [("x","% x y. ABS (fa x y)")] exI 7);

by (ALLGOALS (fast_tac (claset()
	addIs biAbstSet.intrs
	addss simpset())));
qed "abstr_biSubst_lemma";


Goalw [biSubst_def] "abstr e ==> biAbstr (biSubst e n)";
br (abstr_biSubst_lemma RS someI_ex RS conjunct1) 1;
ba 1;
qed "abstr_biAbstr_biSubst";


Goalw [biSubst_def] "abstr e ==> biSubst e n (VAR n) = e";
br (abstr_biSubst_lemma RS someI_ex RS conjunct2 RS conjunct2) 1;
ba 1;
qed "abstr_biSubst_id";


Goalw [biSubst_def] "abstr e ==> newFor n (biSubst e n dflt dflt)";
br (abstr_biSubst_lemma RS someI_ex RS conjunct2 RS conjunct1) 1;
ba 1;
qed "abstr_newFor_biSubst";


(*

Goal "subst (CON a) n = (% x. CON a)";
br abstr_subst 1;
br refl 1;
by (abstr_tac [] [] 1);
by (Simp_tac 1);
qed "subst_CON";


Goal "subst (VAR m) n = (if n=m then (% x. x) else (% x. VAR m))";
br abstr_subst 1;
by (Simp_tac 1);
by (abstr_tac [] [] 1);
by (Simp_tac 1);
qed "subst_VAR";


Goal "[| proper s; proper t |] \
	\ ==> subst (s $$ t) n = (% x. subst s n x $$ subst t n x)";
br abstr_subst 1;
by (asm_simp_tac (simpset() addsimps [proper_subst_id]) 1);
br abstr_APP 1;
be proper_abstr_subst 1;
be proper_abstr_subst 1;
by (asm_simp_tac (simpset() addsimps [proper_newFor_subst]) 1);
qed "subst_APP";

*)

Goal "abstr e ==> subst (LAM y. e y) n = (% x. LAM y. biSubst e n x y)";
br abstr_subst 1;
by (asm_simp_tac (simpset()
	addsimps [abstr_LAM_simp, abstr_biSubst_id,
		abstr_biAbstr_biSubst RS biAbstr_abstr_LAM1]) 1);

br (abstr_biAbstr_biSubst RS biAbstr_abstr_LAM1) 1;
ba 1;

by (asm_simp_tac (simpset()
	addsimps [newFor_LAM, abstr_newFor_biSubst,
		abstr_biAbstr_biSubst RS biAbstr_proper_abstr1,
		proper_dflt]) 1);

qed "subst_LAM";


Goal "biAbst i f ==> ! e. abst i e --> abst i (% x. f x (e x))";
be biAbstSet.induct 1;
by (strip_tac 7);
bd ((le_refl RS le_SucI) RSN (2, abst_le_abst)) 7;
by (ALLGOALS (fast_tac (claset() addIs abstSet.intrs)));
qed_spec_mp "biAbst_abst_compose";


Goalw [biAbstr_def, abstr_def]
  "[| biAbstr f; abstr e |] ==> abstr (% x. f x (e x))";
be biAbst_abst_compose 1;
ba 1;
qed "biAbstr_abstr_compose";


Goalw [biAbstr_def] "biAbstr f ==> ! s t. proper s --> proper t \
	\ --> newFor n s --> newFor n t --> newFor n (f dflt dflt) \
	\ --> newFor n (f s t)";
be biAbstSet.induct 1;
by (ALLGOALS (fast_tac (claset() addss simpset())));
qed_spec_mp "biAbstr_newFor_apply";


Goal "[| abstr e; proper u; proper t |] \
	\ ==> biSubst e n u (subst t n u) = subst (e t) n u";

by (res_inst_tac [("f", "% x. biSubst e n x (subst t n x)")]
	(refl RSN (2, cong)) 1);
br (abstr_subst RS sym) 1;
by (asm_simp_tac (simpset()
	addsimps [subst_VAR_id, abstr_biSubst_id]) 1);
by (res_inst_tac [("f","biSubst e n"), ("e","subst t n")]
	biAbstr_abstr_compose 1);
br abstr_biAbstr_biSubst 1;
ba 1;
br proper_abstr_subst 1;
ba 1;
by (res_inst_tac [("f","biSubst e n")] biAbstr_newFor_apply 1);
br abstr_biAbstr_biSubst 1;
ba 1;
br proper_dflt 1;
br (proper_abstr_subst RS abstr_proper_proper) 1;
ba 1;
br proper_dflt 1;
by (Simp_tac 1);
by (simp_tac (simpset() addsimps [newFor_subst]) 1);
br abstr_newFor_biSubst 1;
ba 1;
qed "biSubst_subst_simp";