Coq 复杂对象不等式的证明

Coq 复杂对象不等式的证明,coq,coq-tactic,Coq,Coq Tactic,我有一对完全不兼容的地图。我想知道什么是优雅的/自动化的方式来获得它的证明 Require Import Coq.Strings.String. (* Prelude: the total_map data structure from Software Foundations, slightly modified *) Definition total_map := string -> nat. Definition empty_st : total_map := (fun _ =&g

我有一对完全不兼容的地图。我想知道什么是优雅的/自动化的方式来获得它的证明

Require Import Coq.Strings.String.

(* Prelude: the total_map data structure from Software Foundations, slightly modified *)
Definition total_map := string -> nat.
Definition empty_st : total_map := (fun _ => 0).
Definition t_update (m : total_map) k v := fun k' => if string_dec k k' then v else m k'.
Notation "a '!->' x" := (t_update empty_st a x) (at level 100).
Notation "x '!->' v ';' m" := (t_update m x v) (at level 100, v at next level, right associativity).

(* The actual goal I'm trying to solve *)
Definition X: string := "X".
Definition Y: string := "Y".
Goal forall n, (X !-> n; Y !-> n) <> (X !-> 1; Y !-> 2).
Proof.
  intros n contra.
  remember (X !-> n; Y !-> n) as st.
  remember (st X) as n1.
  assert (n1 = n). { rewrite Heqn1; rewrite Heqst; cbv; reflexivity. }
  assert (n1 = 1). { rewrite Heqn1; rewrite contra; cbv; reflexivity. }
  remember (st Y) as n2.
  assert (n2 = n). { rewrite Heqn2; rewrite Heqst; cbv; reflexivity. }
  assert (n2 = 2). { rewrite Heqn2; rewrite contra; cbv; reflexivity. }
  congruence.
Qed.
需要导入Coq.Strings.String。
(*前奏曲:软件基础的总地图数据结构,稍作修改*)
定义总映射:=字符串->nat。
定义为空:总映射:=(乐趣=>0)。
定义t_更新(m:total_map)k v:=fun k'=>如果字符串为'u dec k'那么v else m k'。
符号“a”!->“x”:=(t\U更新为空\U st a x)(在级别100)。
符号“x”!->“v”;“m”:=(t_更新m x v)(在100级,v在下一级,右关联性)。
(*我试图解决的实际目标*)
定义X:string:=“X”。
定义Y:字符串:=“Y”。
所有n的目标,(X!->n;Y!->n)(X!->1;Y!->2)。
证明。
反面介绍。
记住(X!->n;Y!->n)是st。
记住(stx)是n1。
断言(n1=n)。{重写Heqn1;重写Heqst;cbv;自反性。}
断言(n1=1)。{重写Heqn1;重写contra;cbv;自反性。}
记住(sty)是n2。
断言(n2=n)。{重写Heqn2;重写Heqst;cbv;自反性。}
断言(n2=2)。{重写Heqn2;重写contra;cbv;自反性。}
相似
Qed。

为了实现自动化,您需要准确描述您的验证策略。以下是一种可能的证明策略:

要证明
total\u map
s的不等式:

  • 首先介绍平等假设
  • 然后,对于添加到任一映射的每个键,添加与该键相关联的值在两个映射中相同的假设
  • 然后,通过展开
    t\u update
    ,使用
    string\u dec x
    为真,并查看是否有任何其他
    string\u dec
    计算下来,简化所有这些等式假设
  • 最后,通过一致性来解决目标
  • 我们可以自动化这些步骤中的每一步。总之,它变成:

    Require Import Coq.Strings.String.
    
    (* Prelude: the total_map data structure from Software Foundations, slightly modified *)
    Definition total_map := string -> nat.
    Definition empty_st : total_map := (fun _ => 0).
    Definition t_update (m : total_map) k v := fun k' => if string_dec k k' then v else m k'.
    Notation "a '!->' x" := (t_update empty_st a x) (at level 100).
    Notation "x '!->' v ';' m" := (t_update m x v) (at level 100, v at next level, right associativity).
    
    (* Automation *)
    
    (* 1. First introduce the equality hypothesis. *)
    Ltac start_proving_inequality H :=
      intro H.
    
    (* 2. Then, for every key that's been added to either map, add the hypothesis that the value associated to that key is the same in both maps. *)
    (* To do this, we need a tactic that will pose a proof only if it does not already exist. *)
    Ltac unique_pose_proof lem :=
      let T := type of lem in
      lazymatch goal with
      | [ H : T |- _ ] => fail 0 "A hypothesis of type" T "already exists"
      | _ => pose proof lem
      end.
    
    (* Maybe move this elsewhere? *)
    Definition t_get (m : total_map) k := m k.
    
    Ltac saturate_with_keys H :=
      repeat match type of H with
             | context[t_update _ ?k ?v]
               => unique_pose_proof (f_equal (fun m => t_get m k) H)
             end.
    
    (* 3. Then simplify all such equality hypotheses by unfolding `t_update`, using that `string_dec x x` is true, and seeing if any other `string_dec`s compute down. *)
    Require Import Coq.Logic.Eqdep_dec.
    Lemma string_dec_refl x : string_dec x x = left eq_refl.
    Proof.
      destruct (string_dec x x); [ apply f_equal | congruence ].
      apply UIP_dec, string_dec.
    Qed.
    
    (* N.B. You can add more cases here to deal with other sorts of ways you might reduce [t_get] here *)
    Ltac simplify_t_get_t_update_in H :=
      repeat first [ progress cbv [t_get t_update empty_st] in H
                   | match type of H with
                     | context[string_dec ?x ?x] => rewrite (string_dec_refl x) in H
                     | context[string_dec ?x ?y]
                       => let v := (eval cbv in (string_dec x y)) in
                          (* check that it fully reduces *)
                          lazymatch v with left _ => idtac | right _ => idtac end;
                          progress change (string_dec x y) with v in H
                     end ].
    
    Ltac simplify_t_get_t_update :=
      (* first we must change hypotheses of the form [(fun m => t_get m k) m = (fun m => t_get m k) m'] into [t_get _ _ = t_get _ _] *)
      cbv beta in *;
      repeat match goal with
             | [ H : t_get _ _ = t_get _ _ |- _ ] => progress simplify_t_get_t_update_in H
             end.
    
    (* 4. Finally, solve the goal by `congruence`. *)
    Ltac finish_proving_inequality := congruence.
    
    (* Now we put it all together *)
    Ltac prove_total_map_inequality :=
      let H := fresh in
      start_proving_inequality H;
      saturate_with_keys H;
      simplify_t_get_t_update;
      finish_proving_inequality.
    
    (* The actual goal I'm trying to solve *)
    Definition X: string := "X".
    Definition Y: string := "Y".
    Goal forall n, (X !-> n; Y !-> n) <> (X !-> 1; Y !-> 2).
      intros.
      prove_total_map_inequality.
    Qed.
    
    需要导入Coq.Strings.String。
    (*前奏曲:软件基础的总地图数据结构,稍作修改*)
    定义总映射:=字符串->nat。
    定义为空:总映射:=(乐趣=>0)。
    定义t_更新(m:total_map)k v:=fun k'=>如果字符串为'u dec k'那么v else m k'。
    符号“a”!->“x”:=(t\U更新为空\U st a x)(在级别100)。
    符号“x”!->“v”;“m”:=(t_更新m x v)(在100级,v在下一级,右关联性)。
    (*自动化*)
    (*1.首先介绍平等假设。*)
    Ltac启动证明不等式H:=
    介绍H。
    (*2.然后,对于添加到任一映射的每个键,添加与该键关联的值在两个映射中相同的假设。*)
    (*要做到这一点,我们需要一种策略,只有在证据不存在的情况下才能提供证据。*)
    Ltac独特的防姿态lem:=
    设T:=中lem的类型
    拉齐马特进球
    |[H:T |-|]=>失败0“类型为“T”的假设已经存在”
    |_uz=>防姿态lem
    结束。
    (*可能会将此移到其他地方?*)
    定义t_get(m:总映射)k:=m k。
    Ltac使用_键H饱和_:=
    重复匹配H的类型
    |上下文[t_更新?k?v]
    =>独特的姿势证明(f_相等(乐趣m=>t_获得m k)H)
    结束。
    (*3.然后通过展开't_update',使用'string_dec x'为真,并查看是否有任何其他'string_dec'的计算结果,简化所有此类等式假设。*)
    需要导入Coq.Logic.Eqdep\u dec。
    引理string\u dec\u refl x:string\u dec x x=左等式\u refl。
    证明。
    自毁(字符串_dec x x);[应用f|u相等|同余]。
    应用UIP_dec、字符串_dec。
    Qed。
    (*N.B.您可以在此处添加更多案例,以处理您可能会减少的其他类型的方法*)
    Ltac在H中简化\u t\u获取\u t\u更新\u:=
    在H中首先重复[progress cbv[t_get t_update empty_st]
    |将H的类型与
    |上下文[string_dec?x?x]=>在H中重写(string_dec_refl x)
    |上下文[string_dec?x?y]
    =>设v:=(计算cbv in(字符串x y))in
    (*检查是否完全减少*)
    lazymatch v带左=>idtac |右=>idtac端;
    进度变化(字符串_dec x y)与H中的v
    "完"。
    Ltac简化\u t\u获取\u t\u更新:=
    (*首先,我们必须将形式为[(fun m=>t_-get m k)m=(fun m=>t_-get m k)m']的假设更改为[t_-get=t_-get]
    cbvβ-在*;
    与对手重复比赛进球
    |[H:t\U get\U=t\U get\U124;-\ U]=>在H中简化进度
    结束。
    (*4.最后,通过“一致性”解决目标。*)
    Ltac完成证明不等式:=同余。
    (*现在我们把它们放在一起*)
    Ltac证明总映射不等式:=
    设H:=新入
    开始证明不等式H;
    用_键H饱和_;
    简化获取更新;
    完成不等式的证明。
    (*我试图解决的实际目标*)
    定义X:string:=“X”。
    定义Y:字符串:=“Y”。
    所有n的目标,(X!->n;Y!->n)(X!->1;Y!->2)。
    介绍。
    证明全映射不等式。
    Qed。
    
    为了实现自动化,您需要准确描述您的验证策略。以下是一种可能的证明策略:

    要证明
    total\u map
    s的不等式:

  • 首先介绍平等假设
  • 然后,对于添加到任一映射的每个键,添加与该键相关联的值在两个映射中相同的假设
  • 然后,通过展开
    t\u update
    ,使用
    string\u dec x
    为真,并查看是否有任何其他
    string\u dec
    计算下来,简化所有这些等式假设
  • 最后,通过一致性来解决目标
  • 我们可以自动化这些步骤中的每一步。总之,它变成:

    Require Import Coq.Strings.String.
    
    (* Prelude: the total_map data structure from Software Foundations, slightly modified *)
    Definition total_map := string -> nat.
    Definition empty_st : total_map := (fun _ => 0).
    Definition t_update (m : total_map) k v := fun k' => if string_dec k k' then v else m k'.
    Notation "a '!->' x" := (t_update empty_st a x) (at level 100).
    Notation "x '!->' v ';' m" := (t_update m x v) (at level 100, v at next level, right associativity).
    
    (* Automation *)
    
    (* 1. First introduce the equality hypothesis. *)
    Ltac start_proving_inequality H :=
      intro H.
    
    (* 2. Then, for every key that's been added to either map, add the hypothesis that the value associated to that key is the same in both maps. *)
    (* To do this, we need a tactic that will pose a proof only if it does not already exist. *)
    Ltac unique_pose_proof lem :=
      let T := type of lem in
      lazymatch goal with
      | [ H : T |- _ ] => fail 0 "A hypothesis of type" T "already exists"
      | _ => pose proof lem
      end.
    
    (* Maybe move this elsewhere? *)
    Definition t_get (m : total_map) k := m k.
    
    Ltac saturate_with_keys H :=
      repeat match type of H with
             | context[t_update _ ?k ?v]
               => unique_pose_proof (f_equal (fun m => t_get m k) H)
             end.
    
    (* 3. Then simplify all such equality hypotheses by unfolding `t_update`, using that `string_dec x x` is true, and seeing if any other `string_dec`s compute down. *)
    Require Import Coq.Logic.Eqdep_dec.
    Lemma string_dec_refl x : string_dec x x = left eq_refl.
    Proof.
      destruct (string_dec x x); [ apply f_equal | congruence ].
      apply UIP_dec, string_dec.
    Qed.
    
    (* N.B. You can add more cases here to deal with other sorts of ways you might reduce [t_get] here *)
    Ltac simplify_t_get_t_update_in H :=
      repeat first [ progress cbv [t_get t_update empty_st] in H
                   | match type of H with
                     | context[string_dec ?x ?x] => rewrite (string_dec_refl x) in H
                     | context[string_dec ?x ?y]
                       => let v := (eval cbv in (string_dec x y)) in
                          (* check that it fully reduces *)
                          lazymatch v with left _ => idtac | right _ => idtac end;
                          progress change (string_dec x y) with v in H
                     end ].
    
    Ltac simplify_t_get_t_update :=
      (* first we must change hypotheses of the form [(fun m => t_get m k) m = (fun m => t_get m k) m'] into [t_get _ _ = t_get _ _] *)
      cbv beta in *;
      repeat match goal with
             | [ H : t_get _ _ = t_get _ _ |- _ ] => progress simplify_t_get_t_update_in H
             end.
    
    (* 4. Finally, solve the goal by `congruence`. *)
    Ltac finish_proving_inequality := congruence.
    
    (* Now we put it all together *)
    Ltac prove_total_map_inequality :=
      let H := fresh in
      start_proving_inequality H;
      saturate_with_keys H;
      simplify_t_get_t_update;
      finish_proving_inequality.
    
    (* The actual goal I'm trying to solve *)
    Definition X: string := "X".
    Definition Y: string := "Y".
    Goal forall n, (X !-> n; Y !-> n) <> (X !-> 1; Y !-> 2).
      intros.
      prove_total_map_inequality.
    Qed.
    
    需要导入Coq.Strings.String。
    (*前奏曲:软件基础的总地图数据结构,稍作修改*)
    定义总映射:=字符串->nat。
    定义为空:总映射:=(乐趣=>0)。
    定义t_更新(m:总地图)k v:=fun