消除Coq中案例分析产生的冗余子目标

消除Coq中案例分析产生的冗余子目标,coq,Coq,用一个简单的定义 Inductive B := bb. Inductive C := cc. Inductive A := | mkA1 : B -> A | mkA2 : C -> A. Definition id (a: A) : A := match a with | mkA1 b => mkA1 b | mkA2 c => mkA2 c end. 我尝试通过案例分析(析构函数)进行证明,比如: Theorem Foo : forall

用一个简单的定义

Inductive B := bb.
Inductive C := cc.

Inductive A :=
 | mkA1 : B -> A
 | mkA2 : C -> A.

Definition id (a: A) : A :=
 match a with 
  | mkA1 b => mkA1 b 
  | mkA2 c => mkA2 c
end.
我尝试通过案例分析(析构函数)进行证明,比如:

Theorem Foo :
  forall  a1 a2 : A , a1 <> a2 -> id a1 <> id a2.
Proof.
 destruct a1; destruct a2.
 Abort.

虽然我仍然没有办法要求Coq删除重复项。现在我可以证明第二个子目标的引理,并在第三个子目标中重用它。但我想知道一些替代方案。

这里有一些消除重复子目标的战术自动化。请注意,不仅目标必须完全匹配,而且上下文的顺序也必须匹配。在进行案例分析之前,还需要运行初始化策略。这是Coq>=8.5的代码

Inductive B := bb.
Inductive C := cc.

Inductive A :=
| mkA1 : B -> A
| mkA2 : C -> A.

Definition id (a: A) : A :=
  match a with
  | mkA1 b => mkA1 b
  | mkA2 c => mkA2 c
  end.

Record duplicate_prod (A B : Type) := duplicate_conj { duplicate_fst : A ; duplicate_snd : B }.
Definition HERE := True.

Ltac start_remove_duplicates H :=
  simple refine (let H___duplicates := @duplicate_conj _ _ I _ in _);
  [ shelve | | ]; cycle 1.
Ltac find_dup H G :=
  lazymatch type of H with
  | duplicate_prod G _ => constr:(@duplicate_fst _ _ H)
  | duplicate_prod _ _ => find_dup (@duplicate_snd _ _ H) G
  end.
Ltac find_end H :=
  lazymatch type of H with
  | duplicate_prod _ _ => find_end (@duplicate_snd _ _ H)
  | _ => H
  end.
