summaryrefslogtreecommitdiff
path: root/toplevel/auto_ind_decl.ml
diff options
context:
space:
mode:
Diffstat (limited to 'toplevel/auto_ind_decl.ml')
-rw-r--r--toplevel/auto_ind_decl.ml812
1 files changed, 812 insertions, 0 deletions
diff --git a/toplevel/auto_ind_decl.ml b/toplevel/auto_ind_decl.ml
new file mode 100644
index 00000000..094a77ff
--- /dev/null
+++ b/toplevel/auto_ind_decl.ml
@@ -0,0 +1,812 @@
+(************************************************************************)
+(* v * The Coq Proof Assistant / The Coq Development Team *)
+(* <O___,, * CNRS-Ecole Polytechnique-INRIA Futurs-Universite Paris Sud *)
+(* \VV/ **************************************************************)
+(* // * This file is distributed under the terms of the *)
+(* * GNU Lesser General Public License Version 2.1 *)
+(************************************************************************)
+
+(*i $Id: auto_ind_decl.ml 11166 2008-06-22 13:23:35Z herbelin $ i*)
+
+open Tacmach
+open Util
+open Flags
+open Decl_kinds
+open Pp
+open Entries
+open Termops
+open Declarations
+open Declare
+open Term
+open Names
+open Libnames
+open Goptions
+open Mod_subst
+open Indrec
+open Inductiveops
+open Tactics
+open Tacticals
+open Ind_tables
+
+(* boolean equality *)
+
+let quick_chop n l =
+ let rec kick_last = function
+ | t::[] -> []
+ | t::q -> t::(kick_last q)
+ | [] -> failwith "kick_last"
+and aux = function
+ | (0,l') -> l'
+ | (n,h::t) -> aux (n-1,t)
+ | _ -> failwith "quick_chop"
+ in
+ if n > (List.length l) then failwith "quick_chop args"
+ else kick_last (aux (n,l) )
+
+let rec deconstruct_type t =
+ let l,r = decompose_prod t in
+ (List.map (fun (_,b) -> b) (List.rev l))@[r]
+
+let subst_in_constr (_,subst,(ind,const)) =
+ let ind' = (subst_kn subst (fst ind)),(snd ind)
+ and const' = subst_mps subst const in
+ ind',const'
+
+exception EqNotFound of string
+exception EqUnknown of string
+
+(* Some pre declaration of constant we are going to use *)
+let bb = constr_of_global Coqlib.glob_bool
+
+let andb_prop = fun _ -> (Coqlib.build_bool_type()).Coqlib.andb_prop
+
+let andb_true_intro = fun _ ->
+ (Coqlib.build_bool_type()).Coqlib.andb_true_intro
+
+let tt = constr_of_global Coqlib.glob_true
+
+let ff = constr_of_global Coqlib.glob_false
+
+let eq = constr_of_global Coqlib.glob_eq
+
+let sumbool = Coqlib.build_coq_sumbool
+
+let andb = fun _ -> (Coqlib.build_bool_type()).Coqlib.andb
+
+(* reconstruct the inductive with the correct deBruijn indexes *)
+let mkFullInd ind n =
+ let mib = Global.lookup_mind (fst ind) in
+ let nparams = mib.mind_nparams in
+ let nparrec = mib.mind_nparams_rec in
+ (* params context divided *)
+ let lnonparrec,lnamesparrec =
+ context_chop (nparams-nparrec) mib.mind_params_ctxt in
+ if nparrec > 0
+ then mkApp (mkInd ind,
+ Array.of_list(extended_rel_list (nparrec+n) lnamesparrec))
+ else mkInd ind
+
+let make_eq_scheme sp =
+ (* fetching global env *)
+ let env = Global.env() in
+ (* fetching the mutual inductive body *)
+ let mib = Global.lookup_mind sp in
+ (* number of inductives in the mutual *)
+ let nb_ind = Array.length mib.mind_packets in
+ (* number of params in the type *)
+ let nparams = mib.mind_nparams in
+ let nparrec = mib.mind_nparams_rec in
+ (* params context divided *)
+ let lnonparrec,lnamesparrec =
+ context_chop (nparams-nparrec) mib.mind_params_ctxt in
+ (* predef coq's boolean type *)
+ (* rec name *)
+ let rec_name i =(string_of_id (Array.get mib.mind_packets i).mind_typename)^
+ "_eqrec"
+ in
+ (* construct the "fun A B ... N, eqA eqB eqC ... N => fixpoint" part *)
+ let create_input c =
+ let myArrow u v = mkArrow u (lift 1 v)
+ and eqName = function
+ | Name s -> id_of_string ("eq_"^(string_of_id s))
+ | Anonymous -> id_of_string "eq_A"
+ in
+ let ext_rel_list = extended_rel_list 0 lnamesparrec in
+ let lift_cnt = ref 0 in
+ let eqs_typ = List.map (fun aa ->
+ let a = lift !lift_cnt aa in
+ incr lift_cnt;
+ myArrow a (myArrow a bb)
+ ) ext_rel_list in
+
+ let eq_input = List.fold_left2
+ ( fun a b (n,_,_) -> (* mkLambda(n,b,a) ) *)
+ (* here I leave the Naming thingy so that the type of
+ the function is more readable for the user *)
+ mkNamedLambda (eqName n) b a )
+ c (List.rev eqs_typ) lnamesparrec
+ in
+ List.fold_left (fun a (n,_,t) ->(* mkLambda(n,t,a)) eq_input rel_list *)
+ (* Same here , hoping the auto renaming will do something good ;) *)
+ mkNamedLambda
+ (match n with Name s -> s | Anonymous -> id_of_string "A")
+ t a) eq_input lnamesparrec
+ in
+ let make_one_eq cur =
+ let ind = sp,cur in
+ (* current inductive we are working on *)
+ let cur_packet = mib.mind_packets.(snd ind) in
+ (* Inductive toto : [rettyp] := *)
+ let rettyp = Inductive.type_of_inductive env (mib,cur_packet) in
+ (* split rettyp in a list without the non rec params and the last ->
+ e.g. Inductive vec (A:Set) : nat -> Set := ... will do [nat] *)
+ let rettyp_l = quick_chop nparrec (deconstruct_type rettyp) in
+ (* give a type A, this function tries to find the equality on A declared
+ previously *)
+ (* nlist = the number of args (A , B , ... )
+ eqA = the deBruijn index of the first eq param
+ ndx = how much to translate due to the 2nd Case
+ *)
+ let compute_A_equality rel_list nlist eqA ndx t =
+ let lifti = ndx in
+ let rec aux c a = match c with
+ | Rel x -> mkRel (x-nlist+ndx)
+ | Var x -> mkVar (id_of_string ("eq_"^(string_of_id x)))
+ | Cast (x,_,_) -> aux (kind_of_term x) a
+ | App (x,newa) -> aux (kind_of_term x) newa
+ | Ind (sp',i) -> if sp=sp' then mkRel(eqA-nlist-i+nb_ind-1)
+ else ( try
+ let eq = find_eq_scheme (sp',i)
+ and eqa = Array.map
+ (fun x -> aux (kind_of_term x) [||] ) a
+ in
+ let args = Array.append
+ (Array.map (fun x->lift lifti x) a) eqa
+ in if args = [||] then eq
+ else mkApp (eq,Array.append
+ (Array.map (fun x->lift lifti x) a) eqa)
+ with Not_found -> raise(EqNotFound (string_of_kn sp'))
+ )
+ | Sort _ -> raise (EqUnknown "Sort" )
+ | Prod _ -> raise (EqUnknown "Prod" )
+ | Lambda _-> raise (EqUnknown "Lambda")
+ | LetIn _ -> raise (EqUnknown "LetIn")
+ | Const kn -> let mp,dir,lbl= repr_con kn in
+ mkConst (make_con mp dir (
+ mk_label ("eq_"^(string_of_label lbl))))
+ | Construct _ -> raise (EqUnknown "Construct")
+ | Case _ -> raise (EqUnknown "Case")
+ | CoFix _ -> raise (EqUnknown "CoFix")
+ | Fix _ -> raise (EqUnknown "Fix")
+ | Meta _ -> raise (EqUnknown "Meta")
+ | Evar _ -> raise (EqUnknown "Evar")
+ in
+ aux t [||]
+ in
+ (* construct the predicate for the Case part*)
+ let do_predicate rel_list n =
+ List.fold_left (fun a b -> mkLambda(Anonymous,b,a))
+ (mkLambda (Anonymous,
+ mkFullInd ind (n+3+(List.length rettyp_l)+nb_ind-1),
+ bb))
+ (List.rev rettyp_l) in
+ (* make_one_eq *)
+ (* do the [| C1 ... => match Y with ... end
+ ...
+ Cn => match Y with ... end |] part *)
+ let ci = make_case_info env ind MatchStyle in
+ let constrs n = get_constructors env (make_ind_family (ind,
+ extended_rel_list (n+nb_ind-1) mib.mind_params_ctxt)) in
+ let constrsi = constrs (3+nparrec) in
+ let n = Array.length constrsi in
+ let ar = Array.create n ff in
+ for i=0 to n-1 do
+ let nb_cstr_args = List.length constrsi.(i).cs_args in
+ let ar2 = Array.create n ff in
+ let constrsj = constrs (3+nparrec+nb_cstr_args) in
+ for j=0 to n-1 do
+ if (i=j) then
+ ar2.(j) <- let cc = (match nb_cstr_args with
+ | 0 -> tt
+ | _ -> let eqs = Array.make nb_cstr_args tt in
+ for ndx = 0 to nb_cstr_args-1 do
+ let _,_,cc = List.nth constrsi.(i).cs_args ndx in
+ let eqA = compute_A_equality rel_list
+ nparrec
+ (nparrec+3+2*nb_cstr_args)
+ (nb_cstr_args+ndx+1)
+ (kind_of_term cc)
+ in
+ Array.set eqs ndx
+ (mkApp (eqA,
+ [|mkRel (ndx+1+nb_cstr_args);mkRel (ndx+1)|]
+ ))
+ done;
+ Array.fold_left
+ (fun a b -> mkApp (andb(),[|b;a|]))
+ (eqs.(0))
+ (Array.sub eqs 1 (nb_cstr_args - 1))
+ )
+ in
+ (List.fold_left (fun a (p,q,r) -> mkLambda (p,r,a)) cc
+ (constrsj.(j).cs_args)
+ )
+ else ar2.(j) <- (List.fold_left (fun a (p,q,r) ->
+ mkLambda (p,r,a)) ff (constrsj.(j).cs_args) )
+ done;
+
+ ar.(i) <- (List.fold_left (fun a (p,q,r) -> mkLambda (p,r,a))
+ (mkCase (ci,do_predicate rel_list nb_cstr_args,
+ mkVar (id_of_string "Y") ,ar2))
+ (constrsi.(i).cs_args))
+ done;
+ mkNamedLambda (id_of_string "X") (mkFullInd ind (nb_ind-1+1)) (
+ mkNamedLambda (id_of_string "Y") (mkFullInd ind (nb_ind-1+2)) (
+ mkCase (ci, do_predicate rel_list 0,mkVar (id_of_string "X"),ar)))
+ in (* make_eq_scheme *)
+ try
+ let names = Array.make nb_ind Anonymous and
+ types = Array.make nb_ind mkSet and
+ cores = Array.make nb_ind mkSet and
+ res = Array.make nb_ind mkSet in
+ for i=0 to (nb_ind-1) do
+ names.(i) <- Name (id_of_string (rec_name i));
+ types.(i) <- mkArrow (mkFullInd (sp,i) 0)
+ (mkArrow (mkFullInd (sp,i) 1) bb);
+ cores.(i) <- make_one_eq i
+ done;
+ if (string_of_mp (modpath sp ))="Coq.Init.Logic"
+ then print_string "Logic time, do nothing.\n"
+ else (
+ for i=0 to (nb_ind-1) do
+ let cpack = Array.get mib.mind_packets i in
+ if check_eq_scheme (sp,i)
+ then message ("Boolean equality is already defined on "^
+ (string_of_id cpack.mind_typename)^".")
+ else (
+ let fix = mkFix (((Array.make nb_ind 0),i),(names,types,cores)) in
+ res.(i) <- create_input fix
+ )
+ done;
+ );
+ res
+ with
+ | EqUnknown s -> error ("Type unexpected ("^s^
+ ") during boolean eq computation, please report.")
+ | EqNotFound s -> error ("Boolean equality on "^s^
+ " is missing, equality will not be defined.")
+ | _ -> error ("Unknown exception during boolean equality creation,"^
+ " the equality will not be defined.")
+
+(* This function tryies to get the [inductive] between a constr
+ the constr should be Ind i or App(Ind i,[|args|])
+*)
+let destruct_ind c =
+ try let u,v = destApp c in
+ let indc = destInd u in
+ indc,v
+ with _-> let indc = destInd c in
+ indc,[||]
+
+(*
+ In the followind, avoid is the list of names to avoid.
+ If the args of the Inductive type are A1 ... An
+ then avoid should be
+ [| lb_An ... lb _A1 (resp. bl_An ... bl_A1)
+ eq_An .... eq_A1 An ... A1 |]
+so from Ai we can find the the correct eq_Ai bl_ai or lb_ai
+*)
+(* used in the leib -> bool side*)
+let do_replace_lb aavoid narg gls p q =
+ let avoid = Array.of_list aavoid in
+ let do_arg v offset =
+ try
+ let x = narg*offset in
+ let s = destVar v in
+ let n = Array.length avoid in
+ let rec find i =
+ if avoid.(n-i) = s then avoid.(n-i-x)
+ else (if i<n then find (i+1)
+ else error ("Var "^(string_of_id s)^" seems unknown.")
+ )
+ in mkVar (find 1)
+ with _ -> (* if this happen then the args have to be already declared as a
+ Parameter*)
+ (
+ let mp,dir,lbl = repr_con (destConst v) in
+ mkConst (make_con mp dir (mk_label (
+ if offset=1 then ("eq_"^(string_of_label lbl))
+ else ((string_of_label lbl)^"_lb")
+ )))
+ )
+ in
+ let type_of_pq = pf_type_of gls p in
+ let u,v = destruct_ind type_of_pq
+ in let lb_type_of_p =
+ try find_lb_proof u
+ with Not_found ->
+ (* spiwack: the format of this error message should probably
+ be improved. *)
+ let err_msg = msg_with Format.str_formatter
+ (str "Leibniz->boolean:" ++
+ str "You have to declare the" ++
+ str "decidability over " ++
+ Printer.pr_constr type_of_pq ++
+ str " first.");
+ Format.flush_str_formatter ()
+ in
+ error err_msg
+ in let lb_args = Array.append (Array.append
+ (Array.map (fun x -> x) v)
+ (Array.map (fun x -> do_arg x 1) v))
+ (Array.map (fun x -> do_arg x 2) v)
+ in let app = if lb_args = [||]
+ then lb_type_of_p else mkApp (lb_type_of_p,lb_args)
+ in [Equality.replace p q ; apply app ; Auto.default_auto]
+
+
+(* used in the bool -> leib side *)
+let do_replace_bl ind gls aavoid narg lft rgt =
+ let avoid = Array.of_list aavoid in
+ let do_arg v offset =
+ try
+ let x = narg*offset in
+ let s = destVar v in
+ let n = Array.length avoid in
+ let rec find i =
+ if avoid.(n-i) = s then avoid.(n-i-x)
+ else (if i<n then find (i+1)
+ else error ("Var "^(string_of_id s)^" seems unknown.")
+ )
+ in mkVar (find 1)
+ with _ -> (* if this happen then the args have to be already declared as a
+ Parameter*)
+ (
+ let mp,dir,lbl = repr_con (destConst v) in
+ mkConst (make_con mp dir (mk_label (
+ if offset=1 then ("eq_"^(string_of_label lbl))
+ else ((string_of_label lbl)^"_bl")
+ )))
+ )
+ in
+
+ let rec aux l1 l2 =
+ match (l1,l2) with
+ | (t1::q1,t2::q2) -> let tt1 = pf_type_of gls t1 in
+ if t1=t2 then aux q1 q2
+ else (
+ let u,v = try destruct_ind tt1
+ (* trick so that the good sequence is returned*)
+ with _ -> ind,[||]
+ in if u = ind
+ then (Equality.replace t1 t2)::(Auto.default_auto)::(aux q1 q2)
+ else (
+ let bl_t1 =
+ try find_bl_proof u
+ with Not_found ->
+ (* spiwack: the format of this error message should probably
+ be improved. *)
+ let err_msg = msg_with Format.str_formatter
+ (str "boolean->Leibniz:" ++
+ str "You have to declare the" ++
+ str "decidability over " ++
+ Printer.pr_constr tt1 ++
+ str " first.");
+ Format.flush_str_formatter ()
+ in
+ error err_msg
+ in let bl_args =
+ Array.append (Array.append
+ (Array.map (fun x -> x) v)
+ (Array.map (fun x -> do_arg x 1) v))
+ (Array.map (fun x -> do_arg x 2) v )
+ in
+ let app = if bl_args = [||]
+ then bl_t1 else mkApp (bl_t1,bl_args)
+ in
+ (Equality.replace_by t1 t2
+ (tclTHEN (apply app) (Auto.default_auto)))::(aux q1 q2)
+ )
+ )
+ | ([],[]) -> []
+ | _ -> error "Both side of the equality must have the same arity."
+ in
+ let (ind1,ca1) = try destApp lft with
+ _ -> error "replace failed."
+ and (ind2,ca2) = try destApp rgt with
+ _ -> error "replace failed."
+ in
+ let (sp1,i1) = try destInd ind1 with
+ _ -> (try fst (destConstruct ind1) with _ ->
+ error "The expected type is an inductive one.")
+ and (sp2,i2) = try destInd ind2 with
+ _ -> (try fst (destConstruct ind2) with _ ->
+ error "The expected type is an inductive one.")
+ in
+ if (sp1 <> sp2) || (i1 <> i2)
+ then (error "Eq should be on the same type")
+ else (aux (Array.to_list ca1) (Array.to_list ca2))
+
+(*
+ create, from a list of ids [i1,i2,...,in] the list
+ [(in,eq_in,in_bl,in_al),,...,(i1,eq_i1,i1_bl_i1_al )]
+*)
+let list_id l = List.fold_left ( fun a (n,_,t) -> let s' =
+ match n with
+ Name s -> string_of_id s
+ | Anonymous -> "A" in
+ (id_of_string s',id_of_string ("eq_"^s'),
+ id_of_string (s'^"_bl"),
+ id_of_string (s'^"_lb"))
+ ::a
+ ) [] l
+(*
+ build the right eq_I A B.. N eq_A .. eq_N
+*)
+let eqI ind l =
+ let list_id = list_id l in
+ let eA = Array.of_list((List.map (fun (s,_,_,_) -> mkVar s) list_id)@
+ (List.map (fun (_,seq,_,_)-> mkVar seq) list_id ))
+ and e = try find_eq_scheme ind with
+ Not_found -> error
+ ("The boolean equality on "^(string_of_kn (fst ind))^" is needed.");
+ in (if eA = [||] then e else mkApp(e,eA))
+
+let compute_bl_goal ind lnamesparrec nparrec =
+ let eqI = eqI ind lnamesparrec in
+ let list_id = list_id lnamesparrec in
+ let create_input c =
+ let x = id_of_string "x" and
+ y = id_of_string "y" in
+ let bl_typ = List.map (fun (s,seq,_,_) ->
+ mkNamedProd x (mkVar s) (
+ mkNamedProd y (mkVar s) (
+ mkArrow
+ ( mkApp(eq,[|bb;mkApp(mkVar seq,[|mkVar x;mkVar y|]);tt|]))
+ ( mkApp(eq,[|mkVar s;mkVar x;mkVar y|]))
+ ))
+ ) list_id in
+ let bl_input = List.fold_left2 ( fun a (s,_,sbl,_) b ->
+ mkNamedProd sbl b a
+ ) c (List.rev list_id) (List.rev bl_typ) in
+ let eqs_typ = List.map (fun (s,_,_,_) ->
+ mkProd(Anonymous,mkVar s,mkProd(Anonymous,mkVar s,bb))
+ ) list_id in
+ let eq_input = List.fold_left2 ( fun a (s,seq,_,_) b ->
+ mkNamedProd seq b a
+ ) bl_input (List.rev list_id) (List.rev eqs_typ) in
+ List.fold_left (fun a (n,_,t) -> mkNamedProd
+ (match n with Name s -> s | Anonymous -> id_of_string "A")
+ t a) eq_input lnamesparrec
+ in
+ let n = id_of_string "n" and
+ m = id_of_string "m" in
+ create_input (
+ mkNamedProd n (mkFullInd ind nparrec) (
+ mkNamedProd m (mkFullInd ind (nparrec+1)) (
+ mkArrow
+ (mkApp(eq,[|bb;mkApp(eqI,[|mkVar n;mkVar m|]);tt|]))
+ (mkApp(eq,[|mkFullInd ind (nparrec+3);mkVar n;mkVar m|]))
+ )))
+
+let compute_bl_tact ind lnamesparrec nparrec =
+ let list_id = list_id lnamesparrec in
+ let avoid = ref [] in
+ let gsig = top_goal_of_pftreestate (Pfedit.get_pftreestate()) in
+ let first_intros =
+ ( List.map (fun (s,_,_,_) -> s ) list_id ) @
+ ( List.map (fun (_,seq,_,_ ) -> seq) list_id ) @
+ ( List.map (fun (_,_,sbl,_ ) -> sbl) list_id )
+ in
+ let fresh_first_intros = List.map ( fun s ->
+ let fresh = fresh_id (!avoid) s gsig in
+ avoid := fresh::(!avoid); fresh ) first_intros in
+ let freshn = fresh_id (!avoid) (id_of_string "n") gsig in
+ let freshm = avoid := freshn::(!avoid);
+ fresh_id (!avoid) (id_of_string "m") gsig in
+ let freshz = avoid := freshm::(!avoid);
+ fresh_id (!avoid) (id_of_string "Z") gsig in
+ (* try with *)
+ avoid := freshz::(!avoid);
+ Pfedit.by (
+ tclTHENSEQ [ intros_using fresh_first_intros;
+ intro_using freshn ;
+ new_induct false [ (Tacexpr.ElimOnConstr ((mkVar freshn),
+ Rawterm.NoBindings))]
+ None
+ Genarg.IntroAnonymous
+ None;
+ intro_using freshm;
+ new_destruct false [ (Tacexpr.ElimOnConstr ((mkVar freshm),
+ Rawterm.NoBindings))]
+ None
+ Genarg.IntroAnonymous
+ None;
+ intro_using freshz;
+ intros;
+ tclTRY (
+ tclORELSE reflexivity (Equality.discr_tac false None)
+ );
+ simpl_in_hyp
+ ((Rawterm.all_occurrences_expr,freshz),Tacexpr.InHyp);
+(*
+repeat ( apply andb_prop in z;let z1:= fresh "Z" in destruct z as [z1 z]).
+*)
+ tclREPEAT (
+ tclTHENSEQ [
+ apply_in false freshz [(andb_prop()),Rawterm.NoBindings];
+ fun gl ->
+ let fresht = fresh_id (!avoid) (id_of_string "Z") gsig
+ in
+ avoid := fresht::(!avoid);
+ (new_destruct false [Tacexpr.ElimOnConstr
+ ((mkVar freshz,Rawterm.NoBindings))]
+ None
+ ( Genarg.IntroOrAndPattern [[
+ Genarg.IntroIdentifier fresht;
+ Genarg.IntroIdentifier freshz]]) None) gl
+ ]);
+(*
+ Ci a1 ... an = Ci b1 ... bn
+ replace bi with ai; auto || replace bi with ai by apply typeofbi_prod ; auto
+*)
+ fun gls-> let gl = (gls.Evd.it).Evd.evar_concl in
+ match (kind_of_term gl) with
+ | App (c,ca) -> (
+ match (kind_of_term c) with
+ | Ind (i1,i2) ->
+ if(string_of_label (label i1) = "eq")
+ then (
+ tclTHENSEQ ((do_replace_bl ind gls (!avoid)
+ nparrec (ca.(2))
+ (ca.(1)))@[Auto.default_auto]) gls
+ )
+ else
+ (error "Failure while solving Boolean->Leibniz.")
+ | _ -> error "Failure while solving Boolean->Leibniz."
+ )
+ | _ -> error "Failure while solving Boolean->Leibniz."
+
+ ]
+ )
+
+let compute_lb_goal ind lnamesparrec nparrec =
+ let list_id = list_id lnamesparrec in
+ let eqI = eqI ind lnamesparrec in
+ let create_input c =
+ let x = id_of_string "x" and
+ y = id_of_string "y" in
+ let lb_typ = List.map (fun (s,seq,_,_) ->
+ mkNamedProd x (mkVar s) (
+ mkNamedProd y (mkVar s) (
+ mkArrow
+ ( mkApp(eq,[|mkVar s;mkVar x;mkVar y|]))
+ ( mkApp(eq,[|bb;mkApp(mkVar seq,[|mkVar x;mkVar y|]);tt|]))
+ ))
+ ) list_id in
+ let lb_input = List.fold_left2 ( fun a (s,_,_,slb) b ->
+ mkNamedProd slb b a
+ ) c (List.rev list_id) (List.rev lb_typ) in
+ let eqs_typ = List.map (fun (s,_,_,_) ->
+ mkProd(Anonymous,mkVar s,mkProd(Anonymous,mkVar s,bb))
+ ) list_id in
+ let eq_input = List.fold_left2 ( fun a (s,seq,_,_) b ->
+ mkNamedProd seq b a
+ ) lb_input (List.rev list_id) (List.rev eqs_typ) in
+ List.fold_left (fun a (n,_,t) -> mkNamedProd
+ (match n with Name s -> s | Anonymous -> id_of_string "A")
+ t a) eq_input lnamesparrec
+ in
+ let n = id_of_string "n" and
+ m = id_of_string "m" in
+ create_input (
+ mkNamedProd n (mkFullInd ind nparrec) (
+ mkNamedProd m (mkFullInd ind (nparrec+1)) (
+ mkArrow
+ (mkApp(eq,[|mkFullInd ind (nparrec+2);mkVar n;mkVar m|]))
+ (mkApp(eq,[|bb;mkApp(eqI,[|mkVar n;mkVar m|]);tt|]))
+ )))
+
+let compute_lb_tact ind lnamesparrec nparrec =
+ let list_id = list_id lnamesparrec in
+ let avoid = ref [] in
+ let gsig = top_goal_of_pftreestate (Pfedit.get_pftreestate()) in
+ let first_intros =
+ ( List.map (fun (s,_,_,_) -> s ) list_id ) @
+ ( List.map (fun (_,seq,_,_) -> seq) list_id ) @
+ ( List.map (fun (_,_,_,slb) -> slb) list_id )
+ in
+ let fresh_first_intros = List.map ( fun s ->
+ let fresh = fresh_id (!avoid) s gsig in
+ avoid := fresh::(!avoid); fresh ) first_intros in
+ let freshn = fresh_id (!avoid) (id_of_string "n") gsig in
+ let freshm = avoid := freshn::(!avoid);
+ fresh_id (!avoid) (id_of_string "m") gsig in
+ let freshz = avoid := freshm::(!avoid);
+ fresh_id (!avoid) (id_of_string "Z") gsig in
+ (* try with *)
+ avoid := freshz::(!avoid);
+ Pfedit.by (
+ tclTHENSEQ [ intros_using fresh_first_intros;
+ intro_using freshn ;
+ new_induct false [Tacexpr.ElimOnConstr
+ ((mkVar freshn),Rawterm.NoBindings)]
+ None
+ Genarg.IntroAnonymous
+ None;
+ intro_using freshm;
+ new_destruct false [Tacexpr.ElimOnConstr
+ ((mkVar freshm),Rawterm.NoBindings)]
+ None
+ Genarg.IntroAnonymous
+ None;
+ intro_using freshz;
+ intros;
+ tclTRY (
+ tclORELSE reflexivity (Equality.discr_tac false None)
+ );
+ Equality.inj [] false (mkVar freshz,Rawterm.NoBindings);
+ intros; simpl_in_concl;
+ Auto.default_auto;
+ tclREPEAT (
+ tclTHENSEQ [apply (andb_true_intro());
+ simplest_split ;Auto.default_auto ]
+ );
+ fun gls -> let gl = (gls.Evd.it).Evd.evar_concl in
+ (* assume the goal to be eq (eq_type ...) = true *)
+ match (kind_of_term gl) with
+ | App(c,ca) -> (match (kind_of_term ca.(1)) with
+ | App(c',ca') ->
+ let n = Array.length ca' in
+ tclTHENSEQ (do_replace_lb (!avoid)
+ nparrec gls
+ ca'.(n-2) ca'.(n-1)) gls
+ | _ -> error
+ "Failure while solving Leibniz->Boolean."
+ )
+ | _ -> error
+ "Failure while solving Leibniz->Boolean."
+ ]
+ )
+
+(* {n=m}+{n<>m} part *)
+let compute_dec_goal ind lnamesparrec nparrec =
+ let list_id = list_id lnamesparrec in
+ let create_input c =
+ let x = id_of_string "x" and
+ y = id_of_string "y" in
+ let lb_typ = List.map (fun (s,seq,_,_) ->
+ mkNamedProd x (mkVar s) (
+ mkNamedProd y (mkVar s) (
+ mkArrow
+ ( mkApp(eq,[|mkVar s;mkVar x;mkVar y|]))
+ ( mkApp(eq,[|bb;mkApp(mkVar seq,[|mkVar x;mkVar y|]);tt|]))
+ ))
+ ) list_id in
+ let bl_typ = List.map (fun (s,seq,_,_) ->
+ mkNamedProd x (mkVar s) (
+ mkNamedProd y (mkVar s) (
+ mkArrow
+ ( mkApp(eq,[|bb;mkApp(mkVar seq,[|mkVar x;mkVar y|]);tt|]))
+ ( mkApp(eq,[|mkVar s;mkVar x;mkVar y|]))
+ ))
+ ) list_id in
+
+ let lb_input = List.fold_left2 ( fun a (s,_,_,slb) b ->
+ mkNamedProd slb b a
+ ) c (List.rev list_id) (List.rev lb_typ) in
+ let bl_input = List.fold_left2 ( fun a (s,_,sbl,_) b ->
+ mkNamedProd sbl b a
+ ) lb_input (List.rev list_id) (List.rev bl_typ) in
+
+ let eqs_typ = List.map (fun (s,_,_,_) ->
+ mkProd(Anonymous,mkVar s,mkProd(Anonymous,mkVar s,bb))
+ ) list_id in
+ let eq_input = List.fold_left2 ( fun a (s,seq,_,_) b ->
+ mkNamedProd seq b a
+ ) bl_input (List.rev list_id) (List.rev eqs_typ) in
+ List.fold_left (fun a (n,_,t) -> mkNamedProd
+ (match n with Name s -> s | Anonymous -> id_of_string "A")
+ t a) eq_input lnamesparrec
+ in
+ let n = id_of_string "n" and
+ m = id_of_string "m" in
+ let eqnm = mkApp(eq,[|mkFullInd ind (2*nparrec+2);mkVar n;mkVar m|]) in
+ create_input (
+ mkNamedProd n (mkFullInd ind (2*nparrec)) (
+ mkNamedProd m (mkFullInd ind (2*nparrec+1)) (
+ mkApp(sumbool(),[|eqnm;mkApp (Coqlib.build_coq_not(),[|eqnm|])|])
+ )
+ )
+ )
+
+let compute_dec_tact ind lnamesparrec nparrec =
+ let list_id = list_id lnamesparrec in
+ let eqI = eqI ind lnamesparrec in
+ let avoid = ref [] in
+ let gsig = top_goal_of_pftreestate (Pfedit.get_pftreestate()) in
+ let eqtrue x = mkApp(eq,[|bb;x;tt|]) in
+ let eqfalse x = mkApp(eq,[|bb;x;ff|]) in
+ let first_intros =
+ ( List.map (fun (s,_,_,_) -> s ) list_id ) @
+ ( List.map (fun (_,seq,_,_) -> seq) list_id ) @
+ ( List.map (fun (_,_,sbl,_) -> sbl) list_id ) @
+ ( List.map (fun (_,_,_,slb) -> slb) list_id )
+ in
+ let fresh_first_intros = List.map ( fun s ->
+ let fresh = fresh_id (!avoid) s gsig in
+ avoid := fresh::(!avoid); fresh ) first_intros in
+ let freshn = fresh_id (!avoid) (id_of_string "n") gsig in
+ let freshm = avoid := freshn::(!avoid);
+ fresh_id (!avoid) (id_of_string "m") gsig in
+ let freshH = avoid := freshm::(!avoid);
+ fresh_id (!avoid) (id_of_string "H") gsig in
+ let eqbnm = mkApp(eqI,[|mkVar freshn;mkVar freshm|]) in
+ avoid := freshH::(!avoid);
+ Pfedit.by ( tclTHENSEQ [
+ intros_using fresh_first_intros;
+ intros_using [freshn;freshm];
+ assert_as true (Genarg.IntroIdentifier freshH) (
+ mkApp(sumbool(),[|eqtrue eqbnm; eqfalse eqbnm|])
+ ) ]);
+(*we do this so we don't have to prove the same goal twice *)
+ Pfedit.by ( tclTHEN
+ (new_destruct false [Tacexpr.ElimOnConstr
+ (eqbnm,Rawterm.NoBindings)]
+ None
+ Genarg.IntroAnonymous
+ None)
+ Auto.default_auto
+ );
+ Pfedit.by (
+ let freshH2 = fresh_id (!avoid) (id_of_string "H") gsig in
+ avoid := freshH2::(!avoid);
+ new_destruct false [Tacexpr.ElimOnConstr
+ ((mkVar freshH),Rawterm.NoBindings)]
+ None
+ (Genarg.IntroOrAndPattern [
+ [Genarg.IntroAnonymous];
+ [Genarg.IntroIdentifier freshH2]]) None
+ );
+ let arfresh = Array.of_list fresh_first_intros in
+ let xargs = Array.sub arfresh 0 (2*nparrec) in
+ let blI = try find_bl_proof ind with
+ Not_found -> error (
+ "Error during the decidability part, boolean to leibniz"^
+ " equality is required.")
+ in
+ let lbI = try find_lb_proof ind with
+ Not_found -> error (
+ "Error during the decidability part, leibniz to boolean"^
+ " equality is required.")
+ in
+
+ (* left *)
+ Pfedit.by ( tclTHENSEQ [ simplest_left;
+ apply (mkApp(blI,Array.map(fun x->mkVar x) xargs));
+ Auto.default_auto
+ ]);
+ (*right *)
+ let freshH3 = fresh_id (!avoid) (id_of_string "H") gsig in
+ avoid := freshH3::(!avoid);
+ Pfedit.by (tclTHENSEQ [ simplest_right ;
+ unfold_constr (Lazy.force Coqlib.coq_not_ref);
+ intro;
+ Equality.subst_all;
+ assert_as true (Genarg.IntroIdentifier freshH3)
+ (mkApp(eq,[|bb;mkApp(eqI,[|mkVar freshm;mkVar freshm|]);tt|]))
+ ]);
+ Pfedit.by
+ (tclTHENSEQ [apply (mkApp(lbI,Array.map (fun x->mkVar x) xargs));
+ Auto.default_auto
+ ]);
+ Pfedit.by (Equality.general_rewrite_bindings_in true
+ all_occurrences
+ (List.hd !avoid)
+ ((mkVar (List.hd (List.tl !avoid))),
+ Rawterm.NoBindings
+ )
+ true);
+ Pfedit.by (Equality.discr_tac false None)
+
+