Coq 证明偶数+;偶数=偶数,使用策略相互感应

Coq 证明偶数+;偶数=偶数,使用策略相互感应,coq,Coq,我在Coq中尝试了相互感应,我定义的第一种类型是 Inductive IsEven : nat -> Prop := | EvenO : IsEven O | EvenS n : IsOdd n -> IsEven (S n) with IsOdd : nat -> Prop := | OddS n : IsEven n -> IsOdd (S n). 我现在想证明偶数之和是偶数。我可以通过定点和模式匹配来实现这一点: Fixpoint even_plus_

我在Coq中尝试了相互感应,我定义的第一种类型是

Inductive IsEven : nat -> Prop :=
  | EvenO : IsEven O
  | EvenS n : IsOdd n -> IsEven (S n)
with IsOdd : nat -> Prop :=
  | OddS n : IsEven n -> IsOdd (S n).
我现在想证明偶数之和是偶数。我可以通过定点和模式匹配来实现这一点:

Fixpoint even_plus_even (n m : nat) (evenn : IsEven n) (evenm : IsEven m) : IsEven (n + m) :=
match evenn with
  | EvenO => evenm
  | EvenS n' oddn' => EvenS (n' + m) (odd_plus_even n' m oddn' evenm)
end
with odd_plus_even (n m : nat) (oddn : IsOdd n) (evenm : IsEven m) : IsOdd (n + m) :=
match oddn with
  | OddS n' evenn' => OddS (n' + m) (even_plus_even n' m evenn' evenm)
end.
这定义了
偶数加偶数
奇数加偶数
。我现在想用一种更简洁的方法来证明这一点(最好不要使用许多预定义的引理来尽可能地保持代码的自包含性),但我还没走多远

具体地说,是否可以像我们在不动点上所能使用的那样,只用一个引理来证明
偶数加偶数
奇数加偶数

编辑:非常感谢您的回答,
引理。。。使用…
语法正是我想要的。其实

Lemma even_plus_even2 (n m : nat) (evenn : IsEven n) (evenm : IsEven m) : IsEven (n + m)
  with odd_plus_even2 (n m : nat) (oddn : IsOdd n)   (evenm : IsEven m) : IsOdd  (n + m).
Proof.
  induction evenn; simpl. assumption. constructor. auto.
  induction oddn;  simpl.             constructor. auto.
Defined.

生成与我原始问题中的
不动点
完全相同的证明项。

Coq中支持相互感应。我知道两种方法,但我只记得如何使用其中一种:

  • 组合方案
  • 以下是它的工作原理:

    Scheme IsEven_ind2 := Induction for IsEven Sort Prop
      with IsOdd_ind2  := Induction for IsOdd Sort Prop.
    
    Combined Scheme IsEvenOdd_ind from IsEven_ind2, IsOdd_ind2. 
    
    Lemma foo: (forall (n: nat) (evenn: IsEven n), forall m (evenm: IsEven m), IsEven (n + m) ) /\
               (forall (n: nat) (oddn: IsOdd n), forall m (evenm: IsEven m), IsOdd (n + m)).
    Proof.
    apply IsEvenOdd_ind.
    - now intros m hm.
    - intros h hn hi m hm.
      rewrite plus_Sn_m.
      apply EvenS.
      now apply hi.
    - intros h hn hi m hm.
      rewrite plus_Sn_m.
      apply OddS.
      now apply hi.
    Qed.
    
  • 引理
  • 在这个问题上,我只是不知道如何完成它,但这是一个语法问题iirc:

    Lemma foo: forall (n m: nat) (evenn: IsEven n) (evenm: IsEven m), IsEven (n + m)
    with bar:  forall (n m: nat) (oddn: IsOdd n) (evenm: IsEven m), IsOdd (n + m).
    Proof.
    - intros n m hn; revert m; induction hn as [ | p hp]; intros m hm; simpl in *.
      + exact hm.
      + now apply EvenS; apply bar.
    - intros n m hn hm; revert n hn; induction hm as [ | p hp]; intros n hn; simpl in *.
      + now apply bar; [ exact hn | apply EvenO ].
      + apply bar; [ exact hn | ].
        now apply EvenS.
    (* can't Qed, I get a Error: Cannot guess decreasing argument of fix. *)
    Qed.
    
    编辑: 下面是带有解决方案的
    引理的有效语法

    Lemma foo (n: nat) (evenn: IsEven n): forall (m: nat) (evenm: IsEven m), IsEven (n + m)
     with bar (n: nat) (oddn:  IsOdd  n): forall (m: nat) (evenm: IsEven m), IsOdd  (n + m).
    Proof.
    - induction evenn as [ | p hp]; intros m hm; simpl in *.
      + exact hm.
      + now apply EvenS; apply bar.
    - induction oddn as [p hp]; intros n hn; simpl in *.
      + apply OddS.
        now apply foo.
    Qed.
    

    在Coq中有相互感应的支持。我知道两种方法,但我只记得如何使用其中一种:

  • 组合方案
  • 以下是它的工作原理:

    Scheme IsEven_ind2 := Induction for IsEven Sort Prop
      with IsOdd_ind2  := Induction for IsOdd Sort Prop.
    
    Combined Scheme IsEvenOdd_ind from IsEven_ind2, IsOdd_ind2. 
    
    Lemma foo: (forall (n: nat) (evenn: IsEven n), forall m (evenm: IsEven m), IsEven (n + m) ) /\
               (forall (n: nat) (oddn: IsOdd n), forall m (evenm: IsEven m), IsOdd (n + m)).
    Proof.
    apply IsEvenOdd_ind.
    - now intros m hm.
    - intros h hn hi m hm.
      rewrite plus_Sn_m.
      apply EvenS.
      now apply hi.
    - intros h hn hi m hm.
      rewrite plus_Sn_m.
      apply OddS.
      now apply hi.
    Qed.
    
  • 引理
  • 在这个问题上,我只是不知道如何完成它,但这是一个语法问题iirc:

    Lemma foo: forall (n m: nat) (evenn: IsEven n) (evenm: IsEven m), IsEven (n + m)
    with bar:  forall (n m: nat) (oddn: IsOdd n) (evenm: IsEven m), IsOdd (n + m).
    Proof.
    - intros n m hn; revert m; induction hn as [ | p hp]; intros m hm; simpl in *.
      + exact hm.
      + now apply EvenS; apply bar.
    - intros n m hn hm; revert n hn; induction hm as [ | p hp]; intros n hn; simpl in *.
      + now apply bar; [ exact hn | apply EvenO ].
      + apply bar; [ exact hn | ].
        now apply EvenS.
    (* can't Qed, I get a Error: Cannot guess decreasing argument of fix. *)
    Qed.
    
    编辑: 下面是带有
    解决方案的
    引理的有效语法

    Lemma foo (n: nat) (evenn: IsEven n): forall (m: nat) (evenm: IsEven m), IsEven (n + m)
     with bar (n: nat) (oddn:  IsOdd  n): forall (m: nat) (evenm: IsEven m), IsOdd  (n + m).
    Proof.
    - induction evenn as [ | p hp]; intros m hm; simpl in *.
      + exact hm.
      + now apply EvenS; apply bar.
    - induction oddn as [p hp]; intros n hn; simpl in *.
      + apply OddS.
        now apply foo.
    Qed.
    

    例如,您可以通过将两个引理“并”成一个引理来同时证明这两个引理,然后使用
    proj1
    proj2
    提取子句的左或右部分

    Lemma even_or_odd_plus_even:  forall (n m : nat),
        (forall (evenn : IsEven n) (evenm : IsEven m), IsEven (n + m)) /\
        (forall (oddn : IsOdd n) (evenm : IsEven m), IsOdd (n + m)).
    Proof.
      induction n; split; intros;
        try destruct (IHn m) as [He Ho];
        try apply evenm;
        try inversion oddn;
        try inversion evenn;
        constructor; auto.
    Qed.
    
    Definition even_plus_even n m := proj1 (even_or_odd_plus_even n m).
    Definition odd_plus_even n m := proj2 (even_or_odd_plus_even n m).
    
    给你

    even_plus_even : forall n m : nat, IsEven n -> IsEven m -> IsEven (n + m)
    odd_plus_even  : forall n m : nat, IsOdd n -> IsEven m -> IsOdd (n + m)
    
    请注意,这两个子句共享
    n
    m
    ,如果无法单独证明这两个子句,则需要使用这两个子句,因为它们需要相互依赖。(但在这种情况下,他们没有。你可以单独证明这些陈述,正如安东所示。)

    编辑:刚刚看到了Vinz解决方案。我不知道引理有
    语法(谢谢展示!),但这是有意义的,我认为这是一种更简洁的方法来定义这个相互依赖的定义

    Lemma even_plus_even: forall n m, IsEven n -> IsEven m -> IsEven (n+m)
     with odd_plus_even: forall n m, IsOdd n -> IsEven m -> IsOdd (n+m).
    Proof.
      induction 1; simpl; auto using EvenS.
      induction 1; simpl; auto using OddS.
    Qed.
    

    例如,您可以通过将两个引理“并”成一个引理来同时证明这两个引理,然后使用
    proj1
    proj2
    提取子句的左或右部分

    Lemma even_or_odd_plus_even:  forall (n m : nat),
        (forall (evenn : IsEven n) (evenm : IsEven m), IsEven (n + m)) /\
        (forall (oddn : IsOdd n) (evenm : IsEven m), IsOdd (n + m)).
    Proof.
      induction n; split; intros;
        try destruct (IHn m) as [He Ho];
        try apply evenm;
        try inversion oddn;
        try inversion evenn;
        constructor; auto.
    Qed.
    
    Definition even_plus_even n m := proj1 (even_or_odd_plus_even n m).
    Definition odd_plus_even n m := proj2 (even_or_odd_plus_even n m).
    
    给你

    even_plus_even : forall n m : nat, IsEven n -> IsEven m -> IsEven (n + m)
    odd_plus_even  : forall n m : nat, IsOdd n -> IsEven m -> IsOdd (n + m)
    
    请注意,这两个子句共享
    n
    m
    ,如果无法单独证明这两个子句,则需要使用这两个子句,因为它们需要相互依赖。(但在这种情况下,他们没有。你可以单独证明这些陈述,正如安东所示。)

    编辑:刚刚看到了Vinz解决方案。我不知道引理有
    语法(谢谢展示!),但这是有意义的,我认为这是一种更简洁的方法来定义这个相互依赖的定义

    Lemma even_plus_even: forall n m, IsEven n -> IsEven m -> IsEven (n+m)
     with odd_plus_even: forall n m, IsOdd n -> IsEven m -> IsOdd (n+m).
    Proof.
      induction 1; simpl; auto using EvenS.
      induction 1; simpl; auto using OddS.
    Qed.
    

    TTBOMK您将不得不使用一种棘手的
    修复
    策略,因此您的生活不会更好。我的观点是,你使用了错误的Coq工具来解决你的问题。归纳定义是非常强大的理论工具,而
    奇数
    /
    偶数
    是简单的函数,更好地定义为函数
    nat->bool
    ,偶数只定义为
    偶数n=~奇数n
    ,就像在数学竞赛中所做的那样,所以你的生活不会好很多。我的观点是,你使用了错误的Coq工具来解决你的问题。归纳定义是非常强大的理论工具,
    奇数
    /
    偶数
    是简单的函数,可以更好地定义为函数
    nat->bool
    ,偶数只定义为
    偶数n=~奇数n
    ,例如在数学竞赛中,
    引理
    不动点
    都只是
    定理
    的别名,请参见,这意味着您也可以使用证明策略定义不动点定义,而无需预先给出明确的证明项。顺便说一句,
    refine
    策略非常有用,如果你想明确给出部分证明项,同时留下漏洞来用策略来填补。实际上,
    引理和
    不动点
    都只是
    定理
    的别名,请参见,这意味着你也可以用证明策略来定义不动点定义,没有预先给出明确的证明项。顺便说一句,如果您想明确给出部分证明术语,同时留下漏洞以用策略来填补,那么
    refine
    策略非常有用。