Ltac revert_until H :=
  repeat lazymatch goal with
         | [ H' : _ |- _ ]
           => first [ constr_eq H H'; fail 1
                    | revert H' ]
         end.
Ltac remove_duplicates :=
  [ > lazymatch goal with
      | [ |- duplicate_prod _ _ ] => idtac
      | [ H : duplicate_prod _ _ |- _ ]
        => generalize (I : HERE);
           revert_until H;
           let G := match goal with |- ?G => G end in
           lazymatch type of H with
           | context[duplicate_prod G]
             => let lem := find_dup H G in exact lem
           | _ => let lem := find_end H in
                  refine (@duplicate_fst _ _ lem); clear H; (* clear to work around a bug in Coq *)
                  shelve
           end
      end.. ].
Ltac finish_duplicates :=
  [ > lazymatch goal with
      | [ H : duplicate_prod _ _ |- _ ] => clear H
      end..
  | repeat match goal with
           | [ |- duplicate_prod _ ?e ]
             => split;
                [ repeat lazymatch goal with
                         | [ |- HERE -> _ ] => fail
                         | _ => intro
                         end;
                  intros _
                | try (is_evar e; exact I) ]
           end ].


Theorem Foo :
  forall  a1 a2 : A , a1 <> a2 -> id a1 <> id a2.
Proof.
  start_remove_duplicates.
  destruct a1; destruct a2.
  2:intro; apply not_eq_sym in H; apply not_eq_sym; revert c b H; intros c b.
  all:remove_duplicates.
  all:finish_duplicates.
归纳B:=bb。
归纳C:=cc。
感应式A:=
|mkA1:B->A
|mkA2:C->A。
定义id(a:a):a:=
匹配
|mkA1 b=>mkA1 b
|mkA2 c=>mkA2 c
结束。
记录重复生产(ab:Type):=duplicate\u conj{duplicate\u fst:A;duplicate\u snd:B}。
此处的定义:=True。
Ltac启动\u删除\u重复项H:=
简单细化(设H_uuu重复:=@duplicate_uconj_uui_uuin);
[搁置| |];周期1。
Ltac find_dup H G:=
H的lazymatch型
|复制产品G=>constr:(@duplicate\u fst\uh)
|duplicate\u prod\uu=>find\u dup(@duplicate\u snd\uh)G
结束。
Ltac find_end H:=
H的lazymatch型
|重复生产=>查找结束(@duplicate\u snd\uh)
|_uz=>H
结束。
Ltac在H:=
用鼠标重复lazymatch目标
|[H':|-|]
=>第一个[constr_eq H';失败1
|回复H']
结束。
Ltac删除重复项:=
[>lazymatch的进球
|[|-复制产品]=>idtac
|[H:复制产品u124; 124;-124;]
=>概括(I:这里);
恢复到H;
设G:=将目标与|-?G=>G结尾匹配
H的lazymatch型
|上下文[重复产品]
=>让lem:=在精确的lem中找到_duph G
|_u=>让lem:=在
细化(@duplicate\u fst\uulem);清除H;(*清除以解决Coq*中的错误)
搁置
结束
完..]。
Ltac饰面\u副本:=
[>lazymatch的进球
|[H:重复生产124;-124;]=>清除H
结束。。
|与对手重复比赛进球
|[|-重复生产]
=>分裂;
[重复lazymatch的目标,并
|[|-此处->\]=>失败
|_uz=>简介
结束;
介绍_
|试一试(准确无误)]
"完"。
定理Foo:
对于所有a1 a2:A,a1 a2->id a1 id a2。
证明。
开始删除重复项。
破坏a1;破坏a2。
2:介绍;在H中应用not_eq_sym;应用非均衡符号;还原c b H;简介c.b。
全部:删除重复项。
全部:完成所有副本。

这个想法是,您首先创建一个evar,它将保存针对特定目标的解决方案。然后进行案例分析。然后,你去完成目标,或者用评估报告中的一个新的投影来解决它们,或者,如果你看到你正在寻找的目标已经有了一个解决方案,你就使用这个解决方案。最后,将evar分解为多个(消除重复)目标。还有一些附加的样板文件,用于还原创建evar时不存在的假设(为了安抚类型良好的术语的变量范围),记住哪些内容最初来自上下文,并在最后将这些内容重新引入上下文。

,你的例子有点棘手,因为目标确实是不可证明的,在这种情况下,除了将你分解为一个中间引理之外,没有什么可以做的了。然而,在实际用例中,人们倾向于通过使用受控数量的自动化来消除这些冗余步骤。如果你发布一个具体的例子,我们可以试着看一看。@ejgallego谢谢。你能具体说明一下这些多余的步骤吗?你的意思是引理的提取是多余的步骤吗?还是生成冗余子目标的步骤?或者两者都有?还是别的什么?我同意像
abstract
这样的自动化策略可以帮助解决第一种情况,但如果你是说,通过一些验证工程,我们甚至不需要在一开始就生成多余的子目标,那就更好了!事实上,我的意思是,通常这些“多余”的子目标最好在它们产生后立即消除。@ejgallego在不显著改变问题的情况下,我对其进行了更新,使其变得微不足道。你认为我们可以在它上面应用一些控制量的自动化吗?或者你能告诉我在哪里可以得到更多关于自动化技术的信息吗?那么我会相应地更新问题吗?谢谢。一个典型的更有趣的例子是,当证明目标时,例如
对于所有x y,x=y->x==y
,在这些情况下,您通常会调用
一致性
,以清除假设为
A=B
等的目标。。。在其他方面是对称的。
Focus 2; 
intro; apply not_eq_sym in H; apply not_eq_sym; revert H;
Unfocus.
Inductive B := bb.
Inductive C := cc.

Inductive A :=
| mkA1 : B -> A
| mkA2 : C -> A.

Definition id (a: A) : A :=
  match a with
  | mkA1 b => mkA1 b
  | mkA2 c => mkA2 c
  end.

Record duplicate_prod (A B : Type) := duplicate_conj { duplicate_fst : A ; duplicate_snd : B }.
Definition HERE := True.

Ltac start_remove_duplicates H :=
  simple refine (let H___duplicates := @duplicate_conj _ _ I _ in _);
  [ shelve | | ]; cycle 1.
Ltac find_dup H G :=
  lazymatch type of H with
  | duplicate_prod G _ => constr:(@duplicate_fst _ _ H)
  | duplicate_prod _ _ => find_dup (@duplicate_snd _ _ H) G
  end.
Ltac find_end H :=
  lazymatch type of H with
  | duplicate_prod _ _ => find_end (@duplicate_snd _ _ H)
  | _ => H
  end.
Ltac revert_until H :=
  repeat lazymatch goal with
         | [ H' : _ |- _ ]
           => first [ constr_eq H H'; fail 1
                    | revert H' ]
         end.
Ltac remove_duplicates :=
  [ > lazymatch goal with
      | [ |- duplicate_prod _ _ ] => idtac
      | [ H : duplicate_prod _ _ |- _ ]
        => generalize (I : HERE);
           revert_until H;
           let G := match goal with |- ?G => G end in
           lazymatch type of H with
           | context[duplicate_prod G]
             => let lem := find_dup H G in exact lem
           | _ => let lem := find_end H in
                  refine (@duplicate_fst _ _ lem); clear H; (* clear to work around a bug in Coq *)
                  shelve
           end
      end.. ].
Ltac finish_duplicates :=
  [ > lazymatch goal with
      | [ H : duplicate_prod _ _ |- _ ] => clear H
      end..
  | repeat match goal with
           | [ |- duplicate_prod _ ?e ]
             => split;
                [ repeat lazymatch goal with
                         | [ |- HERE -> _ ] => fail
                         | _ => intro
                         end;
                  intros _
                | try (is_evar e; exact I) ]
           end ].


Theorem Foo :
  forall  a1 a2 : A , a1 <> a2 -> id a1 <> id a2.
Proof.
  start_remove_duplicates.
  destruct a1; destruct a2.
  2:intro; apply not_eq_sym in H; apply not_eq_sym; revert c b H; intros c b.
  all:remove_duplicates.
  all:finish_duplicates.