aboutsummaryrefslogtreecommitdiff
path: root/tactics
diff options
context:
space:
mode:
authorherbelin2012-04-15 22:06:11 +0000
committerherbelin2012-04-15 22:06:11 +0000
commite1f5180e88bf02a22c954ddbdcbdfeb168d264a6 (patch)
tree86e1f5b98681f5e85aef645a9de894508d98920b /tactics
parent25c1cfeea010b7267955d6683a381b50e2f52f71 (diff)
Fixing tauto "special" behavior on singleton types w/ 2 parameters (bug #2680).
- tauto/intuition now works uniformly on and, prod, or, sum, False, Empty_set, unit, True (and isomorphic copies of them), iff, ->, and on all inhabited singleton types with a no-arguments constructor such as "eq t t" (even though the last case goes out of propositional logic: this features is so often used that it is difficult to come back on it). - New dtauto and dintuition works on all inductive types with one constructors and no real arguments (for instance, they work on records such as "Equivalence"), in addition to -> and eq-like types. - Moreover, both of them no longer unfold inner negations (this is a souce of incompatibility for intuition and evaluation of the level of incompatibility on contribs still needs to be done). Incidentally, and amazingly, fixing bug #2680 made that constants InfA_compat and InfA_eqA in SetoidList.v lost one argument: old tauto had indeed destructed a section hypothesis "@StrictOrder A ltA@ thinking it was a conjunction, making this section hypothesis artificially necessary while it was not. Renouncing to the unfolding of inner negations made auto/eauto sometimes succeeding more, sometimes succeeding less. There is by the way a (standard) problem with not in auto/eauto: even when given as an "unfold hint", it works only in goals, not in hypotheses, so that auto is not able to solve something like "forall P, (forall x, ~ P x) -> P 0 -> False". Should we automatically add a lemma of type "HYPS -> A -> False" in the hint database everytime a lemma ""HYPS -> ~A" is declared (and "unfold not" is a hint), and similarly for all unfold hints? At this occasion, also re-did some proofs of Znumtheory. git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@15180 85f007b7-540e-0410-9357-904b9bb8a0f7
Diffstat (limited to 'tactics')
-rw-r--r--tactics/hipattern.ml435
-rw-r--r--tactics/hipattern.mli8
-rw-r--r--tactics/tauto.ml4211
3 files changed, 159 insertions, 95 deletions
diff --git a/tactics/hipattern.ml4 b/tactics/hipattern.ml4
index 6f07eed703..4f1174916b 100644
--- a/tactics/hipattern.ml4
+++ b/tactics/hipattern.ml4
@@ -81,9 +81,9 @@ let has_nodep_prod = has_nodep_prod_after 0
(* style: None = record; Some false = conjunction; Some true = strict conj *)
-let match_with_one_constructor style allow_rec t =
+let match_with_one_constructor style onlybinary allow_rec t =
let (hdapp,args) = decompose_app t in
- match kind_of_term hdapp with
+ let res = match kind_of_term hdapp with
| Ind ind ->
let (mib,mip) = Global.lookup_inductive ind in
if (Array.length mip.mind_consnames = 1)
@@ -110,22 +110,25 @@ let match_with_one_constructor style allow_rec t =
None
else
None
+ | _ -> None in
+ match res with
+ | Some (hdapp,args) when not onlybinary || List.length args = 2 -> res
| _ -> None
-let match_with_conjunction ?(strict=false) t =
- match_with_one_constructor (Some strict) false t
+let match_with_conjunction ?(strict=false) ?(onlybinary=false) t =
+ match_with_one_constructor (Some strict) onlybinary false t
let match_with_record t =
- match_with_one_constructor None false t
+ match_with_one_constructor None false false t
-let is_conjunction ?(strict=false) t =
- op2bool (match_with_conjunction ~strict t)
+let is_conjunction ?(strict=false) ?(onlybinary=false) t =
+ op2bool (match_with_conjunction ~strict ~onlybinary t)
let is_record t =
op2bool (match_with_record t)
let match_with_tuple t =
- let t = match_with_one_constructor None true t in
+ let t = match_with_one_constructor None false true t in
Option.map (fun (hd,l) ->
let ind = destInd hd in
let (mib,mip) = Global.lookup_inductive ind in
@@ -146,14 +149,15 @@ let test_strict_disjunction n lc =
| [_,None,c] -> isRel c && destRel c = (n - i)
| _ -> false) 0 lc
-let match_with_disjunction ?(strict=false) t =
+let match_with_disjunction ?(strict=false) ?(onlybinary=false) t =
let (hdapp,args) = decompose_app t in
- match kind_of_term hdapp with
+ let res = match kind_of_term hdapp with
| Ind ind ->
let car = mis_constr_nargs ind in
let (mib,mip) = Global.lookup_inductive ind in
- if array_for_all (fun ar -> ar = 1) car &&
- not (mis_is_recursive (ind,mib,mip))
+ if array_for_all (fun ar -> ar = 1) car
+ && not (mis_is_recursive (ind,mib,mip))
+ && (mip.mind_nrealargs = 0)
then
if strict then
if test_strict_disjunction mib.mind_nparams mip.mind_nf_lc then
@@ -167,10 +171,13 @@ let match_with_disjunction ?(strict=false) t =
Some (hdapp,Array.to_list cargs)
else
None
+ | _ -> None in
+ match res with
+ | Some (hdapp,args) when not onlybinary || List.length args = 2 -> res
| _ -> None
-let is_disjunction ?(strict=false) t =
- op2bool (match_with_disjunction ~strict t)
+let is_disjunction ?(strict=false) ?(onlybinary=false) t =
+ op2bool (match_with_disjunction ~strict ~onlybinary t)
(* An empty type is an inductive type, possible with indices, that has no
constructors *)
diff --git a/tactics/hipattern.mli b/tactics/hipattern.mli
index 82e9e3b8eb..e4ae554091 100644
--- a/tactics/hipattern.mli
+++ b/tactics/hipattern.mli
@@ -53,13 +53,13 @@ val is_non_recursive_type : testing_function
(** Non recursive type with no indices and exactly one argument for each
constructor; canonical definition of n-ary disjunction if strict *)
-val match_with_disjunction : ?strict:bool -> (constr * constr list) matching_function
-val is_disjunction : ?strict:bool -> testing_function
+val match_with_disjunction : ?strict:bool -> ?onlybinary:bool -> (constr * constr list) matching_function
+val is_disjunction : ?strict:bool -> ?onlybinary:bool -> testing_function
(** Non recursive tuple (one constructor and no indices) with no inner
dependencies; canonical definition of n-ary conjunction if strict *)
-val match_with_conjunction : ?strict:bool -> (constr * constr list) matching_function
-val is_conjunction : ?strict:bool -> testing_function
+val match_with_conjunction : ?strict:bool -> ?onlybinary:bool -> (constr * constr list) matching_function
+val is_conjunction : ?strict:bool -> ?onlybinary:bool -> testing_function
(** Non recursive tuple, possibly with inner dependencies *)
val match_with_record : (constr * constr list) matching_function
diff --git a/tactics/tauto.ml4 b/tactics/tauto.ml4
index 036c4f0ea8..12bb36eb41 100644
--- a/tactics/tauto.ml4
+++ b/tactics/tauto.ml4
@@ -28,22 +28,30 @@ let assoc_var s ist =
(** Parametrization of tauto *)
+type tauto_flags = {
+
(* Whether conjunction and disjunction are restricted to binary connectives *)
-(* (this is the compatibility mode) *)
-let binary_mode = true
+ binary_mode : bool;
+
+(* Whether compatibility for buggy detection of binary connective is on *)
+ binary_mode_bugged_detection : bool;
(* Whether conjunction and disjunction are restricted to the connectives *)
(* having the structure of "and" and "or" (up to the choice of sorts) in *)
-(* contravariant position in an hypothesis (this is the compatibility mode) *)
-let strict_in_contravariant_hyp = true
+(* contravariant position in an hypothesis *)
+ strict_in_contravariant_hyp : bool;
(* Whether conjunction and disjunction are restricted to the connectives *)
(* having the structure of "and" and "or" (up to the choice of sorts) in *)
(* an hypothesis and in the conclusion *)
-let strict_in_hyp_and_ccl = false
+ strict_in_hyp_and_ccl : bool;
(* Whether unit type includes equality types *)
-let strict_unit = false
+ strict_unit : bool;
+
+(* Whether inner unfolding is allowed *)
+ inner_unfolding : bool
+}
(* Whether inner iff are unfolded *)
let iff_unfolding = ref false
@@ -70,8 +78,8 @@ let is_empty ist =
(* Strictly speaking, this exceeds the propositional fragment as it
matches also equality types (and solves them if a reflexivity) *)
-let is_unit_or_eq ist =
- let test = if strict_unit then is_unit_type else is_unit_or_eq_type in
+let is_unit_or_eq flags ist =
+ let test = if flags.strict_unit then is_unit_type else is_unit_or_eq_type in
if test (assoc_var "X1" ist) then
<:tactic<idtac>>
else
@@ -85,13 +93,13 @@ let is_record t =
mib.Declarations.mind_record
| _ -> false
-let is_binary t =
+let bugged_is_binary t =
isApp t &&
let (hdapp,args) = decompose_app t in
match (kind_of_term hdapp) with
| Ind ind ->
let (mib,mip) = Global.lookup_inductive ind in
- mib.Declarations.mind_nparams = 2
+ mib.Declarations.mind_nparams = 2
| _ -> false
let iter_tac tacl =
@@ -99,70 +107,72 @@ let iter_tac tacl =
(** Dealing with conjunction *)
-let is_conj ist =
+let is_conj flags ist =
let ind = assoc_var "X1" ist in
- if (not binary_mode || is_binary ind) (* && not (is_record ind) *)
- && is_conjunction ~strict:strict_in_hyp_and_ccl ind
+ if (not flags.binary_mode_bugged_detection || bugged_is_binary ind) &&
+ is_conjunction
+ ~strict:flags.strict_in_hyp_and_ccl
+ ~onlybinary:flags.binary_mode ind
then
<:tactic<idtac>>
else
<:tactic<fail>>
-let flatten_contravariant_conj ist =
+let flatten_contravariant_conj flags ist =
let typ = assoc_var "X1" ist in
let c = assoc_var "X2" ist in
let hyp = assoc_var "id" ist in
- match match_with_conjunction ~strict:strict_in_contravariant_hyp typ with
+ match match_with_conjunction
+ ~strict:flags.strict_in_contravariant_hyp
+ ~onlybinary:flags.binary_mode typ
+ with
| Some (_,args) ->
- let i = List.length args in
- if not binary_mode || i = 2 then
- let newtyp = valueIn (VConstr ([],List.fold_right mkArrow args c)) in
- let hyp = valueIn (VConstr ([],hyp)) in
- let intros =
- iter_tac (List.map (fun _ -> <:tactic< intro >>) args)
- <:tactic< idtac >> in
- <:tactic<
- let newtyp := $newtyp in
- let hyp := $hyp in
- assert newtyp by ($intros; apply hyp; split; assumption);
- clear hyp
- >>
- else
- <:tactic<fail>>
+ let newtyp = valueIn (VConstr ([],List.fold_right mkArrow args c)) in
+ let hyp = valueIn (VConstr ([],hyp)) in
+ let intros =
+ iter_tac (List.map (fun _ -> <:tactic< intro >>) args)
+ <:tactic< idtac >> in
+ <:tactic<
+ let newtyp := $newtyp in
+ let hyp := $hyp in
+ assert newtyp by ($intros; apply hyp; split; assumption);
+ clear hyp
+ >>
| _ ->
<:tactic<fail>>
(** Dealing with disjunction *)
-let is_disj ist =
+let is_disj flags ist =
let t = assoc_var "X1" ist in
- if (not binary_mode || is_binary t) &&
- is_disjunction ~strict:strict_in_hyp_and_ccl t
+ if (not flags.binary_mode_bugged_detection || bugged_is_binary t) &&
+ is_disjunction
+ ~strict:flags.strict_in_hyp_and_ccl
+ ~onlybinary:flags.binary_mode t
then
<:tactic<idtac>>
else
<:tactic<fail>>
-let flatten_contravariant_disj ist =
+let flatten_contravariant_disj flags ist =
let typ = assoc_var "X1" ist in
let c = assoc_var "X2" ist in
let hyp = assoc_var "id" ist in
- match match_with_disjunction ~strict:strict_in_contravariant_hyp typ with
+ match match_with_disjunction
+ ~strict:flags.strict_in_contravariant_hyp
+ ~onlybinary:flags.binary_mode
+ typ with
| Some (_,args) ->
- let i = List.length args in
- if not binary_mode || i = 2 then
- let hyp = valueIn (VConstr ([],hyp)) in
- iter_tac (list_map_i (fun i arg ->
- let typ = valueIn (VConstr ([],mkArrow arg c)) in
- let i = Tacexpr.Integer i in
- <:tactic<
- let typ := $typ in
- let hyp := $hyp in
- let i := $i in
- assert typ by (intro; apply hyp; constructor i; assumption)
- >>) 1 args) <:tactic< let hyp := $hyp in clear hyp >>
- else
- <:tactic<fail>>
+ let hyp = valueIn (VConstr ([],hyp)) in
+ iter_tac (list_map_i (fun i arg ->
+ let typ = valueIn (VConstr ([],mkArrow arg c)) in
+ let i = Tacexpr.Integer i in
+ <:tactic<
+ let typ := $typ in
+ let hyp := $hyp in
+ let i := $i in
+ assert typ by (intro; apply hyp; constructor i; assumption)
+ >>) 1 args) <:tactic< let hyp := $hyp in clear hyp >>
| _ ->
<:tactic<fail>>
@@ -173,13 +183,11 @@ let not_dep_intros ist =
<:tactic<
repeat match goal with
| |- (forall (_: ?X1), ?X2) => intro
- | |- (Coq.Init.Logic.not _) => unfold Coq.Init.Logic.not at 1
- | H:(Coq.Init.Logic.not _)|-_ => unfold Coq.Init.Logic.not at 1 in H
- | H:forall (_: Coq.Init.Logic.not _), _|-_ => unfold Coq.Init.Logic.not at 1 in H
+ | |- (Coq.Init.Logic.not _) => unfold Coq.Init.Logic.not at 1; intro
end >>
-let axioms ist =
- let t_is_unit_or_eq = tacticIn is_unit_or_eq
+let axioms flags ist =
+ let t_is_unit_or_eq = tacticIn (is_unit_or_eq flags)
and t_is_empty = tacticIn is_empty in
<:tactic<
match reverse goal with
@@ -189,12 +197,12 @@ let axioms ist =
end >>
-let simplif ist =
- let t_is_unit_or_eq = tacticIn is_unit_or_eq
- and t_is_conj = tacticIn is_conj
- and t_flatten_contravariant_conj = tacticIn flatten_contravariant_conj
- and t_flatten_contravariant_disj = tacticIn flatten_contravariant_disj
- and t_is_disj = tacticIn is_disj
+let simplif flags ist =
+ let t_is_unit_or_eq = tacticIn (is_unit_or_eq flags)
+ and t_is_conj = tacticIn (is_conj flags)
+ and t_flatten_contravariant_conj = tacticIn (flatten_contravariant_conj flags)
+ and t_flatten_contravariant_disj = tacticIn (flatten_contravariant_disj flags)
+ and t_is_disj = tacticIn (is_disj flags)
and t_not_dep_intros = tacticIn not_dep_intros in
<:tactic<
$t_not_dep_intros;
@@ -231,11 +239,11 @@ let simplif ist =
end;
$t_not_dep_intros) >>
-let rec tauto_intuit t_reduce solver ist =
- let t_axioms = tacticIn axioms
- and t_simplif = tacticIn simplif
- and t_is_disj = tacticIn is_disj
- and t_tauto_intuit = tacticIn (tauto_intuit t_reduce solver) in
+let rec tauto_intuit flags t_reduce solver ist =
+ let t_axioms = tacticIn (axioms flags)
+ and t_simplif = tacticIn (simplif flags)
+ and t_is_disj = tacticIn (is_disj flags)
+ and t_tauto_intuit = tacticIn (tauto_intuit flags t_reduce solver) in
let t_solver = globTacticIn (fun _ist -> solver) in
<:tactic<
($t_simplif;$t_axioms
@@ -247,6 +255,10 @@ let rec tauto_intuit t_reduce solver ist =
[ exact id
| generalize (fun y:X2 => id (fun x:X1 => y)); intro; clear id;
solve [ $t_tauto_intuit ]]]
+ | id:forall (_:not ?X1), ?X3|- _ =>
+ cut X3;
+ [ intro; clear id; $t_tauto_intuit
+ | cut (not X1); [ exact id | clear id; intro; solve [$t_tauto_intuit ]]]
| |- ?X1 =>
$t_is_disj; solve [left;$t_tauto_intuit | right;$t_tauto_intuit]
end
@@ -267,11 +279,13 @@ let reduction_not _ist =
let t_reduction_not = tacticIn reduction_not
-let intuition_gen tac =
- interp (tacticIn (tauto_intuit t_reduction_not tac))
+let intuition_gen flags tac =
+ let t_reduce =
+ if flags.inner_unfolding then t_reduction_not else <:tactic<idtac>> in
+ interp (tacticIn (tauto_intuit flags t_reduce tac))
-let tauto_intuitionistic g =
- try intuition_gen <:tactic<fail>> g
+let tauto_intuitionistic flags g =
+ try intuition_gen flags <:tactic<fail>> g
with
Refiner.FailError _ | UserError _ ->
errorlabstrm "tauto" (str "tauto failed.")
@@ -280,26 +294,69 @@ let coq_nnpp_path =
let dir = List.map id_of_string ["Classical_Prop";"Logic";"Coq"] in
Libnames.make_path (make_dirpath dir) (id_of_string "NNPP")
-let tauto_classical nnpp g =
- try tclTHEN (apply nnpp) tauto_intuitionistic g
+let tauto_classical flags nnpp g =
+ try tclTHEN (apply nnpp) (tauto_intuitionistic flags) g
with UserError _ -> errorlabstrm "tauto" (str "Classical tauto failed.")
-let tauto g =
+let tauto_gen flags g =
try
let nnpp = constr_of_global (Nametab.global_of_path coq_nnpp_path) in
(* try intuitionistic version first to avoid an axiom if possible *)
- tclORELSE tauto_intuitionistic (tauto_classical nnpp) g
+ tclORELSE (tauto_intuitionistic flags) (tauto_classical flags nnpp) g
with Not_found ->
- tauto_intuitionistic g
-
+ tauto_intuitionistic flags g
let default_intuition_tac = <:tactic< auto with * >>
+(* This is the uniform mode dealing with ->, not, iff and types isomorphic to
+ /\ and *, \/ and +, False and Empty_set, True and unit, _and_ eq-like types;
+ not and iff are unfolded only if necessary *)
+let tauto_uniform_unit_flags = {
+ binary_mode = true;
+ binary_mode_bugged_detection = false;
+ strict_in_contravariant_hyp = true;
+ strict_in_hyp_and_ccl = true;
+ strict_unit = false;
+ inner_unfolding = false
+}
+
+(* This is the compatibility mode (not used) *)
+let tauto_legacy_flags = {
+ binary_mode = true;
+ binary_mode_bugged_detection = true;
+ strict_in_contravariant_hyp = true;
+ strict_in_hyp_and_ccl = false;
+ strict_unit = false;
+ inner_unfolding = true
+}
+
+(* This is the improved mode *)
+let tauto_power_flags = {
+ binary_mode = false; (* support n-ary connectives *)
+ binary_mode_bugged_detection = false;
+ strict_in_contravariant_hyp = false; (* supports non-regular connectives *)
+ strict_in_hyp_and_ccl = false;
+ strict_unit = false;
+ inner_unfolding = false
+}
+
+let tauto = tauto_gen tauto_uniform_unit_flags
+let dtauto = tauto_gen tauto_power_flags
+
TACTIC EXTEND tauto
| [ "tauto" ] -> [ tauto ]
END
+TACTIC EXTEND dtauto
+| [ "dtauto" ] -> [ dtauto ]
+END
+
TACTIC EXTEND intuition
-| [ "intuition" ] -> [ intuition_gen default_intuition_tac ]
-| [ "intuition" tactic(t) ] -> [ intuition_gen t ]
+| [ "intuition" ] -> [ intuition_gen tauto_uniform_unit_flags default_intuition_tac ]
+| [ "intuition" tactic(t) ] -> [ intuition_gen tauto_uniform_unit_flags t ]
+END
+
+TACTIC EXTEND dintuition
+| [ "dintuition" ] -> [ intuition_gen tauto_power_flags default_intuition_tac ]
+| [ "dintuition" tactic(t) ] -> [ intuition_gen tauto_power_flags t ]
END