1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
|
(************************************************************************)
(* 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 11671 2008-12-12 12:43:03Z 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
let dl = dummy_loc
(* 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
(None,None)
None;
intro_using freshm;
new_destruct false [ (Tacexpr.ElimOnConstr ((mkVar freshm),
Rawterm.NoBindings))]
None
(None,None)
None;
intro_using freshz;
intros;
tclTRY (
tclORELSE reflexivity (Equality.discr_tac false None)
);
simpl_in_hyp
((Rawterm.all_occurrences_expr,freshz),InHyp);
(*
repeat ( apply andb_prop in z;let z1:= fresh "Z" in destruct z as [z1 z]).
*)
tclREPEAT (
tclTHENSEQ [
apply_in false false freshz [(Evd.empty,andb_prop()),Rawterm.NoBindings] None;
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
(None, Some (dl,Genarg.IntroOrAndPattern [[
dl,Genarg.IntroIdentifier fresht;
dl,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
(None,None)
None;
intro_using freshm;
new_destruct false [Tacexpr.ElimOnConstr
((mkVar freshm),Rawterm.NoBindings)]
None
(None,None)
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_tac (Name 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
(None,None)
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
(None,Some (dl,Genarg.IntroOrAndPattern [
[dl,Genarg.IntroAnonymous];
[dl,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_tac (Name 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)
